From f759c3d29425b45dd824d02570ed581942993639 Mon Sep 17 00:00:00 2001 From: Skold177 <113406182+Skold177@users.noreply.github.com> Date: Fri, 8 May 2026 14:01:57 -0400 Subject: [PATCH] [lua] Royal Jelly Refactor Cleans up the Royal Jelly code and fixes a bug where the last jelly alive could become permanently immortal --- .../Waughroon_Shrine/mobs/Princess_Jelly.lua | 197 +++++++++--------- sql/mob_spawn_points.sql | 6 +- 2 files changed, 99 insertions(+), 104 deletions(-) diff --git a/scripts/zones/Waughroon_Shrine/mobs/Princess_Jelly.lua b/scripts/zones/Waughroon_Shrine/mobs/Princess_Jelly.lua index 89358433375..897d440f28a 100644 --- a/scripts/zones/Waughroon_Shrine/mobs/Princess_Jelly.lua +++ b/scripts/zones/Waughroon_Shrine/mobs/Princess_Jelly.lua @@ -3,12 +3,12 @@ -- Mob: Princess Jelly -- BCNM: Royal Jelly ----------------------------------- -local waughroonID = zones[xi.zone.WAUGHROON_SHRINE] +local ID = zones[xi.zone.WAUGHROON_SHRINE] ----------------------------------- ---@type TMobEntity local entity = {} -local centers = +local battlefieldCenters = { { -177.5, 60, -142 }, { 22.5, 0, 18 }, @@ -31,6 +31,11 @@ entity.onMobSpawn = function(mob) return end + mob:setLocalVar('reachedCenter', 0) + battlefield:setLocalVar('jelliesInCenter', 0) + battlefield:setLocalVar('jelliesAlive', 8) + battlefield:setLocalVar('queenSpawned', 0) + local elementBitmask = battlefield:getLocalVar('elementChosen') -- Build table with available elements. @@ -56,136 +61,126 @@ entity.onMobSpawn = function(mob) mob:addMod(xi.data.element.getElementalAbsorptionModifier(chosenElement), 1000) end -local function getQueenJellyID(bfNum) - return waughroonID.mob.QUEEN_JELLY + (bfNum - 1) * 10 -end - -local function getDistanceFromCenter(bfNum, mob) +----------------------------------- +-- Returns the distance of the mob from the center of the battlefield. +----------------------------------- +local function getDistanceFromCenter(battlefieldArea, mob) local pos = mob:getPos() - local difX = pos.x - centers[bfNum][1] - local difY = pos.y - centers[bfNum][2] - local difZ = pos.z - centers[bfNum][3] + local difX = pos.x - battlefieldCenters[battlefieldArea][1] + local difY = pos.y - battlefieldCenters[battlefieldArea][2] + local difZ = pos.z - battlefieldCenters[battlefieldArea][3] return math.sqrt(math.pow(difX, 2) + math.pow(difY, 2) + math.pow(difZ, 2)) end -local function allJellysInCenter(bfNum, zone) - local totalMobsAlive = 0 - local totalInCenter = 0 - for i = 1, 8 do - local princess = GetMobByID(getQueenJellyID(bfNum) + i) - if getDistanceFromCenter(bfNum, princess) <= 0.5 then - totalInCenter = totalInCenter + 1 - end - - if princess and princess:isAlive() then - totalMobsAlive = totalMobsAlive + 1 - end - end +entity.onMobFight = function(mob, target) + local battlefield = mob:getBattlefield() - if totalMobsAlive == 0 then - -- Win condition - return false + if not battlefield then + return end - return totalMobsAlive == totalInCenter -end + local battlefieldArea = battlefield:getArea() + local jelliesInCenter = battlefield:getLocalVar('jelliesInCenter') + local jelliesAlive = battlefield:getLocalVar('jelliesAlive') -local function princessesTotalHP(bfNum, zone) - local totalHP = 0 - - for i = 1, 8 do - local princess = GetMobByID(getQueenJellyID(bfNum) + i) - if princess and princess:isAlive() then - totalHP = totalHP + princess:getHP() - end + if not battlefieldArea then + return end - return totalHP -end + local battlefieldCenter = battlefieldCenters[battlefieldArea] -local function spawnQueenJelly(bfNum, target, zone) - local queen = GetMobByID(getQueenJellyID(bfNum)) + if not battlefieldCenter then + return + end - if queen and not queen:isSpawned() then - SpawnMob(queen:getID()) - queen:setMaxHP(princessesTotalHP(bfNum, zone)) - queen:setHP(princessesTotalHP(bfNum, zone)) - queen:setPos(centers[bfNum][1], centers[bfNum][2], centers[bfNum][3], 0) - queen:setLocalVar('target', target:getID()) + -- On first combat tick, begin pathing to the center + if not mob:isFollowingPath() then + mob:pathThrough(battlefieldCenter, xi.path.flag.SCRIPT) + end - for i = 1, 8 do - DespawnMob(queen:getID() + i) - end + -- Jellies become invulnerable in the center + if + getDistanceFromCenter(battlefieldArea, mob) <= 0.2 and + mob:getLocalVar('reachedCenter') == 0 + then + mob:setMod(xi.mod.UDMGPHYS, -10000) + mob:setMod(xi.mod.UDMGRANGE, -10000) + mob:setMod(xi.mod.UDMGMAGIC, -10000) + mob:setMod(xi.mod.UDMGBREATH, -10000) + mob:setLocalVar('reachedCenter', 1) + jelliesInCenter = jelliesInCenter + 1 + battlefield:setLocalVar('jelliesInCenter', jelliesInCenter) end -end -entity.onMobSpellChoose = function(mob, target, spellId) - local spellTable = - { - [xi.element.FIRE ] = { xi.magic.spell.BIND, xi.magic.spell.BURN, xi.magic.spell.FIRE }, - [xi.element.ICE ] = { xi.magic.spell.BIND, xi.magic.spell.FROST, xi.magic.spell.BLIZZARD }, - [xi.element.WIND ] = { xi.magic.spell.BIND, xi.magic.spell.CHOKE, xi.magic.spell.AERO }, - [xi.element.EARTH ] = { xi.magic.spell.BIND, xi.magic.spell.RASP , xi.magic.spell.STONE }, - [xi.element.THUNDER] = { xi.magic.spell.BIND, xi.magic.spell.SHOCK, xi.magic.spell.THUNDER }, - [xi.element.WATER ] = { xi.magic.spell.BIND, xi.magic.spell.DROWN, xi.magic.spell.WATER }, - [xi.element.LIGHT ] = { xi.magic.spell.BIND, xi.magic.spell.DIA, xi.magic.spell.BANISH }, - [xi.element.DARK ] = { xi.magic.spell.BIND, xi.magic.spell.BIO, xi.magic.spell.DRAIN }, - } - - local list = mob:getLocalVar('mobElement') - list = list > 0 and list or 1 - local spellList = spellTable[list] + -- If the amount of Princess Jellies alive doesn't equal the amount in center, return. + if + jelliesAlive == 0 or + jelliesAlive ~= jelliesInCenter + then + return + end - return spellList[math.random(1, #spellList)] -end + -- If we make it here, spawn the Queen Jelly + if battlefield:getLocalVar('queenSpawned') == 0 then + battlefield:setLocalVar('queenSpawned', 1) + local queenHP = 0 + local queenJellyID = ID.mob.QUEEN_JELLY + (battlefieldArea - 1) * 10 + local queenJelly = GetMobByID(queenJellyID) -entity.onMobFight = function(mob, target) - local bfNum = mob:getBattlefield():getArea() - local queen = GetMobByID(getQueenJellyID(bfNum)) - local center = centers[bfNum] + if not queenJelly then + return + end - mob:pathThrough(center, xi.path.flag.SCRIPT) + for i = 1, 8 do + local princessJelly = GetMobByID(queenJellyID + i) - -- Jellies become invulnerable in the center - if getDistanceFromCenter(bfNum, mob) <= 0.2 then - mob:setMod(xi.mod.UDMGPHYS, -10000) - mob:setMod(xi.mod.UDMGMAGIC, -10000) - end + if not princessJelly then + return + end - -- When all the jellies are in the center, spawn the queen - if getDistanceFromCenter(bfNum, mob) <= 0.2 then - if - queen and - not queen:isSpawned() and - allJellysInCenter(bfNum, mob:getZone()) - then - spawnQueenJelly(bfNum, target, mob:getZone()) + if princessJelly:isAlive() then + queenHP = queenHP + princessJelly:getHP() + DespawnMob(princessJelly:getID()) + end end - end - if mob:checkDistance(target) >= 20 then - mob:setMagicCastingEnabled(false) - else - mob:setMagicCastingEnabled(true) + SpawnMob(queenJellyID) + queenJelly:setMaxHP(queenHP) + queenJelly:setHP(queenJelly:getMaxHP()) end end -entity.onMobEngage = function(mob, target) - -- battlefield has superlink +local spellTable = +{ + [xi.element.FIRE ] = { xi.magic.spell.BIND, xi.magic.spell.BURN, xi.magic.spell.FIRE }, + [xi.element.ICE ] = { xi.magic.spell.BIND, xi.magic.spell.FROST, xi.magic.spell.BLIZZARD }, + [xi.element.WIND ] = { xi.magic.spell.BIND, xi.magic.spell.CHOKE, xi.magic.spell.AERO }, + [xi.element.EARTH ] = { xi.magic.spell.BIND, xi.magic.spell.RASP , xi.magic.spell.STONE }, + [xi.element.THUNDER] = { xi.magic.spell.BIND, xi.magic.spell.SHOCK, xi.magic.spell.THUNDER }, + [xi.element.WATER ] = { xi.magic.spell.BIND, xi.magic.spell.DROWN, xi.magic.spell.WATER }, + [xi.element.LIGHT ] = { xi.magic.spell.BIND, xi.magic.spell.DIA, xi.magic.spell.BANISH }, + [xi.element.DARK ] = { xi.magic.spell.BIND, xi.magic.spell.BIO, xi.magic.spell.DRAIN }, +} + +entity.onMobSpellChoose = function(mob, target, spellId) + local mobElement = mob:getLocalVar('mobElement') + local spellList = spellTable[mobElement] or spellTable[xi.element.FIRE] + + return spellList[math.random(1, #spellList)] end entity.onMobDeath = function(mob, player, optParams) - local bfNum = mob:getBattlefield():getArea() - local queen = GetMobByID(getQueenJellyID(bfNum)) + if optParams.isKiller or optParams.noKiller then + local battlefield = mob:getBattlefield() - if - queen and - not queen:isSpawned() and - allJellysInCenter(bfNum, mob:getZone()) - then - spawnQueenJelly(bfNum, player, mob:getZone()) + if not battlefield then + return + end + + local jelliesAlive = battlefield:getLocalVar('jelliesAlive') + battlefield:setLocalVar('jelliesAlive', jelliesAlive - 1) end end diff --git a/sql/mob_spawn_points.sql b/sql/mob_spawn_points.sql index 9b6e5fe8ebe..db84427a28f 100644 --- a/sql/mob_spawn_points.sql +++ b/sql/mob_spawn_points.sql @@ -52021,7 +52021,7 @@ INSERT INTO `mob_spawn_points` VALUES (17367170,0,'Flesh_Eater','Flesh Eater',23 INSERT INTO `mob_spawn_points` VALUES (17367171,0,'Flesh_Eater','Flesh Eater',23,38,40,228.647,-60.452,131.708,128); -- Royal Jelly -INSERT INTO `mob_spawn_points` VALUES (17367173,0,'Queen_Jelly','Queen Jelly',24,41,41,-172.000,60.000,-142.000,125); +INSERT INTO `mob_spawn_points` VALUES (17367173,0,'Queen_Jelly','Queen Jelly',24,41,41,-177.500,60.000,-142.000,125); INSERT INTO `mob_spawn_points` VALUES (17367174,0,'Princess_Jelly','Princess Jelly',25,35,35,-193.000,58.000,-130.000,20); INSERT INTO `mob_spawn_points` VALUES (17367175,0,'Princess_Jelly','Princess Jelly',25,35,35,-183.000,58.000,-125.000,40); INSERT INTO `mob_spawn_points` VALUES (17367176,0,'Princess_Jelly','Princess Jelly',25,35,35,-172.000,58.000,-124.000,65); @@ -52030,7 +52030,7 @@ INSERT INTO `mob_spawn_points` VALUES (17367178,0,'Princess_Jelly','Princess Jel INSERT INTO `mob_spawn_points` VALUES (17367179,0,'Princess_Jelly','Princess Jelly',25,35,35,-183.000,58.000,-159.000,205); INSERT INTO `mob_spawn_points` VALUES (17367180,0,'Princess_Jelly','Princess Jelly',25,35,35,-172.000,58.000,-159.000,180); INSERT INTO `mob_spawn_points` VALUES (17367181,0,'Princess_Jelly','Princess Jelly',25,35,35,-160.000,58.000,-154.000,155); -INSERT INTO `mob_spawn_points` VALUES (17367183,0,'Queen_Jelly','Queen Jelly',24,41,41,28.274,0.000,17.964,125); +INSERT INTO `mob_spawn_points` VALUES (17367183,0,'Queen_Jelly','Queen Jelly',24,41,41,22.500,0.000,18.000,125); INSERT INTO `mob_spawn_points` VALUES (17367184,0,'Princess_Jelly','Princess Jelly',25,35,35,7.274,-2.000,29.964,20); INSERT INTO `mob_spawn_points` VALUES (17367185,0,'Princess_Jelly','Princess Jelly',25,35,35,17.274,-2.000,34.964,40); INSERT INTO `mob_spawn_points` VALUES (17367186,0,'Princess_Jelly','Princess Jelly',25,35,35,28.274,-2.000,35.964,65); @@ -52039,7 +52039,7 @@ INSERT INTO `mob_spawn_points` VALUES (17367188,0,'Princess_Jelly','Princess Jel INSERT INTO `mob_spawn_points` VALUES (17367189,0,'Princess_Jelly','Princess Jelly',25,35,35,17.274,-2.000,0.964,205); INSERT INTO `mob_spawn_points` VALUES (17367190,0,'Princess_Jelly','Princess Jelly',25,35,35,28.274,-2.000,0.964,180); INSERT INTO `mob_spawn_points` VALUES (17367191,0,'Princess_Jelly','Princess Jelly',25,35,35,40.274,-2.000,5.964,155); -INSERT INTO `mob_spawn_points` VALUES (17367193,0,'Queen_Jelly','Queen Jelly',24,41,41,228.224,-60.000,137.946,125); +INSERT INTO `mob_spawn_points` VALUES (17367193,0,'Queen_Jelly','Queen Jelly',24,41,41,222.500,-60.000,138.000,125); INSERT INTO `mob_spawn_points` VALUES (17367194,0,'Princess_Jelly','Princess Jelly',25,35,35,207.224,-62.000,149.946,20); INSERT INTO `mob_spawn_points` VALUES (17367195,0,'Princess_Jelly','Princess Jelly',25,35,35,217.224,-62.000,154.946,40); INSERT INTO `mob_spawn_points` VALUES (17367196,0,'Princess_Jelly','Princess Jelly',25,35,35,228.224,-62.000,155.946,65);