From 7e1e25470243240171e5e2032935ade0f401d219 Mon Sep 17 00:00:00 2001 From: Xaver-DaRed Date: Tue, 17 Mar 2026 04:14:11 +0100 Subject: [PATCH 1/2] Normalize the usage of `WEAPONSKILL_STATE_EXIT` listener --- documentation/AI_Events.txt | 2 +- .../pets/attachments/flame_holder.lua | 2 +- scripts/actions/spells/trust/prishe_ii.lua | 6 +- scripts/mixins/families/amphiptere.lua | 6 +- scripts/mixins/families/antlion_ambush.lua | 2 +- .../families/antlion_ambush_no_rehide.lua | 2 +- scripts/mixins/families/avatar.lua | 2 +- scripts/mixins/families/zdei.lua | 6 +- .../Bearclaw_Pinnacle/mobs/Snoll_Tzar.lua | 4 +- .../zones/Boneyard_Gully/mobs/Tuchulcha.lua | 4 +- .../zones/Empyreal_Paradox/mobs/Prishe.lua | 6 +- .../mobs/Ajido-Marujido.lua | 2 +- scripts/zones/Horlais_Peak/mobs/Chlevnik.lua | 4 +- .../LaLoff_Amphitheater/mobs/Ark_Angel_TT.lua | 2 +- .../zones/Mine_Shaft_2716/mobs/Chekochuk.lua | 2 +- .../zones/Mine_Shaft_2716/mobs/Swipostik.lua | 2 +- scripts/zones/Monarch_Linn/mobs/Razon.lua | 2 +- .../Nyzul_Isle/mobs/Long-Gunned_Chariot.lua | 4 +- scripts/zones/RuAun_Gardens/mobs/Despot.lua | 90 ++++++++++--------- .../zones/The_Shrouded_Maw/mobs/Diabolos.lua | 4 +- .../The_Shrouded_Maw/mobs/Diabolos_DN.lua | 4 +- .../The_Shrouded_Maw/mobs/Diabolos_WD.lua | 4 +- .../zones/Throne_Room/mobs/Shadow_of_Rage.lua | 2 +- scripts/zones/Throne_Room/mobs/Zeid_2.lua | 2 +- .../zones/Wajaom_Woodlands/mobs/Gharial.lua | 2 +- src/map/ai/states/mobskill_state.cpp | 19 ++-- src/map/ai/states/petskill_state.cpp | 27 ++++-- src/map/ai/states/weaponskill_state.cpp | 22 ++++- 28 files changed, 143 insertions(+), 93 deletions(-) diff --git a/documentation/AI_Events.txt b/documentation/AI_Events.txt index af60852d563..ad9cca6a815 100644 --- a/documentation/AI_Events.txt +++ b/documentation/AI_Events.txt @@ -52,7 +52,7 @@ WEAPONSKILL_STATE_ENTER - userEntity, skillId WEAPONSKILL_BEFORE_USE - userEntity, skillId WEAPONSKILL_USE - userEntity, targetEntity, skill, tp, action, damage WEAPONSKILL_TAKE - userEntity, targetEntity, skill, tp, action -WEAPONSKILL_STATE_EXIT - userEntity, skillId +WEAPONSKILL_STATE_EXIT - userEntity, skillId, wasExecuted MAGIC_START - Entity, Target, Spell, action MAGIC_USE - Entity, Target, Spell, action diff --git a/scripts/actions/abilities/pets/attachments/flame_holder.lua b/scripts/actions/abilities/pets/attachments/flame_holder.lua index 06d650177de..55941ec917b 100644 --- a/scripts/actions/abilities/pets/attachments/flame_holder.lua +++ b/scripts/actions/abilities/pets/attachments/flame_holder.lua @@ -39,7 +39,7 @@ attachmentObject.onEquip = function(automaton) pet:setLocalVar('flameholder', amount) end) - automaton:addListener('WEAPONSKILL_STATE_EXIT', 'AUTO_FLAME_HOLDER_END', function(pet, skill) + automaton:addListener('WEAPONSKILL_STATE_EXIT', 'AUTO_FLAME_HOLDER_END', function(pet, skillId, wasExecuted) local master = pet:getMaster() local toremove = pet:getLocalVar('flameholdermaneuvers') if toremove == 0 then diff --git a/scripts/actions/spells/trust/prishe_ii.lua b/scripts/actions/spells/trust/prishe_ii.lua index 48e468fc4b7..7aa3cf00832 100644 --- a/scripts/actions/spells/trust/prishe_ii.lua +++ b/scripts/actions/spells/trust/prishe_ii.lua @@ -42,13 +42,13 @@ spellObject.onMobSpawn = function(mob) end end) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'ANIMA_USED', function(mobArg, wsid) - if wsid == psychoAnima then + mob:addListener('WEAPONSKILL_STATE_EXIT', 'ANIMA_USED', function(mobArg, skillId, wasExecuted) + if skillId == psychoAnima then mobArg:removeGambit(itemOneGambit) end --[[ - if wsid == hysteroAnima then + if skillId == hysteroAnima then mobArg:removeGambit(itemTwoGambit) end ]]-- diff --git a/scripts/mixins/families/amphiptere.lua b/scripts/mixins/families/amphiptere.lua index f4fbd99bae4..6f5cdda4f2d 100644 --- a/scripts/mixins/families/amphiptere.lua +++ b/scripts/mixins/families/amphiptere.lua @@ -33,10 +33,10 @@ g_mixins.families.amphiptere = function(amphiptereMob) end end) - amphiptereMob:addListener('WEAPONSKILL_STATE_EXIT', 'SPAM_KNOCKBACK', function(mobArg, actionId) - if actionId == xi.mobSkill.REAVING_WIND then + amphiptereMob:addListener('WEAPONSKILL_STATE_EXIT', 'SPAM_KNOCKBACK', function(mobArg, skillId, wasExecuted) + if skillId == xi.mobSkill.REAVING_WIND then mobArg:useMobAbility(xi.mobSkill.REAVING_WIND_KNOCKBACK) - elseif actionId == xi.mobSkill.REAVING_WIND_KNOCKBACK then + elseif skillId == xi.mobSkill.REAVING_WIND_KNOCKBACK then if GetSystemTime() >= mobArg:getLocalVar('auraEndTime') then mobArg:setLocalVar('auraEndTime', 0) mobArg:setAnimationSub(0) diff --git a/scripts/mixins/families/antlion_ambush.lua b/scripts/mixins/families/antlion_ambush.lua index 1564bafd582..5677acdb0b3 100644 --- a/scripts/mixins/families/antlion_ambush.lua +++ b/scripts/mixins/families/antlion_ambush.lua @@ -25,7 +25,7 @@ g_mixins.families.antlion_ambush = function(antlion) mob:useMobAbility(xi.mobSkill.PIT_AMBUSH_1) end) - antlion:addListener('WEAPONSKILL_STATE_EXIT', 'ANTLION_AMBUSH_FINISH', function(mob, skillId) + antlion:addListener('WEAPONSKILL_STATE_EXIT', 'ANTLION_AMBUSH_FINISH', function(mob, skillId, wasExecuted) if skillId == xi.mobSkill.PIT_AMBUSH_1 then mob:hideName(false) mob:setUntargetable(false) diff --git a/scripts/mixins/families/antlion_ambush_no_rehide.lua b/scripts/mixins/families/antlion_ambush_no_rehide.lua index b1104c6ac05..6adabd573fb 100644 --- a/scripts/mixins/families/antlion_ambush_no_rehide.lua +++ b/scripts/mixins/families/antlion_ambush_no_rehide.lua @@ -24,7 +24,7 @@ g_mixins.families.antlion_ambush_no_rehide = function(antlion) end) -- Ensures an interupted pit ambush doesn't let the mob stay hidden underground - antlion:addListener('WEAPONSKILL_STATE_EXIT', 'ANTLION_AMBUSH_FINISH', function(mob, skillId) + antlion:addListener('WEAPONSKILL_STATE_EXIT', 'ANTLION_AMBUSH_FINISH', function(mob, skillId, wasExecuted) if skillId == xi.mobSkill.PIT_AMBUSH_1 then mob:hideName(false) mob:setUntargetable(false) diff --git a/scripts/mixins/families/avatar.lua b/scripts/mixins/families/avatar.lua index 10b26fd2812..a08946816e6 100644 --- a/scripts/mixins/families/avatar.lua +++ b/scripts/mixins/families/avatar.lua @@ -75,7 +75,7 @@ g_mixins.families.avatar = function(avatarMob) end -- avatar dies as soon as AF ability completes - mob:addListener('WEAPONSKILL_STATE_EXIT', 'AVATAR_MOBSKILL_FINISHED', function(mobArg) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'AVATAR_MOBSKILL_FINISHED', function(mobArg, skillId, wasExecuted) mobArg:setUnkillable(false) mobArg:setHP(0) end) diff --git a/scripts/mixins/families/zdei.lua b/scripts/mixins/families/zdei.lua index 03c5f11ee5b..97b18c4175f 100644 --- a/scripts/mixins/families/zdei.lua +++ b/scripts/mixins/families/zdei.lua @@ -45,8 +45,8 @@ g_mixins.families.zdei = function(zdeiMob) mob:setLocalVar('changeTime', GetSystemTime() + math.random(15, 30)) end) - zdeiMob:addListener('WEAPONSKILL_STATE_EXIT', 'ZDEI_WS_EXIT', function(mob, skillID) - if skillID == xi.mobSkill.OPTIC_INDURATION_CHARGE then + zdeiMob:addListener('WEAPONSKILL_STATE_EXIT', 'ZDEI_WS_EXIT', function(mob, skillId, wasExecuted) + if skillId == xi.mobSkill.OPTIC_INDURATION_CHARGE then local chargeCount = mob:getLocalVar('chargeCount') local chargeTotal = mob:getLocalVar('chargeTotal') @@ -64,7 +64,7 @@ g_mixins.families.zdei = function(zdeiMob) mob:useMobAbility(xi.mobSkill.OPTIC_INDURATION_CHARGE) end - elseif skillID == xi.mobSkill.OPTIC_INDURATION then + elseif skillId == xi.mobSkill.OPTIC_INDURATION then mob:setAutoAttackEnabled(true) mob:setMagicCastingEnabled(true) mob:setLocalVar('chargeCount', 0) diff --git a/scripts/zones/Bearclaw_Pinnacle/mobs/Snoll_Tzar.lua b/scripts/zones/Bearclaw_Pinnacle/mobs/Snoll_Tzar.lua index 6252a77f791..c8de6c5589f 100644 --- a/scripts/zones/Bearclaw_Pinnacle/mobs/Snoll_Tzar.lua +++ b/scripts/zones/Bearclaw_Pinnacle/mobs/Snoll_Tzar.lua @@ -14,8 +14,8 @@ end entity.onMobSpawn = function(mob) mob:setMobMod(xi.mobMod.BASE_DAMAGE_MULTIPLIER, 200) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'SNOLL_EXPLOSION', function(snoll, skillID) - if skillID == xi.mobSkill.HYPOTHERMAL_COMBUSTION_2 then + mob:addListener('WEAPONSKILL_STATE_EXIT', 'SNOLL_EXPLOSION', function(snoll, skillId, wasExecuted) + if skillId == xi.mobSkill.HYPOTHERMAL_COMBUSTION_2 then snoll:getBattlefield():lose() end end) diff --git a/scripts/zones/Boneyard_Gully/mobs/Tuchulcha.lua b/scripts/zones/Boneyard_Gully/mobs/Tuchulcha.lua index 323197f5f8a..4b4ddcd013a 100644 --- a/scripts/zones/Boneyard_Gully/mobs/Tuchulcha.lua +++ b/scripts/zones/Boneyard_Gully/mobs/Tuchulcha.lua @@ -72,9 +72,9 @@ end entity.onMobSpawn = function(mob) mob:setLocalVar('sandpitsUsed', 0) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'TUCHULCHA_SANDPIT', function(tuchulcha, skillID) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'TUCHULCHA_SANDPIT', function(tuchulcha, skillId, wasExecuted) if - skillID == xi.mobSkill.SANDPIT_1 and + skillId == xi.mobSkill.SANDPIT_1 and tuchulcha:getLocalVar('sandpitTriggered') == 1 then -- Prevent further teleports until the next triggered Sandpit. diff --git a/scripts/zones/Empyreal_Paradox/mobs/Prishe.lua b/scripts/zones/Empyreal_Paradox/mobs/Prishe.lua index 42188a365b7..43c1baeba4e 100644 --- a/scripts/zones/Empyreal_Paradox/mobs/Prishe.lua +++ b/scripts/zones/Empyreal_Paradox/mobs/Prishe.lua @@ -153,10 +153,10 @@ entity.onMobSpawn = function(mob) end end) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'PRISHE_DAEDALUS', function(mobArg, skillID) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'PRISHE_DAEDALUS', function(mobArg, skillId, wasExecuted) -- Handle Daedulus Wing TP restoration if - skillID == xi.mobSkill.ITEM_1_PRISHE and + skillId == xi.mobSkill.ITEM_1_PRISHE and mobArg:getLocalVar('daedulus') == 1 then mobArg:setTP(3000) @@ -164,7 +164,7 @@ entity.onMobSpawn = function(mob) end -- Reset animation sub after Nullifying Dropkick completes - if skillID == xi.mobSkill.NULLIFYING_DROPKICK_1 then + if skillId == xi.mobSkill.NULLIFYING_DROPKICK_1 then local target = mobArg:getTarget() if target then target:setAnimationSub(0) diff --git a/scripts/zones/Full_Moon_Fountain/mobs/Ajido-Marujido.lua b/scripts/zones/Full_Moon_Fountain/mobs/Ajido-Marujido.lua index b53d9124405..339684b22e6 100644 --- a/scripts/zones/Full_Moon_Fountain/mobs/Ajido-Marujido.lua +++ b/scripts/zones/Full_Moon_Fountain/mobs/Ajido-Marujido.lua @@ -72,7 +72,7 @@ entity.onMobInitialize = function(mob) mobArg:useMobAbility(xi.mobSkill.AJIDO_WARP_OUT, nil, 0) end) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'WARP_OUT_COMPLETE', function(mobArg, skillId) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'WARP_OUT_COMPLETE', function(mobArg, skillId, wasExecuted) if skillId == xi.mobSkill.AJIDO_WARP_OUT then local config = teleportConfig[mobArg:getBattlefield():getArea()] local targetPosition = utils.randomEntry(config.positions) diff --git a/scripts/zones/Horlais_Peak/mobs/Chlevnik.lua b/scripts/zones/Horlais_Peak/mobs/Chlevnik.lua index de0c72577f0..4122db4f644 100644 --- a/scripts/zones/Horlais_Peak/mobs/Chlevnik.lua +++ b/scripts/zones/Horlais_Peak/mobs/Chlevnik.lua @@ -14,8 +14,8 @@ entity.onMobInitialize = function(mob) 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) - if skillID == xi.mobSkill.FINAL_METEOR then + 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 diff --git a/scripts/zones/LaLoff_Amphitheater/mobs/Ark_Angel_TT.lua b/scripts/zones/LaLoff_Amphitheater/mobs/Ark_Angel_TT.lua index 825a0055140..f0c258b7251 100644 --- a/scripts/zones/LaLoff_Amphitheater/mobs/Ark_Angel_TT.lua +++ b/scripts/zones/LaLoff_Amphitheater/mobs/Ark_Angel_TT.lua @@ -74,7 +74,7 @@ entity.onMobSpawn = function(mob) }) -- Set up warp behavior listeners - mob:addListener('WEAPONSKILL_STATE_EXIT', 'WARP_OUT_COMPLETE', function(ttMob, skillId) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'WARP_OUT_COMPLETE', function(ttMob, skillId, wasExecuted) if skillId == xi.mobSkill.ARKANGEL_TT_WARP_OUT then local config = teleportConfig[ttMob:getBattlefield():getArea()] if config then diff --git a/scripts/zones/Mine_Shaft_2716/mobs/Chekochuk.lua b/scripts/zones/Mine_Shaft_2716/mobs/Chekochuk.lua index aa0a48366af..ecccee8797d 100644 --- a/scripts/zones/Mine_Shaft_2716/mobs/Chekochuk.lua +++ b/scripts/zones/Mine_Shaft_2716/mobs/Chekochuk.lua @@ -26,7 +26,7 @@ entity.onMobSpawn = function(mob) mob:setMobAbilityEnabled(false) -- Add listener for dice reset reactions from other Moblins - mob:addListener('WEAPONSKILL_STATE_EXIT', 'CHEKOCHUK_DICE_RESET', function(mobArg, skillId) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'CHEKOCHUK_DICE_RESET', function(mobArg, skillId, wasExecuted) if skillId ~= xi.mobSkill.GOBLIN_DICE_RESET then return end diff --git a/scripts/zones/Mine_Shaft_2716/mobs/Swipostik.lua b/scripts/zones/Mine_Shaft_2716/mobs/Swipostik.lua index c5cdaef8b77..23bc1b7cbb3 100644 --- a/scripts/zones/Mine_Shaft_2716/mobs/Swipostik.lua +++ b/scripts/zones/Mine_Shaft_2716/mobs/Swipostik.lua @@ -26,7 +26,7 @@ entity.onMobSpawn = function(mob) mob:setMobAbilityEnabled(false) -- Add listener for bomb reactions from other Moblins - mob:addListener('WEAPONSKILL_STATE_EXIT', 'SWIPOSTIK_BOMB_TOSS', function(mobArg, skillId) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'SWIPOSTIK_BOMB_TOSS', function(mobArg, skillId, wasExecuted) if skillId ~= xi.mobSkill.BOMB_TOSS_1 then return end diff --git a/scripts/zones/Monarch_Linn/mobs/Razon.lua b/scripts/zones/Monarch_Linn/mobs/Razon.lua index 6fab736aa8e..0a8600b45c2 100644 --- a/scripts/zones/Monarch_Linn/mobs/Razon.lua +++ b/scripts/zones/Monarch_Linn/mobs/Razon.lua @@ -33,7 +33,7 @@ entity.onMobInitialize = function(mob) mob:setMobMod(xi.mobMod.MAGIC_RANGE, 40) -- When the final self destruct is triggered, all players get kicked out of the battlefield immediately - mob:addListener('WEAPONSKILL_STATE_EXIT', 'FINAL_SELF_DESTRUCT', function(mobArg, skillId) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'FINAL_SELF_DESTRUCT', function(mobArg, skillId, wasExecuted) if skillId ~= xi.mobSkill.SELF_DESTRUCT_CLUSTER_RAZON then return end diff --git a/scripts/zones/Nyzul_Isle/mobs/Long-Gunned_Chariot.lua b/scripts/zones/Nyzul_Isle/mobs/Long-Gunned_Chariot.lua index 7d04010f571..67e3971ed81 100644 --- a/scripts/zones/Nyzul_Isle/mobs/Long-Gunned_Chariot.lua +++ b/scripts/zones/Nyzul_Isle/mobs/Long-Gunned_Chariot.lua @@ -12,8 +12,8 @@ entity.onMobSpawn = function(mob) -- local data = mob:getData('homing') -- sets homing missile variant -- data.HM = 1 - mob:addListener('WEAPONSKILL_STATE_EXIT', 'HOMING_MISSILE_WEAPONSKILL_STATE_EXIT', function(chariotMob, skillid) - if skillid == 2058 then + mob:addListener('WEAPONSKILL_STATE_EXIT', 'HOMING_MISSILE_WEAPONSKILL_STATE_EXIT', function(chariotMob, skillId, wasExecuted) + if skillId == 2058 then chariotMob:setLocalVar('firstHit', 0) end end) diff --git a/scripts/zones/RuAun_Gardens/mobs/Despot.lua b/scripts/zones/RuAun_Gardens/mobs/Despot.lua index dbbc5557f12..689878fefbe 100644 --- a/scripts/zones/RuAun_Gardens/mobs/Despot.lua +++ b/scripts/zones/RuAun_Gardens/mobs/Despot.lua @@ -45,37 +45,10 @@ entity.onMobInitialize = function(mob) mob:addImmunity(xi.immunity.PETRIFY) mob:addImmunity(xi.immunity.TERROR) mob:addImmunity(xi.immunity.PLAGUE) - mob:setMobMod(xi.mobMod.BASE_DAMAGE_MULTIPLIER, 150) -end - -entity.onMobSpawn = function(mob) - local zone = mob:getZone() - if zone then - local ph = GetMobByID(zone:getLocalVar('DespotPlaceholderID')) - if ph then - local pos = ph:getPos() - local killerId = ph:getLocalVar('killer') - - mob:setPos(pos.x, pos.y, pos.z, pos.r) - - if killerId ~= 0 then - local killer = GetPlayerByID(killerId) - - if - killer and - not killer:isEngaged() and - killer:checkDistance(mob) <= 50 - then - mob:updateClaim(killer) - end - end - end - end - - mob:addListener('WEAPONSKILL_STATE_EXIT', 'PH_VAR', function(mobArg, skillID) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'PH_VAR', function(mobArg, skillId, wasExecuted) -- Despot rapidly uses several Panzerfaust in a row - local counter = mob:getLocalVar('panzerfaustCounter') + local counter = mob:getLocalVar('panzerfaustCounter') local maxCount = mob:getLocalVar('panzerfaustMax') mob:setLocalVar('panzerfaustCounter', counter + 1) @@ -95,27 +68,62 @@ entity.onMobSpawn = function(mob) end) end -entity.onMobFight = function(mob, target) - local counter = mob:getLocalVar('panzerfaustCounter') - local maxCount = mob:getLocalVar('panzerfaustMax') +entity.onMobSpawn = function(mob) + mob:setMobMod(xi.mobMod.BASE_DAMAGE_MULTIPLIER, 150) + + -- Early return: No zone object. + local zone = mob:getZone() + if not zone then + return + end + + -- Early return: No placeholder ID. + local ph = GetMobByID(zone:getLocalVar('DespotPlaceholderID')) + if not ph then + return + end + + -- Handle position. + local pos = ph:getPos() + mob:setPos(pos.x, pos.y, pos.z, pos.r) + + -- Handle enmity/claim. + local killerId = ph:getLocalVar('killer') + if killerId == 0 then + return + end + + local killer = GetPlayerByID(killerId) + if not killer then + return + end if - counter > 0 and - counter <= maxCount and - not xi.combat.behavior.isEntityBusy(mob) + not killer:isEngaged() and + killer:checkDistance(mob) <= 50 then - mob:useMobAbility(xi.mobSkill.PANZERFAUST, nil, 0) + mob:updateClaim(killer) end end -entity.onMobWeaponSkill = function(mob, target, skill, action) - skill:setAnimationTime(0) -end +entity.onMobFight = function(mob, target) + if xi.combat.behavior.isEntityBusy(mob) then + return + end -entity.onMobDeath = function(mob, player, optParams) + local counter = mob:getLocalVar('panzerfaustCounter') + if counter == 0 then + return + end + + local maxCount = mob:getLocalVar('panzerfaustMax') + if counter <= maxCount then + mob:useMobAbility(xi.mobSkill.PANZERFAUST, nil, 0) + end end -entity.onMobDespawn = function(mob) +entity.onMobWeaponSkill = function(mob, target, skill, action) + skill:setAnimationTime(0) end return entity diff --git a/scripts/zones/The_Shrouded_Maw/mobs/Diabolos.lua b/scripts/zones/The_Shrouded_Maw/mobs/Diabolos.lua index 42ee50178c1..77a9f86072b 100644 --- a/scripts/zones/The_Shrouded_Maw/mobs/Diabolos.lua +++ b/scripts/zones/The_Shrouded_Maw/mobs/Diabolos.lua @@ -75,9 +75,9 @@ entity.onMobSpawn = function(mob) mob:setLocalVar('instance', inst) mob:setLocalVar('nightmarePercent', math.random(25, 75)) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'DIABOLOS_NIGHTMARE_WS', function(mobArg, skillID) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'DIABOLOS_NIGHTMARE_WS', function(mobArg, skillId, wasExecuted) if - skillID == xi.mobSkill.NIGHTMARE_1 and + skillId == xi.mobSkill.NIGHTMARE_1 and mobArg:getLocalVar('specialNightmare') == 1 then mobArg:setLocalVar('specialNightmare', 0) diff --git a/scripts/zones/The_Shrouded_Maw/mobs/Diabolos_DN.lua b/scripts/zones/The_Shrouded_Maw/mobs/Diabolos_DN.lua index 2d2dad10c54..729c18f86f6 100644 --- a/scripts/zones/The_Shrouded_Maw/mobs/Diabolos_DN.lua +++ b/scripts/zones/The_Shrouded_Maw/mobs/Diabolos_DN.lua @@ -75,9 +75,9 @@ entity.onMobSpawn = function(mob) mob:setMobMod(xi.mobMod.BASE_DAMAGE_MULTIPLIER, 150) mob:setMobMod(xi.mobMod.NO_STANDBACK, 1) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'DIABOLOS_NIGHTMARE_WS', function(mobArg, skillID) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'DIABOLOS_NIGHTMARE_WS', function(mobArg, skillId, wasExecuted) if - skillID == xi.mobSkill.NIGHTMARE_1 and + skillId == xi.mobSkill.NIGHTMARE_1 and mobArg:getLocalVar('specialNightmare') == 1 then mobArg:setLocalVar('specialNightmare', 0) diff --git a/scripts/zones/The_Shrouded_Maw/mobs/Diabolos_WD.lua b/scripts/zones/The_Shrouded_Maw/mobs/Diabolos_WD.lua index 844052c4f4b..93dc86ea5b3 100644 --- a/scripts/zones/The_Shrouded_Maw/mobs/Diabolos_WD.lua +++ b/scripts/zones/The_Shrouded_Maw/mobs/Diabolos_WD.lua @@ -80,9 +80,9 @@ entity.onMobSpawn = function(mob) mob:setMobMod(xi.mobMod.MAGIC_COOL, 20) mob:setMod(xi.mod.REGAIN, 55) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'DIABOLOS_NIGHTMARE_WS', function(mobArg, skillID) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'DIABOLOS_NIGHTMARE_WS', function(mobArg, skillId, wasExecuted) if - skillID == xi.mobSkill.NIGHTMARE_1 and + skillId == xi.mobSkill.NIGHTMARE_1 and mobArg:getLocalVar('specialNightmare') == 1 then mobArg:setLocalVar('specialNightmare', 0) diff --git a/scripts/zones/Throne_Room/mobs/Shadow_of_Rage.lua b/scripts/zones/Throne_Room/mobs/Shadow_of_Rage.lua index 38b39b71ff6..bb0a8a882a8 100644 --- a/scripts/zones/Throne_Room/mobs/Shadow_of_Rage.lua +++ b/scripts/zones/Throne_Room/mobs/Shadow_of_Rage.lua @@ -14,7 +14,7 @@ entity.onMobInitialize = function(mob) mob:addImmunity(xi.immunity.DARK_SLEEP) -- 50% chance to immediately TP move again (but only once per chain) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'SHADOW_TP_CHAIN', function(mobEntity, skillID) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'SHADOW_TP_CHAIN', function(mobEntity, skillId, wasExecuted) local justChained = mobEntity:getLocalVar('justChained') -- Only allow chaining if this wasn't already a chained TP move diff --git a/scripts/zones/Throne_Room/mobs/Zeid_2.lua b/scripts/zones/Throne_Room/mobs/Zeid_2.lua index 7436385a72e..2c3ff6e11d5 100644 --- a/scripts/zones/Throne_Room/mobs/Zeid_2.lua +++ b/scripts/zones/Throne_Room/mobs/Zeid_2.lua @@ -16,7 +16,7 @@ entity.onMobInitialize = function(mob) mob:setMobMod(xi.mobMod.NO_REST, 1) -- 50% chance to immediately TP move again (but only once per chain) - mob:addListener('WEAPONSKILL_STATE_EXIT', 'ZEID_TP_CHAIN', function(mobEntity, skillID) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'ZEID_TP_CHAIN', function(mobEntity, skillId, wasExecuted) local justChained = mobEntity:getLocalVar('justChained') -- Only allow chaining if this wasn't already a chained TP move diff --git a/scripts/zones/Wajaom_Woodlands/mobs/Gharial.lua b/scripts/zones/Wajaom_Woodlands/mobs/Gharial.lua index b8a3d7a9c63..8a24a7c9f32 100644 --- a/scripts/zones/Wajaom_Woodlands/mobs/Gharial.lua +++ b/scripts/zones/Wajaom_Woodlands/mobs/Gharial.lua @@ -20,7 +20,7 @@ entity.onMobSpawn = function(mob) -- https://www.youtube.com/watch?v=CyTY32jS9pU -- https://ffxiclopedia.fandom.com/wiki/Gharial - mob:addListener('WEAPONSKILL_STATE_EXIT', 'USE_BOILING_BLOOD', function(mobArg, skillId) + mob:addListener('WEAPONSKILL_STATE_EXIT', 'USE_BOILING_BLOOD', function(mobArg, skillId, wasExecuted) local roarAbility = 2101 local boilingBlood = 2102 diff --git a/src/map/ai/states/mobskill_state.cpp b/src/map/ai/states/mobskill_state.cpp index 670cd5bcc0f..3e3c57b6694 100644 --- a/src/map/ai/states/mobskill_state.cpp +++ b/src/map/ai/states/mobskill_state.cpp @@ -235,16 +235,22 @@ bool CMobSkillState::Update(timer::time_point tick) void CMobSkillState::Cleanup(timer::time_point tick) { - if (m_PEntity && !IsCompleted()) + if (!m_PEntity) + { + return; + } + + // Interrupted. + if (!IsCompleted()) { ActionInterrupts::AbilityInterrupt(m_PEntity); reduceTpOnInterrupt(); } - // Call finalizer if skill completed (not interrupted) and set any final animationsub - if (m_PEntity && IsCompleted()) + // Not interrupted. + else { - if (m_PSkill->getFinalAnimationSub().has_value() && m_PEntity && m_PEntity->isAlive()) + if (m_PEntity->isAlive() && m_PSkill->getFinalAnimationSub().has_value()) { m_PEntity->animationsub = m_PSkill->getFinalAnimationSub().value(); m_PEntity->updatemask |= UPDATE_COMBAT; @@ -253,9 +259,10 @@ void CMobSkillState::Cleanup(timer::time_point tick) luautils::OnMobSkillFinalize(m_PEntity, m_PSkill.get()); } - if (m_PEntity) + // Call listener. Feed skill result. + if (m_PEntity->isAlive()) { - m_PEntity->PAI->EventHandler.triggerListener("WEAPONSKILL_STATE_EXIT", m_PEntity, m_PSkill->getID()); + m_PEntity->PAI->EventHandler.triggerListener("WEAPONSKILL_STATE_EXIT", m_PEntity, m_PSkill->getID(), IsCompleted()); } } diff --git a/src/map/ai/states/petskill_state.cpp b/src/map/ai/states/petskill_state.cpp index 133dc20028a..4d2e974d8f8 100644 --- a/src/map/ai/states/petskill_state.cpp +++ b/src/map/ai/states/petskill_state.cpp @@ -146,7 +146,6 @@ bool CPetSkillState::Update(timer::time_point tick) bool withMaster = m_PEntity->objtype == TYPE_PET; static_cast(PTarget)->PEnmityContainer->UpdateEnmity(m_PEntity, 0, 0, withMaster); } - m_PEntity->PAI->EventHandler.triggerListener("WEAPONSKILL_STATE_EXIT", m_PEntity, m_PSkill->getID()); if (m_PEntity->objtype == TYPE_PET && m_PEntity->PMaster && m_PEntity->PMaster->objtype == TYPE_PC && (m_PSkill->isBloodPactRage() || m_PSkill->isBloodPactWard())) { @@ -180,14 +179,32 @@ bool CPetSkillState::Update(timer::time_point tick) void CPetSkillState::Cleanup(timer::time_point tick) { - if (m_PEntity && m_PEntity->isAlive() && !IsCompleted()) + if (!m_PEntity) + { + return; + } + + // Interrupted. + if (!IsCompleted()) { ActionInterrupts::AbilityInterrupt(m_PEntity); } - if (m_PSkill->getFinalAnimationSub().has_value() && m_PEntity && m_PEntity->isAlive()) + // Not interrupted. + else + { + if (m_PEntity->isAlive() && m_PSkill->getFinalAnimationSub().has_value()) + { + m_PEntity->animationsub = m_PSkill->getFinalAnimationSub().value(); + m_PEntity->updatemask |= UPDATE_COMBAT; + } + + // luautils::OnMobSkillFinalize(m_PEntity, m_PSkill.get()); + } + + // Call listener. Feed skill result. + if (m_PEntity->isAlive()) { - m_PEntity->animationsub = m_PSkill->getFinalAnimationSub().value(); - m_PEntity->updatemask |= UPDATE_COMBAT; + m_PEntity->PAI->EventHandler.triggerListener("WEAPONSKILL_STATE_EXIT", m_PEntity, m_PSkill->getID(), IsCompleted()); } } diff --git a/src/map/ai/states/weaponskill_state.cpp b/src/map/ai/states/weaponskill_state.cpp index 936d3e33c6b..1eab8ab0912 100644 --- a/src/map/ai/states/weaponskill_state.cpp +++ b/src/map/ai/states/weaponskill_state.cpp @@ -182,7 +182,6 @@ bool CWeaponSkillState::Update(timer::time_point tick) CCharEntity* PChar = static_cast(m_PEntity); PChar->m_charHistory.wsUsed++; } - m_PEntity->PAI->EventHandler.triggerListener("WEAPONSKILL_STATE_EXIT", m_PEntity, m_PSkill->getID()); return true; } return false; @@ -190,5 +189,24 @@ bool CWeaponSkillState::Update(timer::time_point tick) void CWeaponSkillState::Cleanup(timer::time_point tick) { - // TODO: interrupt an in progress ws + if (!m_PEntity) + { + return; + } + + // Interrupted. + if (!IsCompleted()) + { + } + + // Not interrupted. + else + { + } + + // Call listener. Feed skill result. + if (m_PEntity->isAlive()) + { + m_PEntity->PAI->EventHandler.triggerListener("WEAPONSKILL_STATE_EXIT", m_PEntity, m_PSkill->getID(), IsCompleted()); + } } From 33422d5d1cbd722a0515d34b9aacdc78f1b6d4cc Mon Sep 17 00:00:00 2001 From: Xaver-DaRed Date: Tue, 17 Mar 2026 06:52:32 +0100 Subject: [PATCH 2/2] Move `WEAPONSKILL_USE` and `WEAPONSKILL_TAKE` listeners --- src/map/entities/battleentity.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/map/entities/battleentity.cpp b/src/map/entities/battleentity.cpp index e400bc23083..812c98482e8 100644 --- a/src/map/entities/battleentity.cpp +++ b/src/map/entities/battleentity.cpp @@ -2669,10 +2669,12 @@ void CBattleEntity::OnMobSkillFinished(CMobSkillState& state, action_t& action) else { damage = luautils::OnMobWeaponSkill(this, PTargetFound, PSkill, &action); - this->PAI->EventHandler.triggerListener("WEAPONSKILL_USE", this, PTargetFound, PSkill, state.GetSpentTP(), &action, damage); - PTargetFound->PAI->EventHandler.triggerListener("WEAPONSKILL_TAKE", this, PTargetFound, PSkill, state.GetSpentTP(), &action); } + // Call USE and TAKE listeners, no matter what. + this->PAI->EventHandler.triggerListener("WEAPONSKILL_USE", this, PTargetFound, PSkill, state.GetSpentTP(), &action, damage); + PTargetFound->PAI->EventHandler.triggerListener("WEAPONSKILL_TAKE", this, PTargetFound, PSkill, state.GetSpentTP(), &action); + if (msg == MsgBasic::None) { msg = PSkill->getMsg();