From 2a089fb6111011405c3156057888db43438e91b3 Mon Sep 17 00:00:00 2001 From: Skold <113406182+Skold177@users.noreply.github.com> Date: Sat, 28 Mar 2026 11:36:39 -0400 Subject: [PATCH] [lua] KS99 Horns of War Updates Final Meteor with extra guards and resolves long standing bugs with the fight by moving its death into the mobs skill finalize. Also updates it's skill table into lua and converts its additional effect. --- scripts/actions/mobskills/meteor.lua | 12 ++- scripts/enum/mob_skill.lua | 6 ++ scripts/zones/Horlais_Peak/mobs/Chlevnik.lua | 83 ++++++++++++-------- 3 files changed, 66 insertions(+), 35 deletions(-) diff --git a/scripts/actions/mobskills/meteor.lua b/scripts/actions/mobskills/meteor.lua index c4044bef0c5..7e567f75dee 100644 --- a/scripts/actions/mobskills/meteor.lua +++ b/scripts/actions/mobskills/meteor.lua @@ -27,11 +27,15 @@ mobskillObject.onMobWeaponSkill = function(mob, target, skill, action) target:takeDamage(info.damage, mob, info.attackType, info.damageType) end - -- Animation change happens after mobskill finishes. - -- Animation: Chlevnik falls but calls in a final meteor barrage, then dies. - skill:setFinalAnimationSub(1) - return info.damage end +mobskillObject.onMobSkillFinalize = function(mob, skill) + mob:setAnimationSub(1) + mob:timer(6000, function(mobArg) + mobArg:setUnkillable(false) + mobArg:setHP(0) + end) +end + return mobskillObject diff --git a/scripts/enum/mob_skill.lua b/scripts/enum/mob_skill.lua index d10377f9599..8c69554170f 100644 --- a/scripts/enum/mob_skill.lua +++ b/scripts/enum/mob_skill.lua @@ -268,6 +268,12 @@ xi.mobSkill = VULTURE_3 = 626, + WILD_HORN = 628, + THUNDERBOLT_BEHEMOTH = 629, + KICK_OUT = 630, + SHOCK_WAVE_BEHEMOTH = 631, + FLAME_ARMOR = 632, + HOWL_BEHEMOTH = 633, FINAL_METEOR = 634, -- Final Meteor Chlevnik RECOIL_DIVE_1 = 641, diff --git a/scripts/zones/Horlais_Peak/mobs/Chlevnik.lua b/scripts/zones/Horlais_Peak/mobs/Chlevnik.lua index 4122db4f644..be8e16359e1 100644 --- a/scripts/zones/Horlais_Peak/mobs/Chlevnik.lua +++ b/scripts/zones/Horlais_Peak/mobs/Chlevnik.lua @@ -3,7 +3,7 @@ -- Mob: Chlevnik -- KSNM99 : Horns of War --- TODO : Update Howl to give 25% Attack instead of 15% - Update Meteor to 1.6 fTP + dINT * 3(!) +-- TODO : Update Meteor to 1.6 fTP + dINT * 3(!) ----------------------------------- local entity = {} @@ -12,34 +12,26 @@ entity.onMobInitialize = function(mob) mob:addImmunity(xi.immunity.DARK_SLEEP) mob:addImmunity(xi.immunity.PETRIFY) mob:addImmunity(xi.immunity.SILENCE) - mob:setBehavior(bit.bor(mob:getBehavior(), xi.behavior.NO_TURN)) mob:setMobMod(xi.mobMod.AOE_HIT_ALL, 1) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'FINAL_METEOR_DEATH', function(mobArg, skillId, wasExecuted) - if skillId == xi.mobSkill.FINAL_METEOR then - if mobArg:getAnimationSub() ~= 1 then - mobArg:setAnimationSub(1) - end - - mobArg:timer(6000, function(mobArgTimer) - mobArgTimer:setUnkillable(false) - mobArgTimer:setHP(0) - end) - end - end) + mob:setBehavior(bit.bor(mob:getBehavior(), xi.behavior.NO_TURN)) end entity.onMobSpawn = function(mob) - mob:setUnkillable(true) - mob:setAutoAttackEnabled(true) - mob:setMagicCastingEnabled(true) - mob:setMobAbilityEnabled(true) + mob:setMod(xi.mod.STUN_RES_RANK, 10) + mob:setMod(xi.mod.TRIPLE_ATTACK, 5) - mob:addMod(xi.mod.STUNRES, 90) mob:setMobMod(xi.mobMod.NO_MOVE, 0) mob:setMobMod(xi.mobMod.ADD_EFFECT, 1) mob:setMod(xi.mod.REGAIN, 50) + mob:setTP(3000) - mob:setLocalVar('finalMeteor', 0) + mob:setUnkillable(true) + mob:setAutoAttackEnabled(true) + mob:setMagicCastingEnabled(true) + mob:setMobAbilityEnabled(true) + mob:setAnimationSub(0) + + mob:setLocalVar('queueFinalMeteor', 0) end entity.onMobEngage = function(mob, target) @@ -47,28 +39,57 @@ entity.onMobEngage = function(mob, target) end entity.onMobFight = function(mob, target) - local delay = mob:getLocalVar('meteorDelay') - if GetSystemTime() > delay then -- Cooldown on Meteor is 30 seconds. - mob:castSpell(xi.magic.spell.METEOR, target) - mob:setLocalVar('meteorDelay', GetSystemTime() + 30) - end - - if mob:getHP() == 1 and mob:getLocalVar('finalMeteor') == 0 then + if + mob:getHP() == 1 and + mob:getLocalVar('queueFinalMeteor') == 0 + then + mob:setLocalVar('queueFinalMeteor', 1) mob:setAutoAttackEnabled(false) mob:setMagicCastingEnabled(false) mob:setMobAbilityEnabled(false) mob:setMobMod(xi.mobMod.NO_MOVE, 1) - mob:setLocalVar('finalMeteor', 1) + return end - if mob:getLocalVar('finalMeteor') == 1 then + if + mob:getLocalVar('queueFinalMeteor') == 1 and + not xi.combat.behavior.isEntityBusy(mob) + then mob:useMobAbility(xi.mobSkill.FINAL_METEOR, nil, nil, true) -- Ignoring distance based off retail capture. - mob:setLocalVar('finalMeteor', 2) + mob:setLocalVar('queueFinalMeteor', 2) + end + + local delay = mob:getLocalVar('meteorDelay') + + if GetSystemTime() > delay then -- Cooldown on Meteor is 30 seconds. + mob:castSpell(xi.magic.spell.METEOR, target) + mob:setLocalVar('meteorDelay', GetSystemTime() + 30) end end +entity.onMobMobskillChoose = function(mob, target, skillId) + local skillList = + { + xi.mobSkill.WILD_HORN, + xi.mobSkill.THUNDERBOLT_BEHEMOTH, + xi.mobSkill.KICK_OUT, + xi.mobSkill.SHOCK_WAVE_BEHEMOTH, + xi.mobSkill.FLAME_ARMOR, + xi.mobSkill.HOWL_BEHEMOTH, + } + + return skillList[math.random(1, #skillList)] +end + entity.onAdditionalEffect = function(mob, target, damage) - return xi.mob.onAddEffect(mob, target, damage, xi.mob.ae.STUN, { chance = 25, duration = 10 }) -- 25% chance to stun for 10 seconds. + local pTable = + { + chance = 25, + effectId = xi.effect.STUN, + duration = 10, + } + + return xi.combat.action.executeAddEffectEnfeeblement(mob, target, pTable) end entity.onSpellPrecast = function(mob, spell)