From 87ea21db25eb00a15140c3830c963be36cd3e1d5 Mon Sep 17 00:00:00 2001 From: ThrisStraizo <45871917+ThrisStraizo@users.noreply.github.com> Date: Tue, 5 May 2026 15:01:16 -0700 Subject: [PATCH] Return to the Depths Fight This PR implements the fight mechanics for Return to the Depths. --- scripts/enum/mob_skill.lua | 6 + .../Mine_Shaft_2716/mobs/Moblin_Clergyman.lua | 47 +++++ .../Mine_Shaft_2716/mobs/Moblin_Wisewoman.lua | 47 +++++ .../zones/Mine_Shaft_2716/mobs/Twilotak.lua | 178 ++++++++++++++++++ sql/mob_groups.sql | 6 +- sql/mob_pools.sql | 2 +- sql/mob_skills.sql | 24 +-- 7 files changed, 294 insertions(+), 16 deletions(-) create mode 100644 scripts/zones/Mine_Shaft_2716/mobs/Moblin_Clergyman.lua create mode 100644 scripts/zones/Mine_Shaft_2716/mobs/Moblin_Wisewoman.lua create mode 100644 scripts/zones/Mine_Shaft_2716/mobs/Twilotak.lua diff --git a/scripts/enum/mob_skill.lua b/scripts/enum/mob_skill.lua index 35e110a4e9b..43048928534 100644 --- a/scripts/enum/mob_skill.lua +++ b/scripts/enum/mob_skill.lua @@ -550,6 +550,12 @@ xi.mobSkill = FRYPAN_1 = 1081, SMOKEBOMB_1 = 1082, + SMOKEBOMB_2 = 1083, + CRISPY_CANDLE_1 = 1084, + CRISPY_CANDLE_2 = 1085, + PARALYSIS_SHOWER_1 = 1086, + PARALYSIS_SHOWER_2 = 1087, + GOBLIN_RUSH_2 = 1088, -- EES_? = 1091, diff --git a/scripts/zones/Mine_Shaft_2716/mobs/Moblin_Clergyman.lua b/scripts/zones/Mine_Shaft_2716/mobs/Moblin_Clergyman.lua new file mode 100644 index 00000000000..8f214a09e28 --- /dev/null +++ b/scripts/zones/Mine_Shaft_2716/mobs/Moblin_Clergyman.lua @@ -0,0 +1,47 @@ +----------------------------------- +-- Area: Mine Shaft 2716 +-- Return to the Depths: Bastok Quest: 1 79 +-- NM: Twilotak +----------------------------------- +---@type TMobEntity +local entity = {} + +entity.onMobInitialize = function(mob) + mob:addImmunity(xi.immunity.DARK_SLEEP) + mob:addImmunity(xi.immunity.LIGHT_SLEEP) + mob:addImmunity(xi.immunity.GRAVITY) + mob:addImmunity(xi.immunity.BIND) + mob:addImmunity(xi.immunity.TERROR) + mob:addImmunity(xi.immunity.PLAGUE) + mob:addImmunity(xi.immunity.SILENCE) + + mob:addListener('MAGIC_STATE_EXIT', 'MAGIC_EMOTE', function(mobArg, spell) + mobArg:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_3) + end) +end + +entity.onMobSpawn = function(mob) + mob:setMobMod(xi.mobMod.MAGIC_COOL, 240) + mob:setAutoAttackEnabled(false) + mob:setMagicCastingEnabled(false) + mob:setMobAbilityEnabled(false) + mob:setMobMod(xi.mobMod.NO_MOVE, 1) +end + +entity.onMobEngage = function(mob, target) + mob:setMagicCastingEnabled(true) +end + +-- TODO: Change casting logic to only target Twilotak and random players +entity.onMobSpellChoose = function(mob, target, spell) + local spellList = + { + xi.magic.spell.CURE_IV, + xi.magic.spell.HOLY, + xi.magic.spell.PROTECT_III, + } + + return spellList[math.random(1, #spellList)] +end + +return entity diff --git a/scripts/zones/Mine_Shaft_2716/mobs/Moblin_Wisewoman.lua b/scripts/zones/Mine_Shaft_2716/mobs/Moblin_Wisewoman.lua new file mode 100644 index 00000000000..09a57c6da38 --- /dev/null +++ b/scripts/zones/Mine_Shaft_2716/mobs/Moblin_Wisewoman.lua @@ -0,0 +1,47 @@ +----------------------------------- +-- Area: Mine Shaft 2716 +-- Return to the Depths: Bastok Quest: 1 79 +-- NM: Twilotak +----------------------------------- +---@type TMobEntity +local entity = {} + +entity.onMobInitialize = function(mob) + mob:addImmunity(xi.immunity.DARK_SLEEP) + mob:addImmunity(xi.immunity.LIGHT_SLEEP) + mob:addImmunity(xi.immunity.GRAVITY) + mob:addImmunity(xi.immunity.BIND) + mob:addImmunity(xi.immunity.TERROR) + mob:addImmunity(xi.immunity.PLAGUE) + mob:addImmunity(xi.immunity.SILENCE) + + mob:addListener('MAGIC_STATE_EXIT', 'MAGIC_EMOTE', function(mobArg, spell) + mobArg:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_3) + end) +end + +entity.onMobSpawn = function(mob) + mob:setMobMod(xi.mobMod.MAGIC_COOL, 240) + mob:setAutoAttackEnabled(false) + mob:setMagicCastingEnabled(false) + mob:setMobAbilityEnabled(false) + mob:setMobMod(xi.mobMod.NO_MOVE, 1) +end + +entity.onMobEngage = function(mob, target) + mob:setMagicCastingEnabled(true) +end + +-- TODO: Change casting logic to only target Twilotak and random players +entity.onMobSpellChoose = function(mob, target, spell) + local spellList = + { + xi.magic.spell.HASTE, + xi.magic.spell.SLEEP_II, + xi.magic.spell.DISPEL, + } + + return spellList[math.random(1, #spellList)] +end + +return entity diff --git a/scripts/zones/Mine_Shaft_2716/mobs/Twilotak.lua b/scripts/zones/Mine_Shaft_2716/mobs/Twilotak.lua new file mode 100644 index 00000000000..e85d342d611 --- /dev/null +++ b/scripts/zones/Mine_Shaft_2716/mobs/Twilotak.lua @@ -0,0 +1,178 @@ +----------------------------------- +-- Area: Mine Shaft 2716 +-- Return to the Depths: Bastok Quest: 1 79 +-- NM: Twilotak +----------------------------------- +---@type TMobEntity +local entity = {} + +local arenaCenters = +{ + [1] = { x = -459.000, y = 122.032, z = 20.504 }, + [2] = { x = 20.014, y = 2.032, z = 19.936 }, + [3] = { x = 500.000, y = -117.967, z = 19.961 }, +} + +----------------------------------- +-- Draw In Handler +----------------------------------- +local function handleDrawIn(mob, target, battlefield) + -- Early return: No battlefield. + if not battlefield then + return + end + + -- Early return: No center. + local center = arenaCenters[battlefield:getArea()] + if not center then + return + end + + -- Early return: Distance from center check & first wisewoman alive check. + -- Once the wisewoman on the left is killed, players will no longer be drawn in + -- TODO: Additional research on draw in mechanics. It's possible that each add is responsible for draw in on a different player. + if + target:checkDistance(center.x, center.y, center.z) <= 15 or + GetMobByID(mob:getID() + 1):isDead() + then + return + end + + local drawInPosition = + { + x = center.x, + y = center.y, + z = center.z + 3.0, + rot = 194, + } + + ----------------------------------- + -- Draw in all players to the draw in position, skip players already within 15 yalms + ----------------------------------- + for _, player in pairs(battlefield:getPlayers()) do + local distanceFromDrawIn = player:checkDistance(drawInPosition.x, drawInPosition.y, drawInPosition.z) + if distanceFromDrawIn > 15 then + mob:drawIn(player, 0, 0, drawInPosition) + end + end +end + +entity.onMobInitialize = function(mob) + mob:addImmunity(xi.immunity.DARK_SLEEP) + mob:addImmunity(xi.immunity.LIGHT_SLEEP) + mob:addImmunity(xi.immunity.GRAVITY) + mob:addImmunity(xi.immunity.BIND) + mob:addImmunity(xi.immunity.TERROR) + mob:addImmunity(xi.immunity.PLAGUE) + mob:addImmunity(xi.immunity.SILENCE) + + mob:addListener('MAGIC_STATE_EXIT', 'MAGIC_EMOTE', function(mobArg, spell) + mobArg:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_3) + local mobID = mob:getID() + for i = 1, 6 do + local nextMob = GetMobByID(mobID + i) + if nextMob and nextMob:isAlive() then + nextMob:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_2) + end + end + end) + + mob:addListener('EFFECT_LOSE', 'BLOOD_WEAPON_EFFECT_LOSE', function(mobArg, effect) + if effect:getEffectType() == xi.effect.BLOOD_WEAPON then + mob:setMagicCastingEnabled(true) + mobArg:setMod(xi.mod.DELAYP, 0) + mobArg:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_3) + local mobID = mob:getID() + for i = 1, 6 do + local nextMob = GetMobByID(mobID + i) + if nextMob and nextMob:isAlive() then + nextMob:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_2) + end + end + end + end) + + mob:addListener('WEAPONSKILL_STATE_EXIT', 'EMOTE_TIME', function(mobArg, skillId, wasExecuted) + if + skillId == xi.mobSkill.FRYPAN_1 or + skillId == xi.mobSkill.SMOKEBOMB_2 or + skillId == xi.mobSkill.CRISPY_CANDLE_2 or + skillId == xi.mobSkill.PARALYSIS_SHOWER_2 + then + mobArg:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_1) + local mobID = mob:getID() + for i = 1, 6 do + local nextMob = GetMobByID(mobID + i) + if nextMob and nextMob:isAlive() then + nextMob:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_4) + end + end + end + + if + skillId == xi.mobSkill.GOBLIN_RUSH_2 or + skillId == xi.mobSkill.SMOKEBOMB_1 or + skillId == xi.mobSkill.CRISPY_CANDLE_1 or + skillId == xi.mobSkill.PARALYSIS_SHOWER_1 + then + mobArg:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_3) + local mobID = mob:getID() + for i = 1, 6 do + local nextMob = GetMobByID(mobID + i) + if nextMob and nextMob:isAlive() then + nextMob:useMobAbility(xi.mobSkill.MOBLIN_EMOTE_2) + end + end + end + end) +end + +entity.onMobSpawn = function(mob) + mob:setLocalVar('[2hour]HPP', math.random(75, 85)) + mob:setLocalVar('[2hour]Used', 0) + mob:setMobMod(xi.mobMod.BASE_DAMAGE_MULTIPLIER, 150) +end + +entity.onMobFight = function(mob, target) + -- Check for Draw In + local battlefield = mob:getBattlefield() + if not battlefield then + return + end + + handleDrawIn(mob, target, battlefield) + + local currentTime = GetSystemTime() + -- Handle 2 Hour + if + mob:getLocalVar('[2hour]Used') == 0 and + mob:getHPP() < mob:getLocalVar('[2hour]HPP') + then + mob:setLocalVar('[2hour]Used', 1) + mob:setMagicCastingEnabled(false) + mob:useMobAbility(xi.mobSkill.BLOOD_WEAPON_1) + mob:setLocalVar('twoHourTime', currentTime + math.random(120, 180)) + return + end + + if mob:getLocalVar('twoHourTime') == currentTime then + mob:setLocalVar('[2hour]Used', 0) + end +end + +entity.onMobWeaponSkill = function(mob, target, skill, action) + if skill:getID() == xi.mobSkill.BLOOD_WEAPON_1 then + mob:setMod(xi.mod.DELAYP, -25) + end +end + +entity.onMobDeath = function(mob, player, optParams) + local battlefield = mob:getBattlefield() + if not battlefield then + return + end + + battlefield:win() +end + +return entity diff --git a/sql/mob_groups.sql b/sql/mob_groups.sql index c2d2ca6fbe2..6eade33f8c8 100644 --- a/sql/mob_groups.sql +++ b/sql/mob_groups.sql @@ -551,9 +551,9 @@ INSERT INTO `mob_groups` VALUES (2,707,13,'Chekochuk',0,128,0,2200,0,0,NULL); INSERT INTO `mob_groups` VALUES (3,4005,13,'Trikotrak',0,128,0,2300,0,0,NULL); INSERT INTO `mob_groups` VALUES (4,3828,13,'Swipostik',0,128,0,2400,0,0,NULL); INSERT INTO `mob_groups` VALUES (5,559,13,'Bugbby',0,128,0,9000,0,0,NULL); -INSERT INTO `mob_groups` VALUES (6,4057,13,'Twilotak',0,128,0,0,0,0,NULL); -INSERT INTO `mob_groups` VALUES (7,2707,13,'Moblin_Wisewoman',0,128,0,0,0,0,NULL); -INSERT INTO `mob_groups` VALUES (8,2688,13,'Moblin_Clergyman',0,128,0,0,0,0,NULL); +INSERT INTO `mob_groups` VALUES (6,4057,13,'Twilotak',0,128,0,5000,3500,0,NULL); +INSERT INTO `mob_groups` VALUES (7,2707,13,'Moblin_Wisewoman',0,128,0,2100,2500,0,NULL); +INSERT INTO `mob_groups` VALUES (8,2688,13,'Moblin_Clergyman',0,128,0,2100,2500,0,NULL); INSERT INTO `mob_groups` VALUES (9,569,13,'Bugboy',0,128,0,19500,0,0,NULL); INSERT INTO `mob_groups` VALUES (10,2693,13,'Moblin_Fantocciniman',0,128,0,3800,0,0,NULL); INSERT INTO `mob_groups` VALUES (11,1296,13,'Fantoccini',0,128,0,0,0,0,NULL); diff --git a/sql/mob_pools.sql b/sql/mob_pools.sql index 66c106356cf..eab089d6bb4 100644 --- a/sql/mob_pools.sql +++ b/sql/mob_pools.sql @@ -4113,7 +4113,7 @@ INSERT INTO `mob_pools` VALUES (4053,'Tunnel_Worm','Tunnel_Worm',258,0x0000A8010 INSERT INTO `mob_pools` VALUES (4054,'Turul','Turul',6,0x0000AE0800000000000000000000000000000000,4,5,12,240,100,0,1,1,0,2,0,34,1,2199,5,0,174,0,1024,807,6,3,55); INSERT INTO `mob_pools` VALUES (4055,'Tusked_Tigon','Tusked_Tigon',242,0x0000340100000000000000000000000000000000,1,1,7,240,100,0,1,0,1,0,0,0,0,129,0,0,0,0,0,242,242,0,22); INSERT INTO `mob_pools` VALUES (4056,'Tuskertrap','Tuskertrap',114,0x0000410500000000000000000000000000000000,1,1,6,240,100,0,0,0,0,2,0,0,0,133,8,0,0,0,0,114,114,2,13); -INSERT INTO `mob_pools` VALUES (4057,'Twilotak','Twilotak',184,0x0000B90200000000000000000000000000000000,8,8,5,240,100,0,1,0,1,16,0,32,6,159,0,0,5,0,0,184,184,3,25); +INSERT INTO `mob_pools` VALUES (4057,'Twilotak','Twilotak',184,0x0000B90200000000000000000000000000000000,8,1,5,180,100,0,1,0,1,16,0,32,6,159,0,0,5,0,0,184,184,3,25); INSERT INTO `mob_pools` VALUES (4058,'Two-faced_Flan','Two-faced_Flan',112,0x0000070700000000000000000000000000000000,4,4,12,240,100,0,1,1,0,18,0,0,0,3,0,0,507,0,0,416,112,1,12); INSERT INTO `mob_pools` VALUES (4059,'Two_of_Batons','Two_of_Batons',61,0x0000AF0100000000000000000000000000000000,4,4,12,240,100,0,1,0,1,0,0,0,165,129,0,0,2,0,0,61,61,0,10); INSERT INTO `mob_pools` VALUES (4060,'Two_of_Coins','Two_of_Coins',61,0x0000AF0100000000000000000000000000000000,5,5,11,240,100,0,1,0,1,0,0,0,270,129,8,0,3,0,0,61,61,0,10); diff --git a/sql/mob_skills.sql b/sql/mob_skills.sql index 9a2487a0c74..26155016558 100644 --- a/sql/mob_skills.sql +++ b/sql/mob_skills.sql @@ -1109,14 +1109,14 @@ INSERT INTO `mob_skills` VALUES (1077,357,'shell_bash',0,0.0,7.0,2000,1000,4,0,0 INSERT INTO `mob_skills` VALUES (1078,358,'shell_guard',0,0.0,7.0,2000,3000,1,0,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (1079,354,'howl',1,0.0,20.0,2000,1500,1,0,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (1080,742,'the_wrath_of_gudha',1,0.0,15.0,2000,2000,4,0,0,7,0,0,0); -INSERT INTO `mob_skills` VALUES (1081,743,'frypan',1,0.0,10.0,2000,1500,4,0,0,0,0,0,0); -INSERT INTO `mob_skills` VALUES (1082,744,'smokebomb',4,0.0,10.0,2000,1500,4,0,0,0,0,0,0); -INSERT INTO `mob_skills` VALUES (1083,745,'smokebomb',0,0.0,10.0,2000,1500,1,0,0,0,0,0,0); -- fail -INSERT INTO `mob_skills` VALUES (1084,746,'crispy_candle',4,0.0,10.0,2000,1500,4,0,0,0,0,0,0); -INSERT INTO `mob_skills` VALUES (1085,747,'crispy_candle_self',0,0.0,10.0,2000,1500,1,0,0,0,0,0,0); -- fail -INSERT INTO `mob_skills` VALUES (1086,748,'paralysis_shower',4,0.0,10.0,2000,1500,4,0,0,0,0,0,0); -INSERT INTO `mob_skills` VALUES (1087,749,'paralysis_shower',0,0.0,10.0,2000,1500,1,0,0,0,0,0,0); -- fail -INSERT INTO `mob_skills` VALUES (1088,334,'goblin_rush',0,0.0,7.0,2000,1500,4,0,0,1,0,0,0); +INSERT INTO `mob_skills` VALUES (1081,743,'frypan',1,0.0,10.0,2500,2800,4,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (1082,744,'smokebomb',4,0.0,10.0,3900,2000,4,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (1083,745,'smokebomb',0,0.0,10.0,4200,2000,1,0,0,0,0,0,0); -- fail +INSERT INTO `mob_skills` VALUES (1084,746,'crispy_candle',4,0.0,10.0,3900,2000,4,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (1085,747,'crispy_candle_self',0,0.0,10.0,4200,2000,1,0,0,0,0,0,0); -- fail +INSERT INTO `mob_skills` VALUES (1086,748,'paralysis_shower',4,0.0,10.0,3900,2000,4,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (1087,749,'paralysis_shower',0,0.0,10.0,4200,2000,1,0,0,0,0,0,0); -- fail +INSERT INTO `mob_skills` VALUES (1088,334,'goblin_rush',0,0.0,7.0,2500,1000,4,0,0,1,0,0,0); -- INSERT INTO `mob_skills` VALUES (1089,335,'bomb_toss',0,0.0,7.0,2000,1500,4,0,0,0,0,0,0); -- INSERT INTO `mob_skills` VALUES (1090,834,'bomb_toss',0,0.0,7.0,2000,1500,4,0,0,0,0,0,0); -- INSERT INTO `mob_skills` VALUES (1091,19,'eagle_eye_shot',0,0.0,7.0,2000,1500,4,2,0,0,0,0,0); @@ -1371,10 +1371,10 @@ INSERT INTO `mob_skills` VALUES (1339,220,'bane',1,0.0,15.0,2000,1500,4,0,0,0,0, INSERT INTO `mob_skills` VALUES (1340,17,'crossthrash',4,0.0,14.0,2000,1500,4,0,0,5,0,0,0); INSERT INTO `mob_skills` VALUES (1341,993,'knife_edge_circle',4,0.0,7.0,2000,1500,4,0,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (1342,992,'train_fall',0,0.0,7.0,2000,1500,4,0,0,0,0,0,0); -INSERT INTO `mob_skills` VALUES (1343,994,'moblin_emote_1',0,0.0,7.0,2000,0,1,0,0,0,0,0,0); -INSERT INTO `mob_skills` VALUES (1344,995,'moblin_emote_2',0,0.0,7.0,2000,0,1,0,0,0,0,0,0); -INSERT INTO `mob_skills` VALUES (1345,996,'moblin_emote_3',0,0.0,7.0,2000,0,1,0,0,0,0,0,0); -INSERT INTO `mob_skills` VALUES (1346,997,'moblin_emote_4',0,0.0,7.0,2000,0,1,0,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (1343,994,'moblin_emote_1',0,0.0,7.0,2000,0,1,4,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (1344,995,'moblin_emote_2',0,0.0,7.0,2000,0,1,4,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (1345,996,'moblin_emote_3',0,0.0,7.0,2000,0,1,4,0,0,0,0,0); +INSERT INTO `mob_skills` VALUES (1346,997,'moblin_emote_4',0,0.0,7.0,2000,0,1,4,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (1347,998,'dual_strike',0,0.0,7.0,2000,1000,4,0,0,0,0,0,0); INSERT INTO `mob_skills` VALUES (1348,999,'siphon_discharge',4,0.0,15.0,2000,1000,4,0,0,1,0,0,0); INSERT INTO `mob_skills` VALUES (1349,1000,'mantle_pierce',0,0.0,7.0,2000,1000,4,0,0,3,0,0,0);