From 3db139c12070e3d3fcf8d8a6f0a3cde9a089f0fe Mon Sep 17 00:00:00 2001 From: Flibe-XI Date: Sat, 31 Jan 2026 23:53:09 -0500 Subject: [PATCH] fixed timed events in pirates chart, and npc animation --- scripts/globals/brigands_chart.lua | 34 ++++---- scripts/globals/pirates_chart.lua | 130 +++++++++++++++++++---------- sql/mob_pools.sql | 6 +- 3 files changed, 107 insertions(+), 63 deletions(-) diff --git a/scripts/globals/brigands_chart.lua b/scripts/globals/brigands_chart.lua index db4c735e5c4..a306ae7dff6 100644 --- a/scripts/globals/brigands_chart.lua +++ b/scripts/globals/brigands_chart.lua @@ -72,33 +72,35 @@ local eventTable = { time = 180, text = ID.text.WHAT_CAN_I_DO + 5 }, } -local function tryHumeText(spawner, elapsedTime, timerTable) - if not timerTable then +local function tryHumeText(spawner, elapsedTime, timerTable, phase) + if + not timerTable or + not phase or + phase > #timerTable + then return end local npcHume = GetNPCByID(ID.npc.BRIGAND_CHART_HUME) local qm1 = GetNPCByID(ID.npc.BRIGAND_CHART_QM) - local event = timerTable[1] + local event = timerTable[phase] if not (qm1 and npcHume and event) then return end if elapsedTime < event.time then - return timerTable + return phase end if event.text then spawner:showText(qm1, event.text) end - table.remove(timerTable, 1) - - return timerTable + return phase + 1 end -local function emoteChecking(npc, spawner, timeRemaining, timeOfLastCheck, endTime, timerTable) +local function emoteChecking(npc, spawner, timeRemaining, timeOfLastCheck, endTime, timerTable, phase) -- Event continues if player leaves zone -- https://www.youtube.com/watch?v=_opqVW-HIu0 -- https://discord.com/channels/443544205206355968/446401624102010901/650072608922009660 @@ -108,11 +110,11 @@ local function emoteChecking(npc, spawner, timeRemaining, timeOfLastCheck, endTi timeRemaining = timeRemaining - timeElapsedThisCheck local totalTimeElapsed = 180 - timeRemaining - timerTable = tryHumeText(spawner, totalTimeElapsed, timerTable) + phase = tryHumeText(spawner, totalTimeElapsed, timerTable, phase) if timeRemaining > 0 then npc:timer(1000, function(npcArg) - emoteChecking(npcArg, spawner, timeRemaining, timeOfCurrentCheck, endTime, timerTable) + emoteChecking(npcArg, spawner, timeRemaining, timeOfCurrentCheck, endTime, timerTable, phase) end) else resetEvent() @@ -162,18 +164,18 @@ xi.brigandsChart.onEventFinish = function(player, csid, option, npc) npcHume:setStatus(xi.status.NORMAL) npcHume:setAnimation(xi.animation.NONE) npc:setStatus(xi.status.DISAPPEAR) - - player:showText(npc, ID.text.MY_ITEM, xi.item.PENGUIN_RING) - shimmering:setStatus(xi.status.NORMAL) + -- Appearing packet needs time to finish before another packet can be sent successfully - npc:timer(2000, function() - shimmering:entityAnimationPacket(xi.animationString.SHIMMER) + shimmering:timer(2000, function(shimmerArg) + shimmerArg:entityAnimationPacket(xi.animationString.SHIMMER) end) + player:showText(npc, ID.text.MY_ITEM, xi.item.PENGUIN_RING) + -- Events will occur for the next 180 seconds according to eventTable local endTime = GetSystemTime() + 180 - emoteChecking(npc, player, 180, GetSystemTime(), endTime, eventTable) + emoteChecking(npc, player, 180, GetSystemTime(), endTime, eventTable, 1) -- TODO: add fishing hook to catch chests & monster specific to event end end diff --git a/scripts/globals/pirates_chart.lua b/scripts/globals/pirates_chart.lua index 6c7a154bbe5..0242cecb96c 100644 --- a/scripts/globals/pirates_chart.lua +++ b/scripts/globals/pirates_chart.lua @@ -64,21 +64,27 @@ local function removeFromConfrontation(player) player:changeMusic(3, 102) end -local function resetEvent() - local qm4 = GetNPCByID(valkID.npc.PIRATE_CHART_QM) - local panicTaru = GetNPCByID(valkID.npc.PIRATE_CHART_TARU) - local shimmering = GetNPCByID(valkID.npc.SHIMMERING_POINT) - - if qm4 then - for i = 1, 3 do - local member = GetPlayerByID(qm4:getLocalVar('pChartMemberID_' .. i)) +local function resetEvent(members) + local qm4 = GetNPCByID(valkID.npc.PIRATE_CHART_QM) + local panicTaru = GetNPCByID(valkID.npc.PIRATE_CHART_TARU) + local shimmering = GetNPCByID(valkID.npc.SHIMMERING_POINT) + local barnacledBox = GetNPCByID(valkID.npc.BARNACLED_BOX) + + if members then + for _, member in ipairs(members) do removeFromConfrontation(member) end + end + if qm4 then qm4:resetLocalVars() qm4:setStatus(xi.status.NORMAL) end + if barnacledBox then + barnacledBox:resetLocalVars() + end + if panicTaru then panicTaru:setStatus(xi.status.DISAPPEAR) panicTaru:setAnimation(xi.animation.NONE) @@ -91,29 +97,33 @@ end local eventTable = { - { time = 1000, text = valkID.text.RIGHT_OVER_THERE_POINT + 0, emote = xi.emote.POINT, animationString = nil }, - { time = 20000, text = valkID.text.RIGHT_OVER_THERE_POINT + 1, emote = xi.emote.PANIC, animationString = nil }, - { time = 30000, text = valkID.text.RIGHT_OVER_THERE_POINT + 2, emote = xi.emote.PANIC, animationString = nil }, - { time = 40000, text = valkID.text.RIGHT_OVER_THERE_POINT + 3, emote = xi.emote.PANIC, animationString = nil }, - { time = 45000, text = valkID.text.RIGHT_OVER_THERE_POINT + 4, emote = nil, animationString = nil }, - { time = 46000, text = valkID.text.RIGHT_OVER_THERE_POINT + 5, emote = nil, animationString = xi.animationString.EFFECT_DEATH }, + { time = 1, text = valkID.text.RIGHT_OVER_THERE_POINT + 0, emote = xi.emote.POINT, animationString = nil }, + { time = 20, text = valkID.text.RIGHT_OVER_THERE_POINT + 1, emote = xi.emote.PANIC, animationString = nil }, + { time = 30, text = valkID.text.RIGHT_OVER_THERE_POINT + 2, emote = xi.emote.PANIC, animationString = nil }, + { time = 40, text = valkID.text.RIGHT_OVER_THERE_POINT + 3, emote = xi.emote.PANIC, animationString = nil }, + { time = 45, text = valkID.text.RIGHT_OVER_THERE_POINT + 4, emote = nil, animationString = nil }, + { time = 46, text = valkID.text.RIGHT_OVER_THERE_POINT + 5, emote = nil, animationString = xi.animationString.EFFECT_DEATH }, } -local function tryTaruEmote(elapsedTime_ms, timerTable) - if not timerTable then +local function tryTaruEmote(elapsedTime, timerTable, phase) + if + not timerTable or + not phase or + phase > #timerTable + then return end local panicTaru = GetNPCByID(valkID.npc.PIRATE_CHART_TARU) local qm4 = GetNPCByID(valkID.npc.PIRATE_CHART_QM) - local event = timerTable[1] + local event = timerTable[phase] if not (qm4 and panicTaru and event) then return end - if elapsedTime_ms < event.time then - return timerTable + if elapsedTime < event.time then + return phase end if event.text then @@ -132,44 +142,42 @@ local function tryTaruEmote(elapsedTime_ms, timerTable) panicTaru:entityAnimationPacket(event.animationString) end - table.remove(timerTable, 1) - - return timerTable + return phase + 1 end -local function rangeChecking(npc, spawner, timeToMobSpawn, timeOfLastCheck, wasInRangeLastCheck, timeOutOfRangeLastMsg, timerTable) +local function rangeChecking(npc, spawner, timeToMobSpawn, timeOfLastCheck, wasInRangeLastCheck, timeOutOfRangeLastMsg, timerTable, phase) if eventIsNotValid(npc) then - resetEvent() + resetEvent(spawner:getParty()) return false end local timeOfCurrentCheck = GetSystemTime() - local timeElapsedThisCheck = (timeOfCurrentCheck - timeOfLastCheck) * 1000 - local totalTimeElapsed = 50000 - timeToMobSpawn + local timeElapsedThisCheck = timeOfCurrentCheck - timeOfLastCheck + local totalTimeElapsed = 50 - timeToMobSpawn local isInRange = true local timeOutOfRange = 0 - timerTable = tryTaruEmote(totalTimeElapsed, timerTable) + phase = tryTaruEmote(totalTimeElapsed, timerTable, phase) if spawner:checkDistance(npc) > 10 then isInRange = false timeOutOfRange = timeOutOfRangeLastMsg - timeElapsedThisCheck - if wasInRangeLastCheck or (timeOutOfRange > 5000) then + if wasInRangeLastCheck or (timeOutOfRange > 5) then spawner:messageSpecial(valkID.text.NO_LONGER_FEEL_CHILL) timeOutOfRange = 0 end end - if timeToMobSpawn > 1000 then + if timeToMobSpawn > 0 then npc:timer(1000, function(npcArg) - rangeChecking(npcArg, spawner, timeToMobSpawn - timeElapsedThisCheck, timeOfCurrentCheck, isInRange, timeOutOfRange, timerTable) + rangeChecking(npcArg, spawner, timeToMobSpawn - timeElapsedThisCheck, timeOfCurrentCheck, isInRange, timeOutOfRange, timerTable, phase) end) elseif spawner:checkDistance(npc) > 10 or not spawner:isAlive() then - resetEvent() + resetEvent(spawner:getParty()) else local panicTaru = GetNPCByID(valkID.npc.PIRATE_CHART_TARU) local shimmering = GetNPCByID(valkID.npc.SHIMMERING_POINT) @@ -209,6 +217,20 @@ local function rangeChecking(npc, spawner, timeToMobSpawn, timeOfLastCheck, wasI end xi.piratesChart.onTrade = function(player, npc, trade) + local barnacledBox = GetNPCByID(valkID.npc.BARNACLED_BOX) + if + barnacledBox and + barnacledBox:getStatus() == xi.status.NORMAL + then + return + end + + for _, member in ipairs(player:getParty()) do + if member:hasStatusEffect(xi.effect.LEVEL_RESTRICTION) then + return + end + end + if player:getPartySize() > 3 then player:messageSpecial(valkID.text.TOO_MANY_IN_PARTY, 3) elseif player:checkSoloPartyAlliance() == 2 then @@ -224,7 +246,11 @@ end xi.piratesChart.onEventUpdate = function(player, csid, option, npc) if csid == 14 and option == 0 then - player:confirmTrade() + local barnacledBox = GetNPCByID(valkID.npc.BARNACLED_BOX) + if not barnacledBox then + printf('[error] Barnacled Box npc not found') + return + end local party = player:getParty() @@ -232,7 +258,10 @@ xi.piratesChart.onEventUpdate = function(player, csid, option, npc) return end + player:confirmTrade() + npc:setLocalVar('pChartSpawnerID', player:getID()) + barnacledBox:setLocalVar('pChartSpawnerID', player:getID()) -- Change music for party and remove buffs/temp items for idx, member in ipairs(party) do @@ -267,17 +296,22 @@ xi.piratesChart.onEventFinish = function(player, csid, option, npc) -- Setup starting conditions panicTaru:setStatus(xi.status.NORMAL) panicTaru:setAnimation(xi.animation.NONE) - shimmering:setStatus(xi.status.NORMAL) npc:setStatus(xi.status.DISAPPEAR) + shimmering:setStatus(xi.status.NORMAL) + + -- Appearing packet needs time to finish before another packet can be sent successfully + shimmering:timer(2000, function(shimmerArg) + shimmerArg:entityAnimationPacket(xi.animationString.SHIMMER) + end) -- Events will occur for the next 50 seconds according to eventTable -- confrontation will start when timer hits 0 and player still -- meets all required criteria - rangeChecking(npc, player, 50000, GetSystemTime(), true, 0, eventTable) + rangeChecking(npc, player, 50, GetSystemTime(), true, 0, eventTable, 1) end end -local function myBuddiesAreDead(mob) +xi.piratesChart.myBuddiesAreDead = function(mob) local mobID = mob:getID() for _, buddyID in ipairs(barnacleBuddyIDs) do local buddy = GetMobByID(buddyID) @@ -320,7 +354,7 @@ xi.piratesChart.onMobDeath = function(mob, player, optParams) return end - if myBuddiesAreDead(mob) then + if xi.piratesChart.myBuddiesAreDead(mob) then -- Player beat all three bad guys, get treasure chest to appear on this one local barnacledBox = GetNPCByID(valkID.npc.BARNACLED_BOX) @@ -332,6 +366,18 @@ xi.piratesChart.onMobDeath = function(mob, player, optParams) barnacledBox:setStatus(xi.status.NORMAL) barnacledBox:setLocalVar('open', 0) mob:setLocalVar('spawnedChest', 1) + barnacledBox:timer(180000, function(npcArg) + local spawnerID = barnacledBox:getLocalVar('pChartSpawnerID') + local spawner = GetPlayerByID(spawnerID) + + npcArg:setStatus(xi.status.DISAPPEAR) + + if spawner then + resetEvent(spawner:getParty()) + else + resetEvent() + end + end) end end @@ -381,17 +427,13 @@ local pChartLoot = } xi.piratesChart.barnacledBoxOnTrigger = function(player, npc) - local qm4 = GetNPCByID(valkID.npc.PIRATE_CHART_QM) - - if qm4 then - local spawnerID = qm4:getLocalVar('pChartSpawnerID') + local spawnerID = npc:getLocalVar('pChartSpawnerID') - if player:getID() ~= spawnerID then - return - end + if player:getID() ~= spawnerID then + return end - resetEvent() + resetEvent(player:getParty()) -- Distribute rewards if npc:getLocalVar(xi.animationString.OPEN_CRATE_GLOW) == 0 then diff --git a/sql/mob_pools.sql b/sql/mob_pools.sql index 282923f7cfc..83abd39b23f 100644 --- a/sql/mob_pools.sql +++ b/sql/mob_pools.sql @@ -434,7 +434,7 @@ INSERT INTO `mob_pools` VALUES (375,'Baumesel','Baumesel',114,0x0000410500000000 INSERT INTO `mob_pools` VALUES (376,'Bavarois','Bavarois',229,0x0000240100000000000000000000000000000000,1,1,7,240,100,0,1,0,0,4,0,0,0,3,0,0,0,0,0,229,229,NULL,NULL); INSERT INTO `mob_pools` VALUES (377,'BaTho_Mercifulheart','BaTho_Mercifulheart',202,0x00004C0800000000000000000000000000000000,8,8,2,245,100,0,1,0,1,2,0,0,0,0,0,0,5,0,0,202,202,NULL,NULL); INSERT INTO `mob_pools` VALUES (378,'Beach_Bunny','Beach_Bunny',206,0x00000C0100000000000000000000000000000000,6,6,7,240,100,0,0,0,1,0,0,0,339,133,0,0,0,0,0,206,206,2,14); -INSERT INTO `mob_pools` VALUES (379,'Beach_Monk','Beach_Monk',218,0x0000600100000000000000000000000000000000,2,2,7,360,100,0,1,0,0,0,0,0,51,129,0,0,0,0,0,218,218,0,15); +INSERT INTO `mob_pools` VALUES (379,'Beach_Monk','Beach_Monk',218,0x0000600100000000000000000000000000000000,2,2,7,360,100,0,1,0,0,34,0,0,51,129,0,0,0,0,0,218,218,0,15); INSERT INTO `mob_pools` VALUES (380,'Beach_Pugil','Beach_Pugil',197,0x00005C0100000000000000000000000000000000,1,1,7,240,100,0,0,0,1,0,0,0,0,131,0,0,0,0,0,197,197,1,27); INSERT INTO `mob_pools` VALUES (381,'Beadeaux_Vanguard','Beadeaux_Vanguard',202,0x00004E0800000000000000000000000000000000,7,7,3,265,100,0,1,0,1,0,0,0,0,129,0,0,4,0,0,202,202,0,12); INSERT INTO `mob_pools` VALUES (382,'Beady_Beetle','Beady_Beetle',49,0x0000980100000000000000000000000000000000,7,7,8,240,100,0,0,0,1,0,0,0,185,131,0,0,0,0,0,49,49,1,12); @@ -1970,7 +1970,7 @@ INSERT INTO `mob_pools` VALUES (1911,'Hecatomb_Hound','Hecatomb_Hound',143,0x000 INSERT INTO `mob_pools` VALUES (1912,'Hecteyes_RP','Hecteyes_RP',139,0x0000800100000000000000000000000000000000,4,4,12,280,100,0,1,0,0,0,0,0,260,1153,0,0,10,0,0,139,139,0,10); INSERT INTO `mob_pools` VALUES (1913,'Hedjedjet','Hedjedjet',217,0x00001C0100000000000000000000000000000000,1,8,6,240,100,0,0,0,0,2,0,32,1,671,8,0,263,0,0,941,217,3,39); INSERT INTO `mob_pools` VALUES (1914,'Hee_Mida_the_Meticulous','Hee_Mida_the_Meticulous',270,0x00003B0400000000000000000000000000000000,11,11,2,240,100,0,1,0,1,2,0,32,0,159,0,0,7,0,0,360,360,3,20); -INSERT INTO `mob_pools` VALUES (1915,'Heike_Crab','Heike_Crab',77,0x0000640100000000000000000000000000000000,7,7,4,240,100,0,0,0,0,2,0,0,51,1155,8,0,0,0,0,77,77,1,13); +INSERT INTO `mob_pools` VALUES (1915,'Heike_Crab','Heike_Crab',77,0x0000640100000000000000000000000000000000,7,7,4,240,100,0,1,0,0,34,0,0,51,1155,8,0,0,0,0,77,77,1,13); INSERT INTO `mob_pools` VALUES (1916,'Heithrun','Heithrun',167,0x0000550100000000000000000000000000000000,1,1,7,280,100,0,0,1,1,2,0,0,0,3,0,0,0,0,0,0,167,1,24); INSERT INTO `mob_pools` VALUES (1917,'Heliodor_Quadav','Heliodor_Quadav',202,0x00009A0200000000000000000000000000000000,4,4,5,265,100,0,1,0,1,0,0,0,518,1155,0,0,2,0,0,202,202,1,15); INSERT INTO `mob_pools` VALUES (1918,'Heliodromos','Heliodromos',141,0x0000550500000000000000000000000000000000,6,6,2,240,100,0,1,1,1,2,0,0,290,1157,0,0,0,0,0,141,141,2,13); @@ -2049,7 +2049,7 @@ INSERT INTO `mob_pools` VALUES (1990,'Hornfly','Hornfly',113,0x0000C001000000000 INSERT INTO `mob_pools` VALUES (1991,'Horrid_Fluke','Horrid_Fluke',172,0x0000140100000000000000000000000000000000,1,1,7,240,100,0,1,0,0,4,0,0,0,643,0,0,0,0,0,172,172,NULL,NULL); INSERT INTO `mob_pools` VALUES (1992,'Hotupuku','Hotupuku',58,0x0000470500000000000000000000000000000000,1,7,5,300,100,0,1,1,1,16,0,32,4828,1183,0,0,0,0,0,58,58,NULL,NULL); INSERT INTO `mob_pools` VALUES (1993,'Houndfly','Houndfly',113,0x0000C00100000000000000000000000000000000,1,1,8,240,100,0,1,0,1,16,0,0,1804,1665,0,0,0,0,0,374,374,0,12); -INSERT INTO `mob_pools` VALUES (1994,'Houu_the_Shoalwader','Houu_the_Shoalwader',213,0x0000130500000000000000000000000000000000,2,2,1,480,100,0,1,1,0,0,0,32,0,155,0,0,0,0,0,213,213,1,12); +INSERT INTO `mob_pools` VALUES (1994,'Houu_the_Shoalwader','Houu_the_Shoalwader',213,0x0000130500000000000000000000000000000000,2,2,1,480,100,0,1,0,0,34,0,32,0,155,0,0,0,0,0,213,213,1,12); INSERT INTO `mob_pools` VALUES (1995,'Hover_Tank','Hover_Tank',175,0x00009C0100000000000000000000000000000000,5,1,7,240,100,0,1,0,0,0,0,0,292,1155,0,0,36,0,0,175,175,1,37); INSERT INTO `mob_pools` VALUES (1996,'Hraesvelg','Hraesvelg',179,0x0000920100000000000000000000000000000000,1,1,7,360,100,0,1,1,1,18,0,0,0,3,0,0,0,0,0,179,179,2,36); INSERT INTO `mob_pools` VALUES (1997,'Hrani','Hrani',358,0x0000F00200000000000000000000000000000000,8,8,1,240,100,0,1,1,1,2,0,0,0,3,0,0,5,0,0,358,358,2,20);