From 7fbf535b808216d2e4af02cffce0eeb232d0eb88 Mon Sep 17 00:00:00 2001 From: Skold177 <113406182+Skold177@users.noreply.github.com> Date: Sun, 18 Jan 2026 14:08:11 -0500 Subject: [PATCH] [lua] [sql] ENM Shell We Dance? Implements the ENM Shell We Dance? --- scripts/actions/mobskills/gas_shell.lua | 3 +- scripts/actions/mobskills/painful_whip.lua | 11 +- scripts/actions/mobskills/palsynyxis.lua | 8 +- .../actions/mobskills/suctorial_tentacle.lua | 12 +- scripts/actions/mobskills/venom_shell.lua | 5 +- .../Boneyard_Gully/shell_we_dance.lua | 85 +++++-- scripts/enum/mob_skill.lua | 5 + .../zones/Boneyard_Gully/mobs/Bladmall.lua | 230 +++++++++++++++--- .../Boneyard_Gully/mobs/Nepionic_Bladmall.lua | 37 ++- .../Boneyard_Gully/mobs/Nepionic_Parata.lua | 15 +- scripts/zones/Boneyard_Gully/mobs/Parata.lua | 187 +++++++++++--- sql/mob_groups.sql | 8 +- sql/mob_pools.sql | 8 +- sql/mob_skill_lists.sql | 10 +- sql/mob_skills.sql | 10 +- 15 files changed, 498 insertions(+), 136 deletions(-) diff --git a/scripts/actions/mobskills/gas_shell.lua b/scripts/actions/mobskills/gas_shell.lua index ddc09b7ff54..b5b85d92f7c 100644 --- a/scripts/actions/mobskills/gas_shell.lua +++ b/scripts/actions/mobskills/gas_shell.lua @@ -6,6 +6,7 @@ -- Utsusemi/Blink absorb: Ignores shadows -- Range: Unknown radial -- Notes: Poison is about 24/tic. The Nightmare Uragnite uses an enhanced version that also inflicts Plague. +-- TODO: Gas shell probably scales with level, needs captures. ----------------------------------- ---@type TMobSkill local mobskillObject = {} @@ -15,7 +16,7 @@ mobskillObject.onMobSkillCheck = function(target, mob, skill) end mobskillObject.onMobWeaponSkill = function(target, mob, skill) - skill:setMsg(xi.mobskills.mobStatusEffectMove(mob, target, xi.effect.POISON, math.random(23, 24), 0, 60)) + skill:setMsg(xi.mobskills.mobStatusEffectMove(mob, target, xi.effect.POISON, math.random(23, 24), 0, math.random(30, 90))) return xi.effect.POISON end diff --git a/scripts/actions/mobskills/painful_whip.lua b/scripts/actions/mobskills/painful_whip.lua index 551385a70a3..c3b1ce667d8 100644 --- a/scripts/actions/mobskills/painful_whip.lua +++ b/scripts/actions/mobskills/painful_whip.lua @@ -11,12 +11,13 @@ end mobskillObject.onMobWeaponSkill = function(target, mob, skill) local numhits = 1 - local ftp = 2.5 - local accmod = 1 - local info = xi.mobskills.mobPhysicalMove(mob, target, skill, numhits, accmod, ftp, xi.mobskills.physicalTpBonus.NO_EFFECT) - - local dmg = xi.mobskills.mobFinalAdjustments(info.dmg, mob, skill, target, xi.attackType.PHYSICAL, xi.damageType.BLUNT, info.hitslanded) + local ftp = 3.0 + local accmod = 1 + local params = { canCrit = true } + local info = xi.mobskills.mobPhysicalMove(mob, target, skill, numhits, accmod, ftp, xi.mobskills.physicalTpBonus.NO_EFFECT, 0, 0, 0, params) + local dmg = xi.mobskills.mobFinalAdjustments(info.dmg, mob, skill, target, xi.attackType.PHYSICAL, xi.damageType.BLUNT, info.hitslanded) target:takeDamage(dmg, mob, xi.attackType.PHYSICAL, xi.damageType.BLUNT) + return dmg end diff --git a/scripts/actions/mobskills/palsynyxis.lua b/scripts/actions/mobskills/palsynyxis.lua index f60d964bdc1..71705f274e3 100644 --- a/scripts/actions/mobskills/palsynyxis.lua +++ b/scripts/actions/mobskills/palsynyxis.lua @@ -15,10 +15,10 @@ end mobskillObject.onMobWeaponSkill = function(target, mob, skill) local numhits = 1 - local accmod = 1 - local ftp = math.random(1, 2) - local info = xi.mobskills.mobPhysicalMove(mob, target, skill, numhits, accmod, ftp, xi.mobskills.physicalTpBonus.NO_EFFECT) - local dmg = xi.mobskills.mobFinalAdjustments(info.dmg, mob, skill, target, xi.attackType.PHYSICAL, xi.damageType.SLASHING, info.hitslanded) + local accmod = 1 + local ftp = 1.5 + local info = xi.mobskills.mobPhysicalMove(mob, target, skill, numhits, accmod, ftp, xi.mobskills.physicalTpBonus.NO_EFFECT) + local dmg = xi.mobskills.mobFinalAdjustments(info.dmg, mob, skill, target, xi.attackType.PHYSICAL, xi.damageType.SLASHING, info.hitslanded) xi.mobskills.mobPhysicalStatusEffectMove(mob, target, skill, xi.effect.PARALYSIS, 25, 0, 120) diff --git a/scripts/actions/mobskills/suctorial_tentacle.lua b/scripts/actions/mobskills/suctorial_tentacle.lua index d7f38c00f9a..14c37d12406 100644 --- a/scripts/actions/mobskills/suctorial_tentacle.lua +++ b/scripts/actions/mobskills/suctorial_tentacle.lua @@ -1,6 +1,9 @@ ----------------------------------- --- Poison Sting --- Induces poison +-- Suctorial Tentacle +-- Binds target for 30-90 seconds +-- Type: Enfeebling +-- Utsusemi/Blink absorb: Ignores shadows +-- Range: Melee ----------------------------------- ---@type TMobSkill local mobskillObject = {} @@ -10,9 +13,8 @@ mobskillObject.onMobSkillCheck = function(target, mob, skill) end mobskillObject.onMobWeaponSkill = function(target, mob, skill) - skill:setMsg(xi.mobskills.mobStatusEffectMove(mob, target, xi.effect.POISON, 5, 3, 180)) - - return xi.effect.POISON + skill:setMsg(xi.mobskills.mobStatusEffectMove(mob, target, xi.effect.BIND, 1, 0, math.random(30, 90))) + return xi.effect.BIND end return mobskillObject diff --git a/scripts/actions/mobskills/venom_shell.lua b/scripts/actions/mobskills/venom_shell.lua index 832f241a783..9a2f5270fcb 100644 --- a/scripts/actions/mobskills/venom_shell.lua +++ b/scripts/actions/mobskills/venom_shell.lua @@ -15,7 +15,10 @@ mobskillObject.onMobSkillCheck = function(target, mob, skill) end mobskillObject.onMobWeaponSkill = function(target, mob, skill) - skill:setMsg(xi.mobskills.mobStatusEffectMove(mob, target, xi.effect.POISON, 12, 0, 120)) + local power = math.floor(mob:getMainLvl() / 2) - 2 + power = math.max(power, 16) -- Floor of 16 damage per tick + + skill:setMsg(xi.mobskills.mobStatusEffectMove(mob, target, xi.effect.POISON, power, 0, 120)) return xi.effect.POISON end diff --git a/scripts/battlefields/Boneyard_Gully/shell_we_dance.lua b/scripts/battlefields/Boneyard_Gully/shell_we_dance.lua index f4a8cca2b5a..a451926a754 100644 --- a/scripts/battlefields/Boneyard_Gully/shell_we_dance.lua +++ b/scripts/battlefields/Boneyard_Gully/shell_we_dance.lua @@ -23,36 +23,89 @@ local content = Battlefield:new({ boneyardGullyID.mob.PARATA + 26, }, - grantXP = 2000, - - experimental = true, + grantXP = 3000, }) --- TODO: Needs additional cleanup and mixin work (previous comment). Examine --- mob spawn handling and move hardcoded IDs to this script or the mob and read as necessary. +content.groups = +{ + { + mobIds = + { + { + boneyardGullyID.mob.PARATA, + boneyardGullyID.mob.PARATA + 1, + }, + + { + boneyardGullyID.mob.PARATA + 9, + boneyardGullyID.mob.PARATA + 10, + }, + + { + boneyardGullyID.mob.PARATA + 18, + boneyardGullyID.mob.PARATA + 19, + }, + + }, + + allDeath = utils.bind(content.handleAllMonstersDefeated, content), + }, + + { + mobIds = + { + { + boneyardGullyID.mob.PARATA + 2, + boneyardGullyID.mob.PARATA + 3, + boneyardGullyID.mob.PARATA + 4, + boneyardGullyID.mob.PARATA + 5, + boneyardGullyID.mob.PARATA + 6, + boneyardGullyID.mob.PARATA + 7, + }, + + { + boneyardGullyID.mob.PARATA + 11, + boneyardGullyID.mob.PARATA + 12, + boneyardGullyID.mob.PARATA + 13, + boneyardGullyID.mob.PARATA + 14, + boneyardGullyID.mob.PARATA + 15, + boneyardGullyID.mob.PARATA + 16, + }, -content:addEssentialMobs({ 'Parata', 'Bladmall' }) + { + boneyardGullyID.mob.PARATA + 20, + boneyardGullyID.mob.PARATA + 21, + boneyardGullyID.mob.PARATA + 22, + boneyardGullyID.mob.PARATA + 23, + boneyardGullyID.mob.PARATA + 24, + boneyardGullyID.mob.PARATA + 25, + }, + }, + + spawned = false, + }, +} content.loot = { { - { itemId = xi.item.PIECE_OF_CASSIA_LUMBER, weight = 375 }, - { itemId = xi.item.SQUARE_OF_ELTORO_LEATHER, weight = 328 }, - { itemId = xi.item.DRAGON_BONE, weight = 263 }, + { itemId = xi.item.PIECE_OF_CASSIA_LUMBER, weight = 3750 }, + { itemId = xi.item.SQUARE_OF_ELTORO_LEATHER, weight = 3750 }, + { itemId = xi.item.DRAGON_BONE, weight = 2500 }, }, { - { itemId = xi.item.NONE, weight = 850 }, - { itemId = xi.item.CLOUD_EVOKER, weight = 150 }, + { itemId = xi.item.NONE, weight = 9500 }, + { itemId = xi.item.CLOUD_EVOKER, weight = 500 }, }, { quantity = 2, - { itemId = xi.item.NONE, weight = 275 }, - { itemId = xi.item.STONE_SPLITTER, weight = 150 }, - { itemId = xi.item.FRENZY_FIFE, weight = 150 }, - { itemId = xi.item.BLAU_DOLCH, weight = 150 }, - { itemId = xi.item.SCROLL_OF_ARMYS_PAEON_V, weight = 275 }, + { itemId = xi.item.NONE, weight = 2750 }, + { itemId = xi.item.STONE_SPLITTER, weight = 1500 }, + { itemId = xi.item.FRENZY_FIFE, weight = 1500 }, + { itemId = xi.item.BLAU_DOLCH, weight = 1500 }, + { itemId = xi.item.SCROLL_OF_ARMYS_PAEON_V, weight = 2750 }, }, } diff --git a/scripts/enum/mob_skill.lua b/scripts/enum/mob_skill.lua index 49a36d75396..d4988682f16 100644 --- a/scripts/enum/mob_skill.lua +++ b/scripts/enum/mob_skill.lua @@ -160,6 +160,11 @@ xi.mobSkill = FRIGHTFUL_ROAR_1 = 501, MORTAL_RAY_1 = 502, UNBLESSED_ARMOR = 503, + GAS_SHELL_1 = 504, + VENOM_SHELL_1 = 505, + PALSYNYXIS_1 = 506, + PAINFUL_WHIP_1 = 507, + SUCTORIAL_TENTACLE_1 = 508, SELF_DESTRUCT_BOMB = 509, diff --git a/scripts/zones/Boneyard_Gully/mobs/Bladmall.lua b/scripts/zones/Boneyard_Gully/mobs/Bladmall.lua index 63bc16c404b..9595dcd54dc 100644 --- a/scripts/zones/Boneyard_Gully/mobs/Bladmall.lua +++ b/scripts/zones/Boneyard_Gully/mobs/Bladmall.lua @@ -1,64 +1,218 @@ ----------------------------------- --- Area: Boneyard Gully --- Mob: Bladmall --- ENM: Shell We Dance? +-- Area : Boneyard Gully +-- Mob : Bladmall +-- ENM : Shell We Dance? +-- NOTE : This Uragnite does not heal when going into its' shell. It should not use the Uragnite mixin. ----------------------------------- ---@type TMobEntity local entity = {} +----------------------------------- +-- Enter/Exit Shell functions +----------------------------------- +local function enterShell(mob) + mob:setAnimationSub(1) + mob:setAutoAttackEnabled(false) + mob:setMod(xi.mod.UDMGPHYS, -7500) + mob:setMod(xi.mod.UDMGRANGE, -7500) + mob:setMod(xi.mod.UDMGMAGIC, -7500) + mob:setMod(xi.mod.UDMGBREATH, -7500) + mob:setMobMod(xi.mobMod.NO_MOVE, 1) + mob:setMagicCastingEnabled(false) + mob:setLocalVar('shellExitTime', GetSystemTime() + math.random(50, 70)) + mob:useMobAbility(xi.mobSkill.VENOM_SHELL_1) +end + +local function exitShell(mob) + mob:setAnimationSub(0) + mob:setAutoAttackEnabled(true) + mob:setMod(xi.mod.UDMGPHYS, 0) + mob:setMod(xi.mod.UDMGRANGE, 0) + mob:setMod(xi.mod.UDMGMAGIC, 0) + mob:setMod(xi.mod.UDMGBREATH, 0) + mob:setMobMod(xi.mobMod.NO_MOVE, 0) + mob:setMagicCastingEnabled(true) +end + +----------------------------------- +-- Pet Setup +----------------------------------- +local petOffsets = { 4, 5, 6 } + +local callPetParams = +{ + dieWithOwner = true, -- Pets die when Bladmall dies. + ignoreBusy = true, + noAnimation = true, + maxSpawns = 1, +} + +local petSpawnTable = +{ + { hpp = 75, minDelay = 45, maxDelay = 90 }, -- 1st pet summoned at 75% HP or 45-90 seconds after engage. + { hpp = 55, minDelay = 105, maxDelay = 150 }, -- 2nd pet summoned at 55% HP or 105-150 seconds after previous pet. + { hpp = 35, minDelay = 105, maxDelay = 150 }, -- 3rd pet summoned at 35% HP or 105-150 seconds after previous pet. +} + +----------------------------------- +-- onMobInitialize +----------------------------------- +entity.onMobInitialize = function(mob) + mob:addImmunity(xi.immunity.BIND) + mob:addImmunity(xi.immunity.BLIND) + mob:addImmunity(xi.immunity.GRAVITY) + mob:addImmunity(xi.immunity.PARALYZE) + mob:addImmunity(xi.immunity.SILENCE) + mob:addImmunity(xi.immunity.DARK_SLEEP) + mob:addImmunity(xi.immunity.LIGHT_SLEEP) + mob:addImmunity(xi.immunity.STUN) + mob:setBehavior(xi.behavior.STANDBACK) +end +----------------------------------- +-- onMobSpawn +----------------------------------- entity.onMobSpawn = function(mob) + mob:setMod(xi.mod.REFRESH, 50) + mob:setMobMod(xi.mobMod.MAGIC_COOL, 20) + mob:setMobMod(xi.mobMod.STANDBACK_COOL, 0) + mob:setMobMod(xi.mobMod.MAGIC_DELAY, math.random(3, 7)) + mob:setMobMod(xi.mobMod.BASE_DAMAGE_MULTIPLIER, 150) + mob:setLocalVar('petPhase', 1) + mob:setLocalVar('nextPetTime', 0) end -entity.onMobFight = function(mob, target) - local battlefield = mob:getBattlefield() - if not battlefield then +----------------------------------- +-- onMobFight +----------------------------------- +entity.onMobFight = function(mob) + if xi.combat.behavior.isEntityBusy(mob) then return end - local mobId = mob:getID() - local mobHPP = mob:getHPP() - local adds = mob:getLocalVar('adds') - local petId = 0 + local currentTime = GetSystemTime() - -- Pet #1 spawn at 95% hp or less - if mobHPP <= 95 and adds == 0 then - petId = mobId + 4 + ----------------------------------- + -- Check if it's time to exit shell + ----------------------------------- + if + mob:getAnimationSub() == 1 and + currentTime >= mob:getLocalVar('shellExitTime') + then + exitShell(mob) + end - -- Pet #2 spawn at 60% hp or less - elseif mobHPP <= 60 and adds == 1 then - petId = mobId + 5 + ----------------------------------- + -- Enrage at 15% HP or below + ----------------------------------- + if + mob:getHPP() <= 15 and + mob:getLocalVar('enrage') == 0 + then + mob:setLocalVar('enrage', 1) + mob:injectActionPacket(mob:getID(), 11, 433, 0, 0x18, 0, 0, 0) + mob:setMobMod(xi.mobMod.MAGIC_COOL, 5) + mob:setMobMod(xi.mobMod.BASE_DAMAGE_MULTIPLIER, 200) + end - -- Pet #3 spawn at 40% hp or less - elseif mobHPP <= 40 and adds == 2 then - petId = mobId + 6 + ----------------------------------- + -- If all our pets have spawned, nothing else to do here + ----------------------------------- + local phase = mob:getLocalVar('petPhase') + if phase > #petSpawnTable then + return end - -- If we have spawned a pet - if petId > 0 then - mob:setLocalVar('adds', adds + 1) + ----------------------------------- + -- Set up first pet timer/threshold on first mob tick + ----------------------------------- + if + mob:getLocalVar('nextPetTime') == 0 and + phase == 1 + then + mob:setLocalVar('nextPetTime', currentTime + math.random(petSpawnTable[1].minDelay, petSpawnTable[1].maxDelay)) + return + end - local pet = SpawnMob(petId) - if pet then - battlefield:insertEntity(pet:getTargID(), false, true) - pet:updateEnmity(target) + ----------------------------------- + -- Check to see if it's time to spawn a pet either via HP threshold or timer + ----------------------------------- + if + petSpawnTable[phase] and + (mob:getHPP() <= petSpawnTable[phase].hpp or + currentTime >= mob:getLocalVar('nextPetTime')) + then + enterShell(mob) - local pos = mob:getPos() - pet:setPos(pos.x, pos.y, pos.z, pos.rot) + local pets = {} + for _, offset in ipairs(petOffsets) do + table.insert(pets, mob:getID() + offset) end - end -end -entity.onMobDeath = function(mob, player, optParams) - -- Kill adds. - if optParams.isKiller or optParams.noKiller then - local mobId = mob:getID() - for i = 4, 6 do - local pet = GetMobByID(mobId + i) - if pet and pet:isAlive() then - pet:setHP(0) + if xi.mob.callPets(mob, pets, callPetParams) then + phase = phase + 1 + mob:setLocalVar('petPhase', phase) + + if petSpawnTable[phase] then + mob:setLocalVar('nextPetTime', currentTime + math.random(petSpawnTable[phase].minDelay, petSpawnTable[phase].maxDelay)) end end end end +----------------------------------- +-- TP Moves - If in shell, use Venom Shell, otherwise, select from other skills +----------------------------------- +entity.onMobMobskillChoose = function(mob, target) + if mob:getAnimationSub() == 1 then + return xi.mobSkill.VENOM_SHELL_1 + end + + local skillList = + { + xi.mobSkill.GAS_SHELL_1, + xi.mobSkill.PALSYNYXIS_1, + xi.mobSkill.PAINFUL_WHIP_1, + xi.mobSkill.SUCTORIAL_TENTACLE_1, + } + + return skillList[math.random(1, #skillList)] +end + +----------------------------------- +-- Spell Selection +----------------------------------- +entity.onMobSpellChoose = function(mob, target, spellId) + local spellList = + { + [1] = { xi.magic.spell.WATER_IV, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [2] = { xi.magic.spell.WATERGA_III, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [3] = { xi.magic.spell.FLOOD, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [4] = { xi.magic.spell.CURE_V, mob, true, xi.action.type.HEALING_TARGET, 50, 0, 100 }, + [5] = { xi.magic.spell.CURAGA_IV, mob, true, xi.action.type.HEALING_FORCE_SELF, 50, 0, 100 }, + [6] = { xi.magic.spell.PROTECTRA_IV, mob, false, xi.action.type.ENHANCING_FORCE_SELF, xi.effect.PROTECT, 0, 100 }, + [7] = { xi.magic.spell.SHELLRA_IV, mob, false, xi.action.type.ENHANCING_FORCE_SELF, xi.effect.SHELL, 0, 100 }, + } + + if mob:hasStatusEffectByFlag(xi.effectFlag.ERASABLE) then + table.insert(spellList, #spellList + 1, { xi.magic.spell.ERASE, mob, true, xi.action.type.NONE, nil, 100 }) + end + + if target:hasStatusEffectByFlag(xi.effectFlag.DISPELABLE) then + table.insert(spellList, #spellList + 1, { xi.magic.spell.DISPELGA, target, false, xi.action.type.NONE, nil, 100 }) + end + + local groupTable = + { + GetMobByID(mob:getID() - 1), -- Parata + GetMobByID(mob:getID() + 1), -- Nepionic Parata + GetMobByID(mob:getID() + 2), -- Nepionic Parata + GetMobByID(mob:getID() + 3), -- Nepionic Parata + GetMobByID(mob:getID() + 4), -- Nepionic Bladmall + GetMobByID(mob:getID() + 5), -- Nepionic Bladmall + GetMobByID(mob:getID() + 6), -- Nepionic Bladmall + } + + return xi.combat.behavior.chooseAction(mob, target, groupTable, spellList) +end + return entity diff --git a/scripts/zones/Boneyard_Gully/mobs/Nepionic_Bladmall.lua b/scripts/zones/Boneyard_Gully/mobs/Nepionic_Bladmall.lua index 1309c308458..d6cf69a8b52 100644 --- a/scripts/zones/Boneyard_Gully/mobs/Nepionic_Bladmall.lua +++ b/scripts/zones/Boneyard_Gully/mobs/Nepionic_Bladmall.lua @@ -1,15 +1,44 @@ ----------------------------------- --- Area: Boneyard Gully --- Mob: Nepionic Bladmall --- ENM: Shell We Dance? +-- Area : Boneyard Gully +-- Mob : Nepionic Bladmall +-- ENM : Shell We Dance? +-- NOTE : These Uragnites do not go into their shell ----------------------------------- ---@type TMobEntity local entity = {} +----------------------------------- +-- onMobInitialize +----------------------------------- +entity.onMobInitialize = function(mob) + mob:setBehavior(xi.behavior.STANDBACK) +end + +----------------------------------- +-- onMobSpawn +----------------------------------- entity.onMobSpawn = function(mob) + mob:setMobMod(xi.mobMod.MAGIC_COOL, 20) + mob:setMobMod(xi.mobMod.STANDBACK_COOL, 0) + mob:setMobMod(xi.mobMod.MAGIC_DELAY, math.random(3, 7)) end -entity.onMobDeath = function(mob, player, optParams) +----------------------------------- +-- Spell Selection +----------------------------------- +entity.onMobSpellChoose = function(mob, target, spellId) + local spellList = + { + [1] = { xi.magic.spell.WATER_III, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [2] = { xi.magic.spell.WATERGA_II, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [3] = { xi.magic.spell.CURE_IV, mob, false, xi.action.type.HEALING_TARGET, 50, 0, 100 }, + [4] = { xi.magic.spell.SLOWGA, target, false, xi.action.type.ENFEEBLING_TARGET, xi.effect.SLOW, 4, 100 }, + [5] = { xi.magic.spell.BLINDGA, target, false, xi.action.type.ENFEEBLING_TARGET, xi.effect.BLINDNESS, 0, 100 }, + [6] = { xi.magic.spell.PROTECT_IV, mob, false, xi.action.type.ENHANCING_FORCE_SELF, xi.effect.PROTECT, 0, 25 }, + [7] = { xi.magic.spell.SHELL_IV, mob, false, xi.action.type.ENHANCING_FORCE_SELF, xi.effect.SHELL, 0, 25 }, + } + + return xi.combat.behavior.chooseAction(mob, target, nil, spellList) end return entity diff --git a/scripts/zones/Boneyard_Gully/mobs/Nepionic_Parata.lua b/scripts/zones/Boneyard_Gully/mobs/Nepionic_Parata.lua index 980f5aa82e9..4fc5c1c4a6b 100644 --- a/scripts/zones/Boneyard_Gully/mobs/Nepionic_Parata.lua +++ b/scripts/zones/Boneyard_Gully/mobs/Nepionic_Parata.lua @@ -1,15 +1,18 @@ ----------------------------------- --- Area: Boneyard Gully --- Mob: Nepionic Parata --- ENM: Shell We Dance? +-- Area : Boneyard Gully +-- Mob : Nepionic Parata +-- ENM : Shell We Dance? +-- NOTE : These Uragnites do not go into their shell ----------------------------------- ---@type TMobEntity local entity = {} +----------------------------------- +-- onMobSpawn +----------------------------------- entity.onMobSpawn = function(mob) -end - -entity.onMobDeath = function(mob, player, optParams) + mob:setMod(xi.mod.REGAIN, 200) + mob:setMod(xi.mod.DOUBLE_ATTACK, 0) end return entity diff --git a/scripts/zones/Boneyard_Gully/mobs/Parata.lua b/scripts/zones/Boneyard_Gully/mobs/Parata.lua index 9463fc3e999..a67be130e30 100644 --- a/scripts/zones/Boneyard_Gully/mobs/Parata.lua +++ b/scripts/zones/Boneyard_Gully/mobs/Parata.lua @@ -1,64 +1,175 @@ ----------------------------------- --- Area: Boneyard Gully --- Mob: Parata --- ENM: Shell We Dance? +-- Area : Boneyard Gully +-- Mob : Parata +-- ENM : Shell We Dance? +-- NOTE : This Uragnite does not heal when going into its' shell. It should not use the Uragnite mixin. ----------------------------------- ---@type TMobEntity local entity = {} +----------------------------------- +-- Enter/Exit Shell functions +----------------------------------- +local function enterShell(mob) + mob:setAnimationSub(1) + mob:setAutoAttackEnabled(false) + mob:setMod(xi.mod.UDMGPHYS, -7500) + mob:setMod(xi.mod.UDMGRANGE, -7500) + mob:setMod(xi.mod.UDMGMAGIC, -7500) + mob:setMod(xi.mod.UDMGBREATH, -7500) + mob:setMobMod(xi.mobMod.NO_MOVE, 1) + mob:setLocalVar('shellExitTime', GetSystemTime() + math.random(50, 70)) + mob:useMobAbility(xi.mobSkill.VENOM_SHELL_1) +end + +local function exitShell(mob) + mob:setAnimationSub(0) + mob:setAutoAttackEnabled(true) + mob:setMod(xi.mod.UDMGPHYS, 0) + mob:setMod(xi.mod.UDMGRANGE, 0) + mob:setMod(xi.mod.UDMGMAGIC, 0) + mob:setMod(xi.mod.UDMGBREATH, 0) + mob:setMobMod(xi.mobMod.NO_MOVE, 0) +end + +----------------------------------- +-- Pet Setup +----------------------------------- +local petOffsets = { 2, 3, 4 } + +local callPetParams = +{ + dieWithOwner = true, -- Pets die when Parata dies. + ignoreBusy = true, + noAnimation = true, + maxSpawns = 1, +} +local petSpawnTable = +{ + { hpp = 75, minDelay = 45, maxDelay = 90 }, -- 1st pet summoned at 75% HP or 45-90 seconds after engage. + { hpp = 55, minDelay = 105, maxDelay = 150 }, -- 2nd pet summoned at 55% HP or 105-150 seconds after previous pet. + { hpp = 35, minDelay = 105, maxDelay = 150 }, -- 3rd pet summoned at 35% HP or 105-150 seconds after previous pet. +} + +----------------------------------- +-- onMobInitialize +----------------------------------- +entity.onMobInitialize = function(mob) + mob:addImmunity(xi.immunity.BIND) + mob:addImmunity(xi.immunity.BLIND) + mob:addImmunity(xi.immunity.GRAVITY) + mob:addImmunity(xi.immunity.PARALYZE) + mob:addImmunity(xi.immunity.SILENCE) + mob:addImmunity(xi.immunity.DARK_SLEEP) + mob:addImmunity(xi.immunity.LIGHT_SLEEP) + mob:addImmunity(xi.immunity.STUN) +end + +----------------------------------- +-- onMobSpawn +----------------------------------- entity.onMobSpawn = function(mob) + mob:setMod(xi.mod.REGAIN, 200) + mob:setMod(xi.mod.DOUBLE_ATTACK, 30) + mob:setLocalVar('petPhase', 1) + mob:setLocalVar('nextPetTime', 0) end -entity.onMobFight = function(mob, target) - local battlefield = mob:getBattlefield() - if not battlefield then +----------------------------------- +-- onMobFight +----------------------------------- +entity.onMobFight = function(mob) + if xi.combat.behavior.isEntityBusy(mob) then return end - local mobId = mob:getID() - local mobHPP = mob:getHPP() - local adds = mob:getLocalVar('adds') - local petId = 0 + local currentTime = GetSystemTime() - -- Pet #1 spawn at 95% hp or less - if mobHPP <= 95 and adds == 0 then - petId = mobId + 2 + ----------------------------------- + -- Check if it's time to exit shell + ----------------------------------- + if + mob:getAnimationSub() == 1 and + currentTime >= mob:getLocalVar('shellExitTime') + then + exitShell(mob) + end - -- Pet #2 spawn at 60% hp or less - elseif mobHPP <= 60 and adds == 1 then - petId = mobId + 3 + ----------------------------------- + -- Enrage at 15% HP or below + ----------------------------------- + if + mob:getHPP() <= 15 and + mob:getLocalVar('enrage') == 0 + then + mob:setLocalVar('enrage', 1) + mob:injectActionPacket(mob:getID(), 11, 432, 0, 0x18, 0, 0, 0) + mob:setMod(xi.mod.REGAIN, 500) + mob:setMobMod(xi.mobMod.BASE_DAMAGE_MULTIPLIER, 200) + end - -- Pet #3 spawn at 40% hp or less - elseif mobHPP <= 40 and adds == 2 then - petId = mobId + 4 + ----------------------------------- + -- If all our pets have spawned, nothing else to do here + ----------------------------------- + local phase = mob:getLocalVar('petPhase') + if phase > #petSpawnTable then + return end - -- If we have spawned a pet - if petId > 0 then - mob:setLocalVar('adds', adds + 1) + ----------------------------------- + -- Set up first pet timer/threshold on engage + ----------------------------------- + if + mob:getLocalVar('nextPetTime') == 0 and + phase == 1 + then + mob:setLocalVar('nextPetTime', currentTime + math.random(petSpawnTable[1].minDelay, petSpawnTable[1].maxDelay)) + return + end - local pet = SpawnMob(petId) - if pet then - battlefield:insertEntity(pet:getTargID(), false, true) - pet:updateEnmity(target) + ----------------------------------- + -- Check to see if it's time to spawn a pet either via HP threshold or timer + ----------------------------------- + if + petSpawnTable[phase] and + (mob:getHPP() <= petSpawnTable[phase].hpp or + currentTime >= mob:getLocalVar('nextPetTime')) + then + enterShell(mob) - local pos = mob:getPos() - pet:setPos(pos.x, pos.y, pos.z, pos.rot) + local pets = {} + for _, offset in ipairs(petOffsets) do + table.insert(pets, mob:getID() + offset) end - end -end -entity.onMobDeath = function(mob, player, optParams) - -- Kill adds. - if optParams.isKiller or optParams.noKiller then - local mobId = mob:getID() - for i = 2, 4 do - local pet = GetMobByID(mobId + i) - if pet and pet:isAlive() then - pet:setHP(0) + if xi.mob.callPets(mob, pets, callPetParams) then + phase = phase + 1 + mob:setLocalVar('petPhase', phase) + + if petSpawnTable[phase] then + mob:setLocalVar('nextPetTime', currentTime + math.random(petSpawnTable[phase].minDelay, petSpawnTable[phase].maxDelay)) end end end end +----------------------------------- +-- TP Moves - If in shell, use Venom Shell, otherwise, select from other skills +----------------------------------- +entity.onMobMobskillChoose = function(mob, target) + if mob:getAnimationSub() == 1 then + return xi.mobSkill.VENOM_SHELL_1 + end + + local skillList = + { + xi.mobSkill.GAS_SHELL_1, + xi.mobSkill.PALSYNYXIS_1, + xi.mobSkill.PAINFUL_WHIP_1, + xi.mobSkill.SUCTORIAL_TENTACLE_1, + } + + return skillList[math.random(1, #skillList)] +end + return entity diff --git a/sql/mob_groups.sql b/sql/mob_groups.sql index dd3a603363f..4c451ec7f5b 100644 --- a/sql/mob_groups.sql +++ b/sql/mob_groups.sql @@ -354,10 +354,10 @@ INSERT INTO `mob_groups` VALUES (7,3827,8,'Swift_Hunter',0,128,0,5000,0,80,80,0) INSERT INTO `mob_groups` VALUES (8,3613,8,'Shrewd_Hunter',0,128,0,5000,0,80,80,0); INSERT INTO `mob_groups` VALUES (9,247,8,'Armored_Hunter',0,128,0,5000,0,80,80,0); INSERT INTO `mob_groups` VALUES (10,3301,8,'Race_Runner',0,128,0,7000,2000,75,75,0); -INSERT INTO `mob_groups` VALUES (11,3099,8,'Parata',0,128,0,0,0,80,80,0); -INSERT INTO `mob_groups` VALUES (12,444,8,'Bladmall',0,128,0,0,0,80,80,0); -INSERT INTO `mob_groups` VALUES (13,2833,8,'Nepionic_Parata',0,128,0,0,0,73,73,0); -INSERT INTO `mob_groups` VALUES (14,2832,8,'Nepionic_Bladmall',0,128,0,0,0,73,73,0); +INSERT INTO `mob_groups` VALUES (11,3099,8,'Parata',0,128,0,9500,0,80,80,0); +INSERT INTO `mob_groups` VALUES (12,444,8,'Bladmall',0,128,0,5000,5000,80,80,0); +INSERT INTO `mob_groups` VALUES (13,2833,8,'Nepionic_Parata',0,128,0,2500,0,73,73,0); +INSERT INTO `mob_groups` VALUES (14,2832,8,'Nepionic_Bladmall',0,128,0,2100,2100,73,73,0); INSERT INTO `mob_groups` VALUES (15,1860,8,'Gwyn_Ap_Knudd',0,128,0,0,0,75,75,0); INSERT INTO `mob_groups` VALUES (16,598,8,'Cadaver_Warrior',0,128,0,0,0,75,75,0); INSERT INTO `mob_groups` VALUES (17,599,8,'Cadaver_Witch',0,128,0,0,0,75,75,0); diff --git a/sql/mob_pools.sql b/sql/mob_pools.sql index 03b93630dbb..364ed0f9ffa 100644 --- a/sql/mob_pools.sql +++ b/sql/mob_pools.sql @@ -499,7 +499,7 @@ INSERT INTO `mob_pools` VALUES (440,'Black_Triple_Stars','Black_Triple_Stars',47 INSERT INTO `mob_pools` VALUES (441,'Black_Wolf','Black_Wolf',143,0x00006C0100000000000000000000000000000000,1,1,3,240,100,0,1,0,0,0,0,0,186,129,0,0,0,0,0,143,143,0,21); INSERT INTO `mob_pools` VALUES (442,'Blademaw_Pugil','Blademaw_Pugil',197,0x00005C0100000000000000000000000000000000,1,1,8,240,100,0,1,0,1,0,0,0,0,129,0,0,0,0,0,197,197,0,23); INSERT INTO `mob_pools` VALUES (443,'Blade_Bat','Blade_Bat',46,0x0000000100000000000000000000000000000000,1,1,11,240,100,0,1,0,0,0,0,0,322,641,8,0,0,0,0,46,46,0,11); -INSERT INTO `mob_pools` VALUES (444,'Bladmall','Bladmall',251,0x0000510500000000000000000000000000000000,4,3,7,290,100,0,1,1,1,16,0,0,494,133,0,0,433,0,0,251,251,2,13); +INSERT INTO `mob_pools` VALUES (444,'Bladmall','Bladmall',251,0x0000510500000000000000000000000000000000,3,4,7,240,100,0,1,1,1,16,0,0,494,133,0,0,433,0,0,251,251,2,13); INSERT INTO `mob_pools` VALUES (445,'Blanched_Kraken','Blanched_Kraken',218,0x0000610100000000000000000000000000000000,2,2,7,360,100,0,1,0,0,4,0,0,0,131,0,0,0,0,0,218,218,NULL,NULL); INSERT INTO `mob_pools` VALUES (446,'Blanga','Blanga',118,0x0000B10800000000000000000000000000000000,1,6,3,240,100,0,1,0,0,2,0,0,7,157,0,0,0,0,0,957,117,2,13); INSERT INTO `mob_pools` VALUES (447,'Blazer_Beetle','Blazer_Beetle',49,0x0000980100000000000000000000000000000000,7,7,8,240,100,0,1,0,1,0,0,0,497,131,0,0,0,0,0,49,49,1,12); @@ -2887,8 +2887,8 @@ INSERT INTO `mob_pools` VALUES (2828,'Nephiyl_Keepcollapser','Nephiyl_Keepcollap INSERT INTO `mob_pools` VALUES (2829,'Nephiyl_Moatfiller','Nephiyl_Moatfiller',126,0x0000800200000000000000000000000000000000,9,9,5,240,100,0,1,1,1,18,0,0,3663,135,0,0,0,0,0,126,126,3,41); INSERT INTO `mob_pools` VALUES (2830,'Nephiyl_Pinnacletosser','Nephiyl_Pinnacletosser',126,0x0000C30200000000000000000000000000000000,11,11,11,240,100,0,1,1,1,18,0,0,8137,131,0,0,0,0,0,126,126,1,30); INSERT INTO `mob_pools` VALUES (2831,'Nephiyl_Rampartbreacher','Nephiyl_Rampartbreacher',126,0x0000BF0200000000000000000000000000000000,1,1,5,240,100,0,1,1,1,18,0,0,4216,131,0,0,0,0,0,126,126,1,30); -INSERT INTO `mob_pools` VALUES (2832,'Nepionic_Bladmall','Nepionic_Bladmall',251,0x0000510500000000000000000000000000000000,3,3,7,290,100,0,1,1,1,16,0,0,3253,129,0,0,434,0,0,251,251,0,10); -INSERT INTO `mob_pools` VALUES (2833,'Nepionic_Parata','Nepionic_Parata',251,0x0000510500000000000000000000000000000000,1,1,7,290,100,0,1,1,1,16,0,0,1247,129,0,0,0,0,0,251,251,0,10); +INSERT INTO `mob_pools` VALUES (2832,'Nepionic_Bladmall','Nepionic_Bladmall',251,0x0000510500000000000000000000000000000000,3,3,7,210,100,0,1,1,1,16,0,0,3253,129,0,0,434,0,0,251,251,0,10); +INSERT INTO `mob_pools` VALUES (2833,'Nepionic_Parata','Nepionic_Parata',251,0x0000510500000000000000000000000000000000,1,1,7,210,100,0,1,1,1,16,0,0,1247,129,0,0,0,0,0,251,251,0,10); INSERT INTO `mob_pools` VALUES (2834,'Nepionic_Soulflayer','Nepionic_Soulflayer',233,0x0000EF0600000000000000000000000000000000,4,4,5,240,100,0,1,1,1,2,0,0,0,131,4,0,460,0,0,234,233,1,17); INSERT INTO `mob_pools` VALUES (2835,'Nest_Beetle','Nest_Beetle',49,0x0000980100000000000000000000000000000000,7,7,8,240,100,0,0,0,1,0,0,0,344,129,0,0,0,0,0,49,49,0,11); INSERT INTO `mob_pools` VALUES (2836,'Nguruvilu','Nguruvilu',198,0x0000D00600000000000000000000000000000000,1,4,6,240,100,0,0,0,0,2,0,0,0,0,0,0,0,0,0,823,198,NULL,NULL); @@ -3154,7 +3154,7 @@ INSERT INTO `mob_pools` VALUES (3095,'Panzer_Percival','Panzer_Percival',49,0x00 INSERT INTO `mob_pools` VALUES (3096,'Papako','Papako',179,0x0000920100000000000000000000000000000000,1,1,0,0,100,0,0,0,0,0,0,32,0,2201,8,0,0,24,0,179,179,NULL,NULL); INSERT INTO `mob_pools` VALUES (3097,'Para','Para',116,0x0000780100000000000000000000000000000000,1,1,11,240,100,0,1,0,0,2,0,0,0,3,0,0,0,0,0,116,116,NULL,NULL); INSERT INTO `mob_pools` VALUES (3098,'Paralyzing_Tube_GS','Paralyzing_Tube',247,0x0000000700000000000000000000000000000000,1,1,7,240,100,0,1,1,0,0,0,0,7,129,8,0,0,0,0,247,247,0,10); -INSERT INTO `mob_pools` VALUES (3099,'Parata','Parata',251,0x0000510500000000000000000000000000000000,1,1,7,290,100,0,1,1,1,16,0,0,8150,645,0,0,0,0,0,251,251,2,13); +INSERT INTO `mob_pools` VALUES (3099,'Parata','Parata',251,0x0000510500000000000000000000000000000000,1,1,7,240,100,0,1,1,1,16,0,0,8150,645,0,0,0,0,0,251,251,2,13); INSERT INTO `mob_pools` VALUES (3100,'Pardus','Pardus',242,0x0000C80800000000000000000000000000000000,4,4,12,240,100,0,1,1,0,18,0,0,7,129,0,0,2,0,0,242,242,0,22); INSERT INTO `mob_pools` VALUES (3101,'Pascerpot','Pascerpot',79,0x00008D0100000000000000000000000000000000,3,3,11,240,100,0,0,0,0,2,0,32,0,157,0,0,254,0,0,79,79,2,17); INSERT INTO `mob_pools` VALUES (3102,'Passage_Crab','Passage_Crab',77,0x0000640100000000000000000000000000000000,7,7,4,240,100,0,1,0,0,4,0,0,1,129,8,0,0,0,0,77,77,1,13); diff --git a/sql/mob_skill_lists.sql b/sql/mob_skill_lists.sql index 8508371cc24..40fdc3d8a04 100644 --- a/sql/mob_skill_lists.sql +++ b/sql/mob_skill_lists.sql @@ -1069,11 +1069,11 @@ INSERT INTO `mob_skill_lists` VALUES ('ArmoredTroll',247,1898); INSERT INTO `mob_skill_lists` VALUES ('ArmoredTroll',247,1899); INSERT INTO `mob_skill_lists` VALUES ('Pyuu_the_Spatemaker',248,770); -- Jumping Thrust INSERT INTO `mob_skill_lists` VALUES ('Bayawak',249,367); -- Fireball -INSERT INTO `mob_skill_lists` VALUES ('Uragnite_shell',250,1571); -- gas_shell -INSERT INTO `mob_skill_lists` VALUES ('Uragnite_shell',250,1572); -- venom_shell -INSERT INTO `mob_skill_lists` VALUES ('Uragnite',251,1573); -- palsynyxis -INSERT INTO `mob_skill_lists` VALUES ('Uragnite',251,1574); -- painful_whip -INSERT INTO `mob_skill_lists` VALUES ('Uragnite',251,1575); -- suctorial_tentacle +INSERT INTO `mob_skill_lists` VALUES ('Uragnite_shell',250,505); -- venom_shell +INSERT INTO `mob_skill_lists` VALUES ('Uragnite',251,504); -- gas_shell +INSERT INTO `mob_skill_lists` VALUES ('Uragnite',251,506); -- palsynyxis +INSERT INTO `mob_skill_lists` VALUES ('Uragnite',251,507); -- painful_whip +INSERT INTO `mob_skill_lists` VALUES ('Uragnite',251,508); -- suctorial_tentacle INSERT INTO `mob_skill_lists` VALUES ('Vampyr',252,2106); -- bloodrake INSERT INTO `mob_skill_lists` VALUES ('Vampyr',252,2107); -- decollation INSERT INTO `mob_skill_lists` VALUES ('Vampyr',252,2108); -- nosferatus_kiss diff --git a/sql/mob_skills.sql b/sql/mob_skills.sql index 803edc58904..6a3fb22a576 100644 --- a/sql/mob_skills.sql +++ b/sql/mob_skills.sql @@ -528,11 +528,11 @@ INSERT INTO `mob_skills` VALUES (500,853,'mow',1,0.0,15.0,2000,1500,4,0,0,0,0,0, INSERT INTO `mob_skills` VALUES (501,854,'frightful_roar',1,0.0,15.0,2000,1500,4,0,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (502,855,'mortal_ray',0,0.0,10.0,2000,2000,4,0,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (503,856,'unblessed_armor',0,0.0,7.0,2000,1500,1,0,0,0,0,0,0); --- INSERT INTO `mob_skills` VALUES (504,861,'gas_shell',0,0.0,7.0,2000,1500,4,0,0,0,0,0,0); --- INSERT INTO `mob_skills` VALUES (505,862,'venom_shell',0,0.0,7.0,2000,1500,4,0,0,0,0,0,0); --- INSERT INTO `mob_skills` VALUES (506,863,'palsynyxis',0,0.0,7.0,2000,1500,4,0,0,0,0,0,0); --- INSERT INTO `mob_skills` VALUES (507,864,'painful_whip',0,0.0,7.0,2000,1500,4,0,0,0,0,0,0); --- INSERT INTO `mob_skills` VALUES (508,865,'suctorial_tentacle',0,0.0,7.0,2000,1500,4,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (504,861,'gas_shell',1,0.0,15.0,2000,2000,4,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (505,862,'venom_shell',1,0.0,15.0,2000,0,4,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (506,863,'palsynyxis',0,0.0,7.0,2000,1600,4,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (507,864,'painful_whip',0,0.0,7.0,2000,1200,4,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (508,865,'suctorial_tentacle',0,0.0,7.0,2000,800,4,0,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (509,253,'self-destruct_bomb',1,0.0,20.0,2000,1500,4,0,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (510,254,'berserk',0,0.0,7.0,2000,1500,1,0,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (511,253,'self-destruct_bomb_321',1,0.0,30.0,0,0,4,0,0,0,0,0,0);