From b889931b5abce6c57c211ad4dc1853ca0ff2e58a Mon Sep 17 00:00:00 2001 From: Critical <48370698+CriticalXI@users.noreply.github.com> Date: Sun, 8 Feb 2026 13:06:01 -0700 Subject: [PATCH] [lua] Implement Samurai job util --- scripts/actions/abilities/blade_bash.lua | 32 +- scripts/actions/abilities/hagakure.lua | 3 +- scripts/actions/abilities/hamanoha.lua | 4 +- scripts/actions/abilities/hasso.lua | 20 +- scripts/actions/abilities/konzen-ittai.lua | 54 +--- scripts/actions/abilities/meditate.lua | 9 +- scripts/actions/abilities/meikyo_shisui.lua | 7 +- scripts/actions/abilities/seigan.lua | 12 +- scripts/actions/abilities/sekkanoki.lua | 3 +- scripts/actions/abilities/sengikori.lua | 2 +- scripts/actions/abilities/shikikoyo.lua | 16 +- scripts/actions/abilities/third_eye.lua | 21 +- scripts/actions/abilities/warding_circle.lua | 11 +- scripts/actions/abilities/yaegasumi.lua | 6 +- scripts/effects/seigan.lua | 5 +- scripts/effects/warding_circle.lua | 5 +- scripts/globals/job_utils/samurai.lua | 304 +++++++++++++++++++ 17 files changed, 329 insertions(+), 185 deletions(-) create mode 100644 scripts/globals/job_utils/samurai.lua diff --git a/scripts/actions/abilities/blade_bash.lua b/scripts/actions/abilities/blade_bash.lua index 3e5edbd7031..eaa5e88da16 100644 --- a/scripts/actions/abilities/blade_bash.lua +++ b/scripts/actions/abilities/blade_bash.lua @@ -9,37 +9,11 @@ local abilityObject = {} abilityObject.onAbilityCheck = function(player, target, ability) - if not player:isWeaponTwoHanded() then - return xi.msg.basic.NEEDS_2H_WEAPON, 0 - end - - return 0, 0 + return xi.job_utils.samurai.checkBladeBash(player, target, ability) end -abilityObject.onUseAbility = function(player, target, ability) - -- Stun rate - if math.random(1, 100) < 99 then - target:addStatusEffect(xi.effect.STUN, 1, 0, 6) - end - - -- Yes, even Blade Bash deals damage dependant of Dark Knight level - local jobLevel = utils.getActiveJobLevel(player, xi.job.DRK) - local damage = math.floor(player:getMod(xi.mod.WEAPON_BASH) + (jobLevel + 11) / 4) - - -- TODO: Affected by Phalanx/Physical Damage % modifiers? - -- Calculating and applying Blade Bash damage - damage = utils.handleStoneskin(target, damage) - target:takeDamage(damage, player, xi.attackType.PHYSICAL, xi.damageType.BLUNT) - target:updateEnmityFromDamage(player, damage) - - -- Applying Plague based on merit level. - if math.random(1, 100) < 65 then - target:addStatusEffect(xi.effect.PLAGUE, 5, 0, 15 + player:getMerit(xi.merit.BLADE_BASH)) - end - - ability:setMsg(xi.msg.basic.JA_DAMAGE) - - return damage +abilityObject.onUseAbility = function(player, target, ability, action) + return xi.job_utils.samurai.useBladeBash(player, target, ability, action) end return abilityObject diff --git a/scripts/actions/abilities/hagakure.lua b/scripts/actions/abilities/hagakure.lua index e2218aa64f8..7bec5b5df55 100644 --- a/scripts/actions/abilities/hagakure.lua +++ b/scripts/actions/abilities/hagakure.lua @@ -13,8 +13,7 @@ abilityObject.onAbilityCheck = function(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - target:delStatusEffect(xi.effect.HAGAKURE) - player:addStatusEffect(xi.effect.HAGAKURE, 400, 0, 60, 0, 1000) + return xi.job_utils.samurai.useHagakure(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/hamanoha.lua b/scripts/actions/abilities/hamanoha.lua index d6ec0dd76e2..e193b7a9fd4 100644 --- a/scripts/actions/abilities/hamanoha.lua +++ b/scripts/actions/abilities/hamanoha.lua @@ -13,9 +13,7 @@ abilityObject.onAbilityCheck = function(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - local jpValue = target:getJobPointLevel(xi.jp.HAMANOHA_DURATION) - - target:addStatusEffect(xi.effect.HAMANOHA, 12, 0, 180 + jpValue) + return xi.job_utils.samurai.useHamanoha(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/hasso.lua b/scripts/actions/abilities/hasso.lua index 97ccd53285f..9abafaca458 100644 --- a/scripts/actions/abilities/hasso.lua +++ b/scripts/actions/abilities/hasso.lua @@ -9,27 +9,11 @@ local abilityObject = {} abilityObject.onAbilityCheck = function(player, target, ability) - if not target:isWeaponTwoHanded() then - return xi.msg.basic.NEEDS_2H_WEAPON, 0 - end - - return 0, 0 + return xi.job_utils.samurai.checkHasso(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - local strboost = 0 - - if target:getMainJob() == xi.job.SAM then - strboost = (target:getMainLvl() / 7) + target:getJobPointLevel(xi.jp.HASSO_EFFECT) - elseif target:getSubJob() == xi.job.SAM then - strboost = target:getSubLvl() / 7 - end - - if strboost > 0 then - target:delStatusEffect(xi.effect.HASSO) - target:delStatusEffect(xi.effect.SEIGAN) - target:addStatusEffect(xi.effect.HASSO, strboost, 0, 300) - end + return xi.job_utils.samurai.useHasso(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/konzen-ittai.lua b/scripts/actions/abilities/konzen-ittai.lua index c66060ca8e8..772553b63a3 100644 --- a/scripts/actions/abilities/konzen-ittai.lua +++ b/scripts/actions/abilities/konzen-ittai.lua @@ -9,61 +9,11 @@ local abilityObject = {} abilityObject.onAbilityCheck = function(player, target, ability) - if player:getAnimation() ~= 1 then - return xi.msg.basic.REQUIRES_COMBAT, 0 - end - - return 0, 0 + return xi.job_utils.samurai.checkKonzenIttai(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability, action) - local animation = - { - miss = 1, - hit = 5, - } - - local infoValue = animation.miss - if - not target:hasStatusEffect(xi.effect.CHAINBOUND, 0) and - not target:hasStatusEffect(xi.effect.SKILLCHAIN, 0) - then - infoValue = animation.hit - target:addStatusEffectEx(xi.effect.CHAINBOUND, 0, 2, 0, 10, 0, 1) - else - ability:setMsg(xi.msg.basic.JA_NO_EFFECT) - end - - local skill = player:getWeaponSkillType(xi.slot.MAIN) - local anim = 36 - - if skill <= 1 then - anim = 37 - elseif skill <= 3 then - anim = 36 - elseif skill == 4 then - anim = 41 - elseif skill == 5 then - anim = 28 - elseif skill <= 7 then - anim = 40 - elseif skill == 8 then - anim = 42 - elseif skill == 9 then - anim = 43 - elseif skill == 10 then - anim = 44 - elseif skill == 11 then - anim = 39 - elseif skill == 12 then - anim = 45 - end - - action:info(target:getID(), infoValue) - action:setAnimation(target:getID(), anim) - - -- TODO: This returns 3 as param/value on hit - return 0 + return xi.job_utils.samurai.useKonzenIttai(player, target, ability, action) end return abilityObject diff --git a/scripts/actions/abilities/meditate.lua b/scripts/actions/abilities/meditate.lua index 264f954f706..e7e570a1d3d 100644 --- a/scripts/actions/abilities/meditate.lua +++ b/scripts/actions/abilities/meditate.lua @@ -13,14 +13,7 @@ abilityObject.onAbilityCheck = function(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - local amount = 12 - local duration = 15 + player:getMod(xi.mod.MEDITATE_DURATION) - - if player:getMainJob() == xi.job.SAM then - amount = 20 + target:getJobPointLevel(xi.jp.MEDITATE_EFFECT) * 5 - end - - player:addStatusEffectEx(xi.effect.MEDITATE, 0, amount, 3, duration) + return xi.job_utils.samurai.useMeditate(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/meikyo_shisui.lua b/scripts/actions/abilities/meikyo_shisui.lua index 0e9919acc27..d5cb03dd9b8 100644 --- a/scripts/actions/abilities/meikyo_shisui.lua +++ b/scripts/actions/abilities/meikyo_shisui.lua @@ -9,14 +9,11 @@ local abilityObject = {} abilityObject.onAbilityCheck = function(player, target, ability) - ability:setRecast(math.max(0, ability:getRecast() - player:getMod(xi.mod.ONE_HOUR_RECAST) * 60)) - - return 0, 0 + return xi.job_utils.samurai.checkMeikyoShisui(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - player:addStatusEffect(xi.effect.MEIKYO_SHISUI, 1, 0, 30) - player:addTP(3000) + return xi.job_utils.samurai.useMeikyoShisui(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/seigan.lua b/scripts/actions/abilities/seigan.lua index e8dcd94d3fb..e311cdce9b5 100644 --- a/scripts/actions/abilities/seigan.lua +++ b/scripts/actions/abilities/seigan.lua @@ -9,19 +9,11 @@ local abilityObject = {} abilityObject.onAbilityCheck = function(player, target, ability) - if not target:isWeaponTwoHanded() then - return xi.msg.basic.NEEDS_2H_WEAPON, 0 - end - - return 0, 0 + return xi.job_utils.samurai.checkSeigan(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - if target:isWeaponTwoHanded() then - target:delStatusEffect(xi.effect.HASSO) - target:delStatusEffect(xi.effect.SEIGAN) - target:addStatusEffect(xi.effect.SEIGAN, 0, 0, 300) - end + return xi.job_utils.samurai.useSeigan(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/sekkanoki.lua b/scripts/actions/abilities/sekkanoki.lua index 48d70f48182..4659fcd8801 100644 --- a/scripts/actions/abilities/sekkanoki.lua +++ b/scripts/actions/abilities/sekkanoki.lua @@ -13,8 +13,7 @@ abilityObject.onAbilityCheck = function(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - target:delStatusEffect(xi.effect.SEKKANOKI) - target:addStatusEffect(xi.effect.SEKKANOKI, 1, 0, 60) + return xi.job_utils.samurai.useSekkanoki(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/sengikori.lua b/scripts/actions/abilities/sengikori.lua index 445adbb502f..81d58db87d4 100644 --- a/scripts/actions/abilities/sengikori.lua +++ b/scripts/actions/abilities/sengikori.lua @@ -13,7 +13,7 @@ abilityObject.onAbilityCheck = function(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - player:addStatusEffect(xi.effect.SENGIKORI, 25, 0, 60) + return xi.job_utils.samurai.useSengikori(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/shikikoyo.lua b/scripts/actions/abilities/shikikoyo.lua index 8d97ffd2058..81ceaf033b8 100644 --- a/scripts/actions/abilities/shikikoyo.lua +++ b/scripts/actions/abilities/shikikoyo.lua @@ -10,23 +10,11 @@ local abilityObject = {} abilityObject.onAbilityCheck = function(player, target, ability) - if player:getID() == target:getID() then - return xi.msg.basic.CANNOT_PERFORM_TARG, 0 - elseif player:getTP() < 1000 then - return xi.msg.basic.NOT_ENOUGH_TP, 0 - end - - return 0, 0 + return xi.job_utils.samurai.checkShikikoyo(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - local pTP = (player:getTP() - 1000) * (1 + ((player:getMerit(xi.merit.SHIKIKOYO) - 12) / 100)) - pTP = utils.clamp(pTP, 0, 3000 - target:getTP()) - - player:setTP(1000) - target:setTP(target:getTP() + pTP) - - return pTP + return xi.job_utils.samurai.useShikikoyo(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/third_eye.lua b/scripts/actions/abilities/third_eye.lua index ddcce0d9fb3..a6576badd68 100644 --- a/scripts/actions/abilities/third_eye.lua +++ b/scripts/actions/abilities/third_eye.lua @@ -9,28 +9,11 @@ local abilityObject = {} abilityObject.onAbilityCheck = function(player, target, ability) - if - player:hasStatusEffect(xi.effect.SEIGAN) and - player:isWeaponTwoHanded() - then - ability:setRecast(ability:getRecast() / 2) - end - - return 0, 0 + return xi.job_utils.samurai.checkThirdEye(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - if - player:hasStatusEffect(xi.effect.COPY_IMAGE) or - player:hasStatusEffect(xi.effect.BLINK) - then - -- Returns "no effect" message when Copy Image is active when Third Eye is used. - ability:setMsg(xi.msg.basic.JA_NO_EFFECT) - else - player:addStatusEffect(xi.effect.THIRD_EYE, 0, 0, 30) -- Power keeps track of procs - - return xi.effect.THIRD_EYE - end + return xi.job_utils.samurai.useThirdEye(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/warding_circle.lua b/scripts/actions/abilities/warding_circle.lua index 28958a82832..ee74e998dfb 100644 --- a/scripts/actions/abilities/warding_circle.lua +++ b/scripts/actions/abilities/warding_circle.lua @@ -13,16 +13,7 @@ abilityObject.onAbilityCheck = function(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - local duration = 180 + player:getMod(xi.mod.WARDING_CIRCLE_DURATION) - local power = 5 - - if player:getMainJob() == xi.job.SAM then - power = 15 - end - - power = power + player:getMod(xi.mod.WARDING_CIRCLE_POTENCY) - - target:addStatusEffect(xi.effect.WARDING_CIRCLE, power, 0, duration) + return xi.job_utils.samurai.useWardingCircle(player, target, ability) end return abilityObject diff --git a/scripts/actions/abilities/yaegasumi.lua b/scripts/actions/abilities/yaegasumi.lua index 015a70d88e0..87843b45719 100644 --- a/scripts/actions/abilities/yaegasumi.lua +++ b/scripts/actions/abilities/yaegasumi.lua @@ -9,13 +9,11 @@ local abilityObject = {} abilityObject.onAbilityCheck = function(player, target, ability) - ability:setRecast(math.max(0, ability:getRecast() - player:getMod(xi.mod.ONE_HOUR_RECAST) * 60)) - - return 0, 0 + return xi.job_utils.samurai.checkYaegasumi(player, target, ability) end abilityObject.onUseAbility = function(player, target, ability) - player:addStatusEffect(xi.effect.YAEGASUMI, 12, 0, 45) + return xi.job_utils.samurai.useYaegasumi(player, target, ability) end return abilityObject diff --git a/scripts/effects/seigan.lua b/scripts/effects/seigan.lua index e7b76e2332f..d0f385a5580 100644 --- a/scripts/effects/seigan.lua +++ b/scripts/effects/seigan.lua @@ -8,16 +8,13 @@ effectObject.onEffectGain = function(target, effect) -- TODO: confirm if this def bonus is only active with 2hander equipped and either follow the pattern currently in hasso/desperate blows or consider a latent sytle effect local jpValue = target:getJobPointLevel(xi.jp.SEIGAN_EFFECT) - target:addMod(xi.mod.DEF, jpValue * 3) + effect:addMod(xi.mod.DEF, jpValue * 3) end effectObject.onEffectTick = function(target, effect) end effectObject.onEffectLose = function(target, effect) - local jpValue = target:getJobPointLevel(xi.jp.SEIGAN_EFFECT) - - target:delMod(xi.mod.DEF, jpValue * 3) end return effectObject diff --git a/scripts/effects/warding_circle.lua b/scripts/effects/warding_circle.lua index 54766974f7b..6b140a5ae46 100644 --- a/scripts/effects/warding_circle.lua +++ b/scripts/effects/warding_circle.lua @@ -7,16 +7,13 @@ local effectObject = {} effectObject.onEffectGain = function(target, effect) local jpValue = target:getJobPointLevel(xi.jp.WARDING_CIRCLE_EFFECT) - target:addMod(xi.mod.DEMON_KILLER, effect:getPower() + jpValue) + effect:addMod(xi.mod.DEMON_KILLER, effect:getPower() + jpValue) end effectObject.onEffectTick = function(target, effect) end effectObject.onEffectLose = function(target, effect) - local jpValue = target:getJobPointLevel(xi.jp.WARDING_CIRCLE_EFFECT) - - target:delMod(xi.mod.DEMON_KILLER, effect:getPower() + jpValue) end return effectObject diff --git a/scripts/globals/job_utils/samurai.lua b/scripts/globals/job_utils/samurai.lua new file mode 100644 index 00000000000..dc830ef0b24 --- /dev/null +++ b/scripts/globals/job_utils/samurai.lua @@ -0,0 +1,304 @@ +----------------------------------- +-- Samurai Job Utilities +----------------------------------- +require('scripts/globals/ability') +require('scripts/globals/jobpoints') +----------------------------------- +xi = xi or {} +xi.job_utils = xi.job_utils or {} +xi.job_utils.samurai = xi.job_utils.samurai or {} + +----------------------------------- +-- Ability Check Functions +----------------------------------- + +xi.job_utils.samurai.checkMeikyoShisui = function(player, target, ability) + ability:setRecast(math.max(0, ability:getRecast() - player:getMod(xi.mod.ONE_HOUR_RECAST) * 60)) + + return 0, 0 +end + +xi.job_utils.samurai.checkYaegasumi = function(player, target, ability) + ability:setRecast(math.max(0, ability:getRecast() - player:getMod(xi.mod.ONE_HOUR_RECAST) * 60)) + + return 0, 0 +end + +xi.job_utils.samurai.checkThirdEye = function(player, target, ability) + if + player:hasStatusEffect(xi.effect.SEIGAN) and + player:isWeaponTwoHanded() + then + ability:setRecast(ability:getRecast() / 2) + end + + return 0, 0 +end + +xi.job_utils.samurai.checkHasso = function(player, target, ability) + if not player:isWeaponTwoHanded() then + return xi.msg.basic.NEEDS_2H_WEAPON, 0 + end + + return 0, 0 +end + +xi.job_utils.samurai.checkSeigan = function(player, target, ability) + if not player:isWeaponTwoHanded() then + return xi.msg.basic.NEEDS_2H_WEAPON, 0 + end + + return 0, 0 +end + +xi.job_utils.samurai.checkKonzenIttai = function(player, target, ability) + if player:getAnimation() ~= 1 then + return xi.msg.basic.REQUIRES_COMBAT, 0 + end + + return 0, 0 +end + +xi.job_utils.samurai.checkBladeBash = function(player, target, ability) + if not player:isWeaponTwoHanded() then + return xi.msg.basic.NEEDS_2H_WEAPON, 0 + end + + return 0, 0 +end + +xi.job_utils.samurai.checkShikikoyo = function(player, target, ability) + if player:getID() == target:getID() then + return xi.msg.basic.CANNOT_PERFORM_TARG, 0 + elseif player:getTP() < 1000 then + return xi.msg.basic.NOT_ENOUGH_TP, 0 + end + + return 0, 0 +end + +----------------------------------- +-- Ability Use Functions +----------------------------------- + +xi.job_utils.samurai.useMeikyoShisui = function(player, target, ability) + player:addStatusEffect(xi.effect.MEIKYO_SHISUI, 1, 0, 30) + player:addTP(3000) + + return 0 +end + +xi.job_utils.samurai.useYaegasumi = function(player, target, ability) + player:addStatusEffect(xi.effect.YAEGASUMI, 12, 0, 45) + + return xi.effect.YAEGASUMI +end + +xi.job_utils.samurai.useWardingCircle = function(player, target, ability) + local duration = 180 + player:getMod(xi.mod.WARDING_CIRCLE_DURATION) + local power = 15 + + if player:getMainJob() ~= xi.job.SAM then + power = 5 + end + + power = power + player:getMod(xi.mod.WARDING_CIRCLE_POTENCY) + + -- Handle simplified message for other party members. + if player:getID() ~= target:getID() then + ability:setMsg(xi.msg.basic.FORTIFIED_DEMONS) + end + + target:addStatusEffect(xi.effect.WARDING_CIRCLE, power, 0, duration) + + return xi.effect.WARDING_CIRCLE +end + +xi.job_utils.samurai.useThirdEye = function(player, target, ability) + if + player:hasStatusEffect(xi.effect.COPY_IMAGE) or + player:hasStatusEffect(xi.effect.BLINK) + then + -- Returns "no effect" message when Copy Image is active when Third Eye is used. + ability:setMsg(xi.msg.basic.JA_NO_EFFECT) + else + player:addStatusEffect(xi.effect.THIRD_EYE, 0, 0, 30) -- Power keeps track of procs + end + + return xi.effect.THIRD_EYE +end + +xi.job_utils.samurai.useHasso = function(player, target, ability) + local strboost = 0 + + if target:getMainJob() == xi.job.SAM then + strboost = target:getMainLvl() / 7 + target:getJobPointLevel(xi.jp.HASSO_EFFECT) + elseif target:getSubJob() == xi.job.SAM then + strboost = target:getSubLvl() / 7 + end + + if strboost > 0 then + target:delStatusEffect(xi.effect.HASSO) + target:delStatusEffect(xi.effect.SEIGAN) + target:addStatusEffect(xi.effect.HASSO, strboost, 0, 300) + end + + return xi.effect.HASSO +end + +xi.job_utils.samurai.useMeditate = function(player, target, ability) + local amount = 12 + local duration = 15 + player:getMod(xi.mod.MEDITATE_DURATION) + + if player:getMainJob() == xi.job.SAM then + amount = 20 + player:getJobPointLevel(xi.jp.MEDITATE_EFFECT) * 5 + end + + player:addStatusEffectEx(xi.effect.MEDITATE, 0, amount, 3, duration) + + return xi.effect.MEDITATE +end + +xi.job_utils.samurai.useSeigan = function(player, target, ability) + if target:isWeaponTwoHanded() then + target:delStatusEffect(xi.effect.HASSO) + target:delStatusEffect(xi.effect.SEIGAN) + target:addStatusEffect(xi.effect.SEIGAN, 0, 0, 300) + end + + return xi.effect.SEIGAN +end + +xi.job_utils.samurai.useSekkanoki = function(player, target, ability) + target:delStatusEffect(xi.effect.SEKKANOKI) + target:addStatusEffect(xi.effect.SEKKANOKI, 1, 0, 60) + + return xi.effect.SEKKANOKI +end + +xi.job_utils.samurai.useKonzenIttai = function(player, target, ability, action) + local params = + { + miss = 1, + hit = 5, + } + + local infoValue = params.miss + if + not target:hasStatusEffect(xi.effect.CHAINBOUND, 0) and + not target:hasStatusEffect(xi.effect.SKILLCHAIN, 0) + then + infoValue = params.hit + target:addStatusEffectEx(xi.effect.CHAINBOUND, 0, 2, 0, 10, 0, 1) + else + ability:setMsg(xi.msg.basic.JA_NO_EFFECT) + end + + local animationTable = + { + [xi.skill.AXE ] = 28, + [xi.skill.DAGGER ] = 36, + [xi.skill.SWORD ] = 36, + [xi.skill.NONE ] = 37, + [xi.skill.HAND_TO_HAND] = 37, + [xi.skill.CLUB ] = 39, + [xi.skill.GREAT_AXE ] = 40, + [xi.skill.SCYTHE ] = 40, + [xi.skill.GREAT_SWORD ] = 41, + [xi.skill.POLEARM ] = 42, + [xi.skill.KATANA ] = 43, + [xi.skill.GREAT_KATANA] = 44, + [xi.skill.STAFF ] = 45, + } + + local animation = animationTable[player:getWeaponSkillType(xi.slot.MAIN)] or 37 + action:setAnimation(target:getID(), animation) + action:info(target:getID(), infoValue) + + return infoValue == params.hit and 3 or 0 +end + +xi.job_utils.samurai.useBladeBash = function(player, target, ability, action) + -- Damage + -- TODO: Verify damage formula and DRK interaction + local jobLevel = utils.getActiveJobLevel(player, xi.job.DRK) + local damage = math.floor((jobLevel + 11) / 4 + player:getMod(xi.mod.WEAPON_BASH)) + damage = utils.handleStoneskin(target, damage) + target:takeDamage(damage, player, xi.attackType.PHYSICAL, xi.damageType.BLUNT) + target:updateEnmityFromDamage(player, damage) + + -- Stun + if + not xi.data.statusEffect.isTargetImmune(target, xi.effect.STUN, xi.element.THUNDER) and + not xi.data.statusEffect.isTargetResistant(player, target, xi.effect.STUN) and + not xi.data.statusEffect.isEffectNullified(target, xi.effect.STUN, 0) + then + local resistanceRate = xi.combat.magicHitRate.calculateResistRate(player, target, 0, 0, xi.skillRank.A_PLUS, xi.element.THUNDER, xi.mod.INT, xi.effect.STUN, 0) + if xi.data.statusEffect.isResistRateSuccessfull(xi.effect.STUN, resistanceRate, 0) then + target:addStatusEffect(xi.effect.STUN, 1, 0, 6 * resistanceRate) + end + end + + -- Plague + if + not xi.data.statusEffect.isTargetImmune(target, xi.effect.PLAGUE, xi.element.FIRE) and + not xi.data.statusEffect.isTargetResistant(player, target, xi.effect.PLAGUE) and + not xi.data.statusEffect.isEffectNullified(target, xi.effect.PLAGUE, 0) + then + local resistanceRate = xi.combat.magicHitRate.calculateResistRate(player, target, 0, 0, xi.skillRank.A_PLUS, xi.element.FIRE, xi.mod.INT, xi.effect.PLAGUE, 0) + if xi.data.statusEffect.isResistRateSuccessfull(xi.effect.PLAGUE, resistanceRate, 0) then + local duration = (15 + player:getMerit(xi.merit.BLADE_BASH)) * resistanceRate + target:addStatusEffect(xi.effect.PLAGUE, 5, 0, duration) + end + end + + -- Animation + local animationTable = + { + -- [weapon type] = animation ID + [xi.skill.GREAT_SWORD ] = 201, + [xi.skill.GREAT_KATANA] = 201, + [xi.skill.GREAT_AXE ] = 202, + [xi.skill.SCYTHE ] = 202, + [xi.skill.STAFF ] = 202, + [xi.skill.POLEARM ] = 203, + } + + local animation = animationTable[player:getWeaponSkillType(xi.slot.MAIN)] or 0 + action:setAnimation(target:getID(), animation) + + ability:setMsg(xi.msg.basic.JA_DAMAGE) + + return damage +end + +xi.job_utils.samurai.useShikikoyo = function(player, target, ability) + local pTP = (player:getTP() - 1000) * (1 + (player:getMerit(xi.merit.SHIKIKOYO) - 12) / 100) + pTP = utils.clamp(pTP, 0, 3000 - target:getTP()) + + player:setTP(1000) + target:setTP(target:getTP() + pTP) + + return pTP +end + +xi.job_utils.samurai.useSengikori = function(player, target, ability) + player:addStatusEffect(xi.effect.SENGIKORI, 25, 0, 60) + + return xi.effect.SENGIKORI +end + +xi.job_utils.samurai.useHamanoha = function(player, target, ability) + local jpValue = target:getJobPointLevel(xi.jp.HAMANOHA_DURATION) + + target:addStatusEffect(xi.effect.HAMANOHA, 12, 0, 180 + jpValue) + + return xi.effect.HAMANOHA +end + +xi.job_utils.samurai.useHagakure = function(player, target, ability) + player:delStatusEffect(xi.effect.HAGAKURE) + player:addStatusEffect(xi.effect.HAGAKURE, 400, 0, 60, 0, 1000) + + return xi.effect.HAGAKURE +end