From 04434dc6a60148bbb00a5bc642c30ab04a83ecd6 Mon Sep 17 00:00:00 2001 From: ThrisStraizo <45871917+ThrisStraizo@users.noreply.github.com> Date: Fri, 10 Apr 2026 19:52:03 -0700 Subject: [PATCH] Knocking on Forbidden Doors fight mechanics and adjustments This PR adjusts Alsha for more accurate fight behavior. --- scripts/enum/mob_skill.lua | 7 ++ .../Knocking_on_Forbidden_Doors.lua | 17 ++- .../mobs/Bullheaded_Grosvez.lua | 2 + scripts/zones/Misareaux_Coast/mobs/Alsha.lua | 112 +++++++++++++----- sql/mob_groups.sql | 2 +- sql/mob_pools.sql | 2 +- sql/mob_skills.sql | 6 +- sql/mob_spawn_points.sql | 2 +- 8 files changed, 111 insertions(+), 39 deletions(-) diff --git a/scripts/enum/mob_skill.lua b/scripts/enum/mob_skill.lua index 5aa5080251a..abdf957e620 100644 --- a/scripts/enum/mob_skill.lua +++ b/scripts/enum/mob_skill.lua @@ -42,6 +42,13 @@ xi.mobSkill = WHEELING_THRUST = 119, IMPULSE_DRIVE = 120, + SHINING_STRIKE_1 = 160, + SERAPH_STRIKE_1 = 161, + BRAINSHAKER_1 = 162, + + SKULLBREAKER_1 = 165, + TRUE_STRIKE_1 = 166, + RANDGRITH_1 = 170, NETHERSPIKES_1 = 241, diff --git a/scripts/quests/otherAreas/Knocking_on_Forbidden_Doors.lua b/scripts/quests/otherAreas/Knocking_on_Forbidden_Doors.lua index 7fde47804a7..20d596cfb2c 100644 --- a/scripts/quests/otherAreas/Knocking_on_Forbidden_Doors.lua +++ b/scripts/quests/otherAreas/Knocking_on_Forbidden_Doors.lua @@ -110,7 +110,10 @@ quest.sections = return quest:progressEvent(556, { [1] = xi.ki.MIRE_INCENSE }) -- Second time clicking on ??? - elseif progressVar == 3 then + elseif + progressVar == 3 and + not GetMobByID(misareauxID.mob.ALSHA):isSpawned() + then return quest:progressEvent(557, { [1] = xi.ki.MIRE_INCENSE }) -- Clicking on the ??? after killing NM @@ -123,8 +126,15 @@ quest.sections = ['Alsha'] = { onMobDeath = function(mob, player, optParams) - if quest:getVar(player, 'Prog') == 3 then - quest:setVar(player, 'Prog', 4) + -- Needs backend cpp changes to allow Alsha defeating herself to not allow credit. + if optParams.isKiller then + local alliance = player:getAlliance() + + for _, member in ipairs(alliance) do + if member:getCharVar('Quest[4][78]Prog') == 3 then + quest:setVar(player, 'Prog', 4) + end + end end end, }, @@ -146,6 +156,7 @@ quest.sections = [558] = function(player, csid, option, npc) quest:setVar(player, 'Prog', 5) + player:delKeyItem(xi.ki.MIRE_INCENSE) npcUtil.giveKeyItem(player, xi.ki.BETTER_HUMES_AND_MANNEQUINS) end, }, diff --git a/scripts/zones/Carpenters_Landing/mobs/Bullheaded_Grosvez.lua b/scripts/zones/Carpenters_Landing/mobs/Bullheaded_Grosvez.lua index 715a199b175..03350feb5b5 100644 --- a/scripts/zones/Carpenters_Landing/mobs/Bullheaded_Grosvez.lua +++ b/scripts/zones/Carpenters_Landing/mobs/Bullheaded_Grosvez.lua @@ -17,6 +17,8 @@ entity.onMobInitialize = function(mob) end entity.onMobSpawn = function(mob) + mob:setAutoAttackEnabled(true) + mob:addListener('EFFECT_LOSE', 'HUNDRED_FISTS_EFFECT_LOSE', function(mobArg, effect) if effect:getEffectType() == xi.effect.HUNDRED_FISTS then mobArg:messageText(mobArg, ID.text.CATCH_HIS_BREATH, false) diff --git a/scripts/zones/Misareaux_Coast/mobs/Alsha.lua b/scripts/zones/Misareaux_Coast/mobs/Alsha.lua index 064efb635de..c7abb46294f 100644 --- a/scripts/zones/Misareaux_Coast/mobs/Alsha.lua +++ b/scripts/zones/Misareaux_Coast/mobs/Alsha.lua @@ -8,46 +8,98 @@ local ID = zones[xi.zone.MISAREAUX_COAST] ---@type TMobEntity local entity = {} +entity.onMobInitialize = function(mob) + mob:addImmunity(xi.immunity.STUN) + mob:addImmunity(xi.immunity.LIGHT_SLEEP) + mob:addImmunity(xi.immunity.DARK_SLEEP) + mob:addImmunity(xi.immunity.PLAGUE) + mob:addImmunity(xi.immunity.TERROR) + mob:addImmunity(xi.immunity.SILENCE) + mob:setMobMod(xi.mobMod.MAGIC_COOL, 35) +end + entity.onMobSpawn = function(mob) - mob:setLocalVar('CureTime', GetSystemTime() + math.random(60, 180)) -- anywhere from every 1-3 minutes + mob:setLocalVar('CureTime', GetSystemTime() + math.random(45, 90)) + mob:setMobMod(xi.mobMod.SKIP_ALLEGIANCE_CHECK, 1) + mob:setMod(xi.mod.STORETP, 125) + mob:setMod(xi.mod.SPELLINTERRUPT, 100) + mob:setMobMod(xi.mobMod.NO_SPELL_COST, 0) + mob:setAutoAttackEnabled(true) + mob:setMagicCastingEnabled(true) + mob:setMobAbilityEnabled(true) end entity.onMobFight = function(mob, target) - -- Check to see if below 20% HPP, and set the 'final mode' active - if mob:getLocalVar('FinalPhase') ~= 1 and mob:getHPP() < 20 then - target:messageSpecial(ID.text.LARGE_DROPS_OF_OIL) + -- Evaluate battle phase. + local finalPhase = mob:getLocalVar('FinalPhase') + if + finalPhase ~= 1 and + (mob:getHPP() < 25 or mob:getLocalVar('CuresCasted') >= 3) + then mob:setLocalVar('FinalPhase', 1) - -- TODO: Uncomment these lines - -- Fix code below so that Alsha will cast Fire II on herself. Currently not possible without core changes. - --mob:setAutoAttackEnabled(false) - --mob:setMagicCastingEnabled(false) + mob:messageText(mob, ID.text.LARGE_DROPS_OF_OIL, false) + mob:setMobMod(xi.mobMod.NO_SPELL_COST, 1) + mob:setAutoAttackEnabled(false) + mob:setMagicCastingEnabled(false) + mob:setMobAbilityEnabled(false) end ---[[ - -- Queue up a Fire II on herself if FinalPhase is active - if mob:getLocalVar('FinalPhase') == 1 and mob:getLocalVar('Casting') ~= 1 then - mob:setLocalVar('Casting', 1) - mob:setMP(10000) -- Never will run out at this stage - mob:timer(6500, function(m) - m:setLocalVar('Casting', 0) - end) - -- mob:castSpell(145, mob) -- 145 = Fire II + + if xi.combat.behavior.isEntityBusy(mob) then + return end -]] - -- Occasionally cast Cure III on the target (never on herself) - if - mob:getLocalVar('FinalPhase') ~= 1 and - mob:getLocalVar('CureTime') <= GetSystemTime() - then - mob:setLocalVar('CureTime', GetSystemTime() + math.random(60, 180)) - target:messageSpecial(ID.text.DROP_OF_OIL) - mob:timer(1000, function(m) - m:castSpell(3, target) -- Cure III - end) + + -- Final phase behavior: Cast Fire II on itself. + if finalPhase == 1 then + mob:castSpell(xi.magic.spell.FIRE_II, mob) + return + end + + -- Regular behavior: Occasionally cast Cure III on oponent. + if mob:getLocalVar('CureTime') <= GetSystemTime() then + mob:messageText(mob, ID.text.DROP_OF_OIL, false) + mob:setLocalVar('CureTime', GetSystemTime() + math.random(30, 90)) + mob:setLocalVar('CuresCasted', mob:getLocalVar('CuresCasted') + 1) + mob:castSpell(xi.magic.spell.CURE_III, target) end end -entity.onMobDeath = function(mob, player, optParams) - -- TODO: Requires logic to ensure Alsha is killed by a player and not by herself. +entity.onMobMobskillChoose = function(mob, target, skillId) + local tpTable = + { + xi.mobSkill.SHINING_STRIKE_1, + xi.mobSkill.SERAPH_STRIKE_1, + xi.mobSkill.BRAINSHAKER_1, + xi.mobSkill.SKULLBREAKER_1, + xi.mobSkill.TRUE_STRIKE_1, + } + + return tpTable[math.random(1, #tpTable)] +end + +entity.onMobSpellChoose = function(mob, target, spellId) + local spellList = + { + [ 1] = { xi.magic.spell.AERO_II, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [ 2] = { xi.magic.spell.AEROGA_II, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [ 3] = { xi.magic.spell.BLIZZARD_II, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [ 4] = { xi.magic.spell.BLIZZAGA, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [ 5] = { xi.magic.spell.FIRE_II, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [ 6] = { xi.magic.spell.FIRAGA_II, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [ 7] = { xi.magic.spell.FREEZE, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [ 8] = { xi.magic.spell.PARALYZE, target, false, xi.action.type.ENFEEBLING_TARGET, xi.effect.PARALYSIS, 0, 100 }, + [ 9] = { xi.magic.spell.QUAKE, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [10] = { xi.magic.spell.SHOCK_SPIKES, mob, false, xi.action.type.ENHANCING_FORCE_SELF, xi.effect.SHOCK_SPIKES, 0, 100 }, + [11] = { xi.magic.spell.SILENCE, target, false, xi.action.type.ENFEEBLING_TARGET, xi.effect.SILENCE, 0, 100 }, + [12] = { xi.magic.spell.SLEEPGA_II, target, false, xi.action.type.ENFEEBLING_TARGET, xi.effect.SLEEP_II, 2, 100 }, + [13] = { xi.magic.spell.STONE_III, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [14] = { xi.magic.spell.STONEGA_II, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [15] = { xi.magic.spell.THUNDER_II, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [16] = { xi.magic.spell.THUNDAGA, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [17] = { xi.magic.spell.WATER_III, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + [18] = { xi.magic.spell.WATERGA_II, target, false, xi.action.type.DAMAGE_TARGET, nil, 0, 100 }, + } + + return xi.combat.behavior.chooseAction(mob, target, nil, spellList) end return entity diff --git a/sql/mob_groups.sql b/sql/mob_groups.sql index 81f8a75bb37..690012f3e29 100644 --- a/sql/mob_groups.sql +++ b/sql/mob_groups.sql @@ -1040,7 +1040,7 @@ INSERT INTO `mob_groups` VALUES (53,4292,25,'Warder_Euphrosyne',0,128,0,5000,0,0 INSERT INTO `mob_groups` VALUES (54,4293,25,'Warder_Thalia',0,128,0,5000,0,0,NULL); INSERT INTO `mob_groups` VALUES (55,466,25,'Bloody_Coffin',0,128,0,3500,0,0,NULL); INSERT INTO `mob_groups` VALUES (56,484,25,'Boggelmann',0,128,0,7600,0,0,NULL); -INSERT INTO `mob_groups` VALUES (57,98,25,'Alsha',0,128,0,0,0,0,NULL); +INSERT INTO `mob_groups` VALUES (57,98,25,'Alsha',0,128,0,5000,5000,0,NULL); INSERT INTO `mob_groups` VALUES (58,1792,25,'Gration',0,128,0,32000,32000,0,NULL); INSERT INTO `mob_groups` VALUES (59,4505,25,'Ziphius',0,128,2801,9000,0,0,NULL); INSERT INTO `mob_groups` VALUES (60,6739,25,'Tsui-Goab',0,128,0,0,0,0,NULL); diff --git a/sql/mob_pools.sql b/sql/mob_pools.sql index 745f527c078..3125e70fe2b 100644 --- a/sql/mob_pools.sql +++ b/sql/mob_pools.sql @@ -153,7 +153,7 @@ INSERT INTO `mob_pools` VALUES (94,'Almighty_Apkallu','Almighty_Apkallu',27,0x00 INSERT INTO `mob_pools` VALUES (95,'Almops','Almops',126,0x0000130100000000000000000000000000000000,1,1,6,240,100,0,1,0,1,2,0,0,0,3,0,0,0,0,0,126,126,NULL,NULL); INSERT INTO `mob_pools` VALUES (96,'Alpha_Gnole_Anders','Alpha_Gnole_Anders',132,0x0000F10700000000000000000000000000000000,2,9,1,480,100,0,1,1,1,0,0,32,0,1181,5,0,0,0,0,132,132,2,20); INSERT INTO `mob_pools` VALUES (97,'Alraune','Alraune',178,0x00002D0100000000000000000000000000000000,2,2,1,480,100,0,0,0,1,0,0,0,133,1155,0,0,0,0,0,178,178,1,8); -INSERT INTO `mob_pools` VALUES (98,'Alsha','Alsha',145,0x0500370200000000000000000000000000000000,4,3,11,240,100,0,0,0,0,2,0,32,138,1563,0,0,2,0,0,145,145,1,12); +INSERT INTO `mob_pools` VALUES (98,'Alsha','Alsha',145,0x0500370200000000000000000000000000000000,4,3,11,240,100,0,0,0,0,2,0,32,138,1563,0,0,2,0,0,149,145,1,12); INSERT INTO `mob_pools` VALUES (99,'Altedour_I_Tavnazia','Altedour_I_Tavnazia',221,0x0000280200000000000000000000000000000000,4,4,5,360,100,0,1,0,1,0,0,32,0,1179,0,0,2,0,0,221,221,1,20); INSERT INTO `mob_pools` VALUES (100,'Amaltheia','Amaltheia',208,0x0000580100000000000000000000000000000000,3,3,7,320,100,0,1,1,1,2,744,32,323,1183,0,0,20,0,0,208,208,3,58); INSERT INTO `mob_pools` VALUES (101,'Amaranth','Amaranth',207,0x0000E80700000000000000000000000000000000,6,6,7,240,100,0,1,0,1,0,0,0,0,3,0,0,0,0,0,207,207,NULL,NULL); diff --git a/sql/mob_skills.sql b/sql/mob_skills.sql index 37e6846909f..f4ec29f87df 100644 --- a/sql/mob_skills.sql +++ b/sql/mob_skills.sql @@ -192,9 +192,9 @@ INSERT INTO `mob_skills` VALUES (136,159,'blade_ku',0,0.0,7.0,2000,0,4,0,0,0,9,0 -- INSERT INTO `mob_skills` VALUES (157,??,'tachi_shoha' -- INSERT INTO `mob_skills` VALUES (158,??,'tachi_suikawari' -- INSERT INTO `mob_skills` VALUES (159,??,'tachi_mumei' --- INSERT INTO `mob_skills` VALUES (160,??,'shining_strike' --- INSERT INTO `mob_skills` VALUES (161,??,'seraph_strike' --- INSERT INTO `mob_skills` VALUES (162,??,'brainshaker' +INSERT INTO `mob_skills` VALUES (160,76,'shining_strike',0,0.0,7.0,2000,0,4,0,0,0,8,0,0); +INSERT INTO `mob_skills` VALUES (161,77,'seraph_strike',0,0.0,7.0,2000,0,4,0,0,0,8,0,0); +INSERT INTO `mob_skills` VALUES (162,78,'brainshaker',0,0.0,7.0,2000,0,4,0,0,0,7,5,0); -- INSERT INTO `mob_skills` VALUES (163,??,'starlight' -- INSERT INTO `mob_skills` VALUES (164,??,'moonlight' INSERT INTO `mob_skills` VALUES (165,81,'skullbreaker',0,0.0,7.0,2000,0,4,0,0,0,7,5,0); diff --git a/sql/mob_spawn_points.sql b/sql/mob_spawn_points.sql index 28dba42f61d..370502cd1ba 100644 --- a/sql/mob_spawn_points.sql +++ b/sql/mob_spawn_points.sql @@ -5330,7 +5330,7 @@ INSERT INTO `mob_spawn_points` VALUES (16879894,0,'Warder_Euphrosyne','Warder Eu INSERT INTO `mob_spawn_points` VALUES (16879895,0,'Warder_Thalia','Warder Thalia',54,62,63,260.834,9.525,-437.238,185); INSERT INTO `mob_spawn_points` VALUES (16879896,0,'Bloody_Coffin','Bloody Coffin',55,50,52,638.262,-0.608,-518.056,84); INSERT INTO `mob_spawn_points` VALUES (16879897,0,'Boggelmann','Boggelmann',56,70,70,-310.079,-32.877,181.822,163); -INSERT INTO `mob_spawn_points` VALUES (16879898,0,'Alsha','Alsha',57,60,60,-155.804,-16.191,644.617,195); +INSERT INTO `mob_spawn_points` VALUES (16879898,0,'Alsha','Alsha',57,55,55,-155.804,-16.191,644.617,195); INSERT INTO `mob_spawn_points` VALUES (16879899,0,'Gration','Gration',58,85,85,111.363,-17.000,30.344,141); INSERT INTO `mob_spawn_points` VALUES (16879900,0,'Ziphius','Ziphius',59,55,55,148.401,-16.018,520.438,224); INSERT INTO `mob_spawn_points` VALUES (16879901,0,'Tsui-Goab','Tsui-Goab',60,65,65,441.191,-16.321,126.181,250); -- VNM