From 245b2244d7cbf8adb51935f565c4a4c3605c772d Mon Sep 17 00:00:00 2001 From: MrSent Date: Tue, 5 May 2026 01:25:40 +0100 Subject: [PATCH 1/5] valaineral gambits, mods, spells --- scripts/actions/spells/trust/valaineral.lua | 70 ++++++++++++++++++--- scripts/enum/mob_skill.lua | 2 + scripts/globals/gambits.lua | 32 +++++----- sql/mob_skill_lists.sql | 4 +- sql/mob_spell_lists.sql | 8 +++ src/map/ai/helpers/gambits_container.cpp | 22 +++++++ src/map/ai/helpers/gambits_container.h | 32 +++++----- 7 files changed, 130 insertions(+), 40 deletions(-) diff --git a/scripts/actions/spells/trust/valaineral.lua b/scripts/actions/spells/trust/valaineral.lua index 55ee275370e..b031fa60d09 100644 --- a/scripts/actions/spells/trust/valaineral.lua +++ b/scripts/actions/spells/trust/valaineral.lua @@ -18,19 +18,73 @@ spellObject.onSpellCast = function(caster, target, spell) end spellObject.onMobSpawn = function(mob) - --[[ - Summon: With your courage and valor, Altana's children will live to see a brighter day. - Summon (Formerly): Let the Royal Family’s blade be seared forever into their memories! - ]] xi.trust.message(mob, xi.trust.messageOffset.SPAWN) - mob:addGambit(ai.t.SELF, { ai.c.NOT_HAS_TOP_ENMITY, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.PROVOKE }) + mob:setMobMod(xi.mobMod.CAN_SHIELD_BLOCK, 1) + mob:setMobMod(xi.mobMod.CAN_PARRY, 3) - mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.FLASH }) + local lvl = mob:getMainLvl() + local shieldMasteryPower = 0 - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.SENTINEL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.SENTINEL }) + if lvl >= 96 then + shieldMasteryPower = 40 + elseif lvl >= 75 then + shieldMasteryPower = 30 + elseif lvl >= 50 then + shieldMasteryPower = 20 + elseif lvl >= 25 then + shieldMasteryPower = 10 + end + + mob:setMod(xi.mod.SHIELD_MASTERY_TP, shieldMasteryPower) + mob:setMod(xi.mod.SHIELDBLOCKRATE, 35) -- Around 35% block rate at 99 from testing without reprisal on + mob:addMod(xi.mod.SPELLINTERRUPT, 30) -- Spell interruption rate decrease + mob:addMod(xi.mod.CURE_POTENCY, 50) -- Cure Potency Bonus+50% + mob:addMod(xi.mod.FASTCAST, 30) -- Has fastcast around 30% + mob:addMod(xi.mod.REFRESH, 2) -- PLD auto refresh +2mp a tick Refresh+ + mob:addMod(xi.mod.ENMITY, 25) -- Enmity+ + mob:addMod(xi.mod.DMG, -800) -- Damage Taken -8% + mob:addMod(xi.mod.HPP, 10) -- HP+10% + mob:addMod(xi.mod.MPP, 20) -- MP+20% + + mob:addGambit(ai.t.SELF, { ai.c.NOT_HAS_TOP_ENMITY, 0 }, { ai.r.MS, ai.s.SPECIFIC, xi.mobSkill.URIEL_BLADE_1 }, 30) + mob:addGambit(ai.t.SELF, { ai.c.ALWAYS, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.PROVOKE }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.MAJESTY }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.MAJESTY }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PROTECT }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.PROTECT }) + mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.DIVINE_EMBLEM }) + mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.FLASH }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.SENTINEL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.SENTINEL }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.REPRISAL }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.REPRISAL }) + mob:addGambit(ai.t.PARTY, { ai.c.HPP_LT, 50 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) + mob:addGambit(ai.t.SELF, { ai.c.HPP_LT, 70 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.ENLIGHT }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.ENLIGHT }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PHALANX }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.PHALANX }) + mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_I }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) + mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_II }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) + mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.MANAFONT }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) + mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.CHAINSPELL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) + mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.ASTRAL_FLOW }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) + mob:addGambit(ai.t.TARGET, { ai.c.CASTING_DEBUFF, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.FEALTY }) -- This needs more work to cover a multitude of triggers + + mob:addGambit(ai.t.SELF, { + { ai.c.JA_ON_COOLDOWN, xi.ja.SENTINEL }, + { ai.c.NOT_STATUS, xi.effect.DEFENDER }, + { ai.c.NOT_STATUS, xi.effect.SENTINEL }, }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.DEFENDER }) + + mob:addGambit(ai.t.SELF, { + { ai.c.MPP_LT, 50 }, + { ai.c.TP_GTE, 1000 }, }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.CHIVALRY }) + + mob:setTrustTPSkillSettings(ai.tp.RANDOM, ai.s.RANDOM, 2000) - mob:addGambit(ai.t.PARTY, { ai.c.HPP_LT, 50 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) + mob:addListener('WEAPONSKILL_USE', 'VALAINERAL_WEAPONSKILL_USE', function(mobArg, target, skill, tp, action, damage) + if skill:getID() == xi.mobSkill.URIEL_BLADE_1 then -- Uriel Blade + -- Let the Blade of the Conqueror once again bring glory to the Kingdom! + if math.random(1, 100) <= 33 then + xi.trust.message(mobArg, xi.trust.messageOffset.SPECIAL_MOVE_1) + end + end + end) end spellObject.onMobDespawn = function(mob) diff --git a/scripts/enum/mob_skill.lua b/scripts/enum/mob_skill.lua index b7faf2fd2c6..311f234f615 100644 --- a/scripts/enum/mob_skill.lua +++ b/scripts/enum/mob_skill.lua @@ -124,6 +124,8 @@ xi.mobSkill = DETONATOR_1 = 215, + URIEL_BLADE_1 = 238, + NETHERSPIKES_1 = 241, CARNAL_NIGHTMARE_1 = 242, AEGIS_SCHISM_1 = 243, diff --git a/scripts/globals/gambits.lua b/scripts/globals/gambits.lua index 7cf0936bf26..1416a2f14a5 100644 --- a/scripts/globals/gambits.lua +++ b/scripts/globals/gambits.lua @@ -78,21 +78,23 @@ ai.condition = READYING_MS = 18, READYING_JA = 19, CASTING_MA = 20, - RANDOM = 21, - NO_SAMBA = 22, - NO_STORM = 23, - PT_HAS_TANK = 24, - NOT_PT_HAS_TANK = 25, - IS_ECOSYSTEM = 26, - HP_MISSING = 27, - CASTING_ELEMENT_MA = 28, - CAST_ELE_MA_SELF = 29, - CASTING_ELE_MA_AOE = 30, - NEED_ELE_BAREFFECT = 31, - NO_MAX_RUNE = 32, - HAS_RUNES = 33, - LUNGE_MB_AVAILABLE = 34, - SUB_ANIMATION = 35, + CASTING_DEBUFF = 21, + RANDOM = 22, + NO_SAMBA = 23, + NO_STORM = 24, + PT_HAS_TANK = 25, + NOT_PT_HAS_TANK = 26, + IS_ECOSYSTEM = 27, + HP_MISSING = 28, + CASTING_ELEMENT_MA = 29, + CAST_ELE_MA_SELF = 30, + CASTING_ELE_MA_AOE = 31, + NEED_ELE_BAREFFECT = 32, + NO_MAX_RUNE = 33, + HAS_RUNES = 34, + LUNGE_MB_AVAILABLE = 35, + SUB_ANIMATION = 36, + JA_ON_COOLDOWN = 37, } ai.c = ai.condition diff --git a/sql/mob_skill_lists.sql b/sql/mob_skill_lists.sql index 724d4b68ee8..811141297f7 100644 --- a/sql/mob_skill_lists.sql +++ b/sql/mob_skill_lists.sql @@ -3449,9 +3449,9 @@ INSERT INTO `mob_skill_lists` VALUES ('TRUST_Mihli_Aliapoh',1024,162); -- Brain INSERT INTO `mob_skill_lists` VALUES ('TRUST_Mihli_Aliapoh',1024,166); -- True Strike INSERT INTO `mob_skill_lists` VALUES ('TRUST_Mihli_Aliapoh',1024,168); -- Hexastrike INSERT INTO `mob_skill_lists` VALUES ('TRUST_Mihli_Aliapoh',1024,3203); -- Scouring Bubbles -INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,34); -- Red Lotus Blade -INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,41); -- Swift Blade +INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,7); -- Circle Blade INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,42); -- Savage Blade +INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,47); -- Sanguine Blade INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,238); -- Uriel Blade -- INSERT INTO `mob_skill_lists` VALUES ('TRUST_Joachim',1026,0); INSERT INTO `mob_skill_lists` VALUES ('TRUST_Naja_Salaheem',1027,166); -- True Strike diff --git a/sql/mob_spell_lists.sql b/sql/mob_spell_lists.sql index 08e73d379d5..6ac2bcc47f4 100644 --- a/sql/mob_spell_lists.sql +++ b/sql/mob_spell_lists.sql @@ -3214,7 +3214,15 @@ INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,1,5,255); -- cur INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,2,17,255); -- cure_ii (17~255) INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,3,30,255); -- cure_iii (30~255) INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,4,55,255); -- cure_iv (55~255) +INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,43,7,255); -- protect (7~255) +INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,44,27,255); -- protect_ii (27~255) +INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,45,47,255); -- protect_iii (47~255) +INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,46,63,255); -- protect_iv (63~255) +INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,47,77,255); -- protect_v (77~255) +INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,97,61,255); -- reprisal (61~255) +INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,106,77,255); -- phalanx (77~255) INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,112,37,255); -- flash (37~255) +INSERT INTO `mob_spell_lists` VALUES ('TRUST_Valaineral',322,310,85,255); -- enlight (85~255) -- TRUST_Joachim (323) INSERT INTO `mob_spell_lists` VALUES ('TRUST_Joachim',323,1,2,255); -- cure (2~255) diff --git a/src/map/ai/helpers/gambits_container.cpp b/src/map/ai/helpers/gambits_container.cpp index dc74f42cf7c..cc71c3ad89f 100644 --- a/src/map/ai/helpers/gambits_container.cpp +++ b/src/map/ai/helpers/gambits_container.cpp @@ -1012,6 +1012,12 @@ bool CGambitsContainer::CheckTrigger(const CBattleEntity* triggerTarget, Predica predicateResults.push_back(!triggerTarget->StatusEffectContainer->HasStatusEffect(static_cast(predicate.condition_arg))); continue; } + case G_CONDITION::JA_ON_COOLDOWN: + { + auto* PAbility = ability::GetAbility(static_cast(predicate.condition_arg)); + predicateResults.push_back(PAbility->getRecastTime() > 0s); + continue; + } case G_CONDITION::LVL_LT: { predicateResults.push_back(triggerTarget->GetMLevel() < predicate.condition_arg); @@ -1206,6 +1212,22 @@ bool CGambitsContainer::CheckTrigger(const CBattleEntity* triggerTarget, Predica predicateResults.push_back(triggerTarget->PAI->IsCurrentState()); continue; } + case G_CONDITION::CASTING_DEBUFF: + { + // Check if the target is currently casting a debuff magic spell + bool isDebuff = false; + if (triggerTarget->PAI->IsCurrentState()) + { + auto spell = static_cast(triggerTarget->PAI->GetCurrentState())->GetSpell(); + + if (spell->isDebuff()) + { + isDebuff = true; + } + } + predicateResults.push_back(isDebuff); + continue; + } case G_CONDITION::CASTING_ELE_MA_AOE: { bool isAOE = false; diff --git a/src/map/ai/helpers/gambits_container.h b/src/map/ai/helpers/gambits_container.h index 8a2e374d9dc..39ff2e4682c 100644 --- a/src/map/ai/helpers/gambits_container.h +++ b/src/map/ai/helpers/gambits_container.h @@ -83,21 +83,23 @@ enum class G_CONDITION : uint16 READYING_MS = 18, READYING_JA = 19, CASTING_MA = 20, - RANDOM = 21, - NO_SAMBA = 22, - NO_STORM = 23, - PT_HAS_TANK = 24, - NOT_PT_HAS_TANK = 25, - IS_ECOSYSTEM = 26, - HP_MISSING = 27, - CASTING_ELEMENT_MA = 28, - CAST_ELE_MA_SELF = 29, - CASTING_ELE_MA_AOE = 30, - NEED_ELE_BAREFFECT = 31, - NO_MAX_RUNE = 32, - HAS_RUNES = 33, - LUNGE_MB_AVAILABLE = 34, - SUB_ANIMATION = 35, + CASTING_DEBUFF = 21, + RANDOM = 22, + NO_SAMBA = 23, + NO_STORM = 24, + PT_HAS_TANK = 25, + NOT_PT_HAS_TANK = 26, + IS_ECOSYSTEM = 27, + HP_MISSING = 28, + CASTING_ELEMENT_MA = 29, + CAST_ELE_MA_SELF = 30, + CASTING_ELE_MA_AOE = 31, + NEED_ELE_BAREFFECT = 32, + NO_MAX_RUNE = 33, + HAS_RUNES = 34, + LUNGE_MB_AVAILABLE = 35, + SUB_ANIMATION = 36, + JA_ON_COOLDOWN = 37, }; enum class G_REACTION : uint16 From eaa593bac0dea618161072c9527c25e6fc99bfca Mon Sep 17 00:00:00 2001 From: MrSent Date: Thu, 7 May 2026 16:51:00 +0100 Subject: [PATCH 2/5] Uriel Blade script adjustments to be more inline with retail --- scripts/actions/mobskills/uriel_blade.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/actions/mobskills/uriel_blade.lua b/scripts/actions/mobskills/uriel_blade.lua index 8bcae9ba219..0e128840f00 100644 --- a/scripts/actions/mobskills/uriel_blade.lua +++ b/scripts/actions/mobskills/uriel_blade.lua @@ -7,7 +7,7 @@ local mobskillObject = {} mobskillObject.onMobSkillCheck = function(target, mob, skill) - mob:messageBasic(xi.msg.basic.READIES_WS, 0, xi.weaponskill.FAST_BLADE) + mob:messageBasic(xi.msg.basic.READIES_WS, 0, xi.weaponskill.URIEL_BLADE) return 0 end @@ -17,12 +17,17 @@ mobskillObject.onMobWeaponSkill = function(mob, target, skill, action) params.baseDamage = mob:getWeaponDmg() params.numHits = 1 params.fTP = { 4.5, 6.0, 7.5 } - -- params.str_wSC = 0.32 -- TODO: Capture if mobskill weaponskills have wSC. - -- params.mnd_wSC = 0.32 -- TODO: Capture if mobskill weaponskills have wSC. + params.accuracyModifier = { 100, 100, 100 } + params.str_wSC = 0.32 + params.mnd_wSC = 0.32 params.attackType = xi.attackType.PHYSICAL params.damageType = xi.damageType.SLASHING params.shadowBehavior = xi.mobskills.shadowBehavior.NUMSHADOWS_1 + if skill:getTP() < 1000 then + params.fTPBonus = 1000 + end + local info = xi.mobskills.mobPhysicalMove(mob, target, skill, action, params) if xi.mobskills.processDamage(mob, target, skill, action, info) then From e0458d6135953623e9608fbed85af29d2b342e0f Mon Sep 17 00:00:00 2001 From: MrSent Date: Thu, 7 May 2026 16:52:17 +0100 Subject: [PATCH 3/5] Gambit addition for more retail accurate Uriel Blade usage --- scripts/actions/spells/trust/valaineral.lua | 43 ++++++------- scripts/globals/gambits.lua | 1 + src/map/ai/controllers/trust_controller.cpp | 2 +- src/map/ai/helpers/gambits_container.cpp | 70 ++++++++++++++++++++- src/map/ai/helpers/gambits_container.h | 1 + 5 files changed, 93 insertions(+), 24 deletions(-) diff --git a/scripts/actions/spells/trust/valaineral.lua b/scripts/actions/spells/trust/valaineral.lua index b031fa60d09..d8d945e232d 100644 --- a/scripts/actions/spells/trust/valaineral.lua +++ b/scripts/actions/spells/trust/valaineral.lua @@ -47,24 +47,24 @@ spellObject.onMobSpawn = function(mob) mob:addMod(xi.mod.HPP, 10) -- HP+10% mob:addMod(xi.mod.MPP, 20) -- MP+20% - mob:addGambit(ai.t.SELF, { ai.c.NOT_HAS_TOP_ENMITY, 0 }, { ai.r.MS, ai.s.SPECIFIC, xi.mobSkill.URIEL_BLADE_1 }, 30) - mob:addGambit(ai.t.SELF, { ai.c.ALWAYS, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.PROVOKE }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.MAJESTY }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.MAJESTY }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PROTECT }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.PROTECT }) - mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.DIVINE_EMBLEM }) - mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.FLASH }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.SENTINEL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.SENTINEL }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.REPRISAL }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.REPRISAL }) - mob:addGambit(ai.t.PARTY, { ai.c.HPP_LT, 50 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) - mob:addGambit(ai.t.SELF, { ai.c.HPP_LT, 70 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.ENLIGHT }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.ENLIGHT }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PHALANX }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.PHALANX }) - mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_I }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) - mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_II }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) - mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.MANAFONT }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) - mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.CHAINSPELL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) - mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.ASTRAL_FLOW }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) - mob:addGambit(ai.t.TARGET, { ai.c.CASTING_DEBUFF, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.FEALTY }) -- This needs more work to cover a multitude of triggers + mob:addGambit(ai.t.TARGET, { ai.c.VAL_URIEL_CHECK, 0 }, { ai.r.MS, ai.s.SPECIFIC, xi.mobSkill.URIEL_BLADE_1 }) + mob:addGambit(ai.t.SELF, { ai.c.ALWAYS, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.PROVOKE }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.MAJESTY }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.MAJESTY }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PROTECT }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.PROTECT }) + mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.DIVINE_EMBLEM }) + mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.FLASH }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.SENTINEL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.SENTINEL }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.REPRISAL }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.REPRISAL }) + mob:addGambit(ai.t.PARTY, { ai.c.HPP_LT, 50 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) + mob:addGambit(ai.t.SELF, { ai.c.HPP_LT, 70 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.ENLIGHT }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.ENLIGHT }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PHALANX }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.PHALANX }) + mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_I }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) + mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_II }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) + mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.MANAFONT }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) + mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.CHAINSPELL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) + mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.ASTRAL_FLOW }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) + mob:addGambit(ai.t.TARGET, { ai.c.CASTING_DEBUFF, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.FEALTY }) -- This needs more work to cover a multitude of triggers mob:addGambit(ai.t.SELF, { { ai.c.JA_ON_COOLDOWN, xi.ja.SENTINEL }, @@ -75,14 +75,15 @@ spellObject.onMobSpawn = function(mob) { ai.c.MPP_LT, 50 }, { ai.c.TP_GTE, 1000 }, }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.CHIVALRY }) - mob:setTrustTPSkillSettings(ai.tp.RANDOM, ai.s.RANDOM, 2000) + mob:setTrustTPSkillSettings(ai.tp.OPENER, ai.s.RANDOM, 2000) mob:addListener('WEAPONSKILL_USE', 'VALAINERAL_WEAPONSKILL_USE', function(mobArg, target, skill, tp, action, damage) if skill:getID() == xi.mobSkill.URIEL_BLADE_1 then -- Uriel Blade - -- Let the Blade of the Conqueror once again bring glory to the Kingdom! - if math.random(1, 100) <= 33 then + -- Let the Blade of the Conqueror once again bring glory to the Kingdom! + if math.random(1, 100) <= 33 and target:getID() == skill:getPrimaryTargetID() then xi.trust.message(mobArg, xi.trust.messageOffset.SPECIAL_MOVE_1) end + mobArg:setLocalVar('[Gambit]LastUrielTime', GetSystemTime()) end end) end diff --git a/scripts/globals/gambits.lua b/scripts/globals/gambits.lua index 1416a2f14a5..43af96e0e29 100644 --- a/scripts/globals/gambits.lua +++ b/scripts/globals/gambits.lua @@ -95,6 +95,7 @@ ai.condition = LUNGE_MB_AVAILABLE = 35, SUB_ANIMATION = 36, JA_ON_COOLDOWN = 37, + VAL_URIEL_CHECK = 38, } ai.c = ai.condition diff --git a/src/map/ai/controllers/trust_controller.cpp b/src/map/ai/controllers/trust_controller.cpp index ad05f72fb93..eede0ebf0ba 100644 --- a/src/map/ai/controllers/trust_controller.cpp +++ b/src/map/ai/controllers/trust_controller.cpp @@ -167,7 +167,7 @@ auto CTrustController::DoCombatTick(timer::time_point tick) -> Task float currentDistanceToTarget = distance(PTrust->loc.p, PTarget->loc.p); float currentDistanceToMaster = distance(PTrust->loc.p, PMaster->loc.p); - if (currentDistanceToTarget > WarpDistance) + if (!PMaster->PAI->IsEngaged() && currentDistanceToTarget > WarpDistance) { PTrust->PAI->PathFind->WarpTo(PTarget->loc.p); } diff --git a/src/map/ai/helpers/gambits_container.cpp b/src/map/ai/helpers/gambits_container.cpp index cc71c3ad89f..8b8f19998e6 100644 --- a/src/map/ai/helpers/gambits_container.cpp +++ b/src/map/ai/helpers/gambits_container.cpp @@ -34,6 +34,7 @@ #include "utils/battleutils.h" #include "utils/trustutils.h" #include "weapon_skill.h" +#include "notoriety_container.h" #include "ai/controllers/player_controller.h" #include "ai/controllers/trust_controller.h" @@ -814,8 +815,11 @@ auto CGambitsContainer::Tick(timer::time_point tick) -> Task if (action.select == G_SELECT::SPECIFIC) { - controller->Ability(target->targid, PAbility->getID()); - executedAnyAction = true; + if (target != nullptr) + { + controller->Ability(target->targid, PAbility->getID()); + executedAnyAction = true; + } } if (action.select == G_SELECT::BEST_SAMBA) @@ -1328,6 +1332,68 @@ bool CGambitsContainer::CheckTrigger(const CBattleEntity* triggerTarget, Predica predicateResults.push_back(triggerTarget->animationsub == predicate.condition_arg); continue; } + case G_CONDITION::VAL_URIEL_CHECK: + { + bool canUseUriel = false; + auto* PMaster = dynamic_cast(POwner->PMaster); + auto* PMob = dynamic_cast(PMaster->GetBattleTarget()); + + if (PMob != nullptr && PMob->PEnmityContainer != nullptr) + { + bool masterHasEnmity = PMob->PEnmityContainer->HasID(PMaster->id); + bool valHasEnmity = PMob->PEnmityContainer->HasID(POwner->id); + bool valHasTopEnmity = (controller->GetTopEnmity()) ? controller->GetTopEnmity()->targid == POwner->targid : false; + bool masterHasOffTargetAggro = false; + + if (PMaster->PNotorietyContainer != nullptr && PMaster->PNotorietyContainer->hasEnmity()) + { + for (auto it = PMaster->PNotorietyContainer->begin(); it != PMaster->PNotorietyContainer->end(); ++it) + { + if (masterHasOffTargetAggro) + { + break; + } + + auto* PZoneMob = dynamic_cast(*it); + if (!PZoneMob || !PZoneMob->isAlive()) + { + continue; + } + + if (distance(PMaster->loc.p, PZoneMob->loc.p) > 10.0f) + { + continue; + } + + const bool targetingMaster = (PZoneMob->GetBattleTargetID() == PMaster->targid); + const bool isMastersCurrentTarget = (PZoneMob->id == PMob->id); + const bool hostile = (PZoneMob->allegiance != PMaster->allegiance); + + if (targetingMaster && !isMastersCurrentTarget && hostile) + { + masterHasOffTargetAggro = true; + } + } + } + + if ((masterHasEnmity && !valHasTopEnmity) || masterHasOffTargetAggro) + { + auto timeNow = std::chrono::system_clock::now(); + uint32 lastUrielTime = POwner->GetLocalVar("[Gambit]LastUrielTime"); + auto distanceToTarget = distance(POwner->loc.p, PMob->loc.p); + + auto lastTimePoint = std::chrono::time_point(std::chrono::seconds(lastUrielTime)); + auto timeDiff = timeNow - lastTimePoint; + bool longCooldown = (timeDiff >= std::chrono::seconds(30)); // Standard Cooldown + bool shortCooldown = (timeDiff >= std::chrono::seconds(5)); // New Target Cooldown + + canUseUriel = (distanceToTarget <= 10.0f) && + ((valHasEnmity && longCooldown) || (!valHasEnmity && shortCooldown) || (masterHasOffTargetAggro && longCooldown)); + } + } + predicateResults.push_back(canUseUriel); + continue; + } default: { predicateResults.push_back(false); diff --git a/src/map/ai/helpers/gambits_container.h b/src/map/ai/helpers/gambits_container.h index 39ff2e4682c..53458ca3adb 100644 --- a/src/map/ai/helpers/gambits_container.h +++ b/src/map/ai/helpers/gambits_container.h @@ -100,6 +100,7 @@ enum class G_CONDITION : uint16 LUNGE_MB_AVAILABLE = 35, SUB_ANIMATION = 36, JA_ON_COOLDOWN = 37, + VAL_URIEL_CHECK = 38, }; enum class G_REACTION : uint16 From 2b1c191d442527a7986b06247b20265947623512 Mon Sep 17 00:00:00 2001 From: MrSent Date: Thu, 7 May 2026 17:04:11 +0100 Subject: [PATCH 4/5] formatting fixes --- scripts/actions/spells/trust/valaineral.lua | 7 +++++-- src/map/ai/helpers/gambits_container.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/scripts/actions/spells/trust/valaineral.lua b/scripts/actions/spells/trust/valaineral.lua index d8d945e232d..68bfe45437c 100644 --- a/scripts/actions/spells/trust/valaineral.lua +++ b/scripts/actions/spells/trust/valaineral.lua @@ -80,9 +80,12 @@ spellObject.onMobSpawn = function(mob) mob:addListener('WEAPONSKILL_USE', 'VALAINERAL_WEAPONSKILL_USE', function(mobArg, target, skill, tp, action, damage) if skill:getID() == xi.mobSkill.URIEL_BLADE_1 then -- Uriel Blade -- Let the Blade of the Conqueror once again bring glory to the Kingdom! - if math.random(1, 100) <= 33 and target:getID() == skill:getPrimaryTargetID() then - xi.trust.message(mobArg, xi.trust.messageOffset.SPECIAL_MOVE_1) + if math.random(1, 100) <= 33 then + if target:getID() == skill:getPrimaryTargetID() then + xi.trust.message(mobArg, xi.trust.messageOffset.SPECIAL_MOVE_1) + end end + mobArg:setLocalVar('[Gambit]LastUrielTime', GetSystemTime()) end end) diff --git a/src/map/ai/helpers/gambits_container.cpp b/src/map/ai/helpers/gambits_container.cpp index 8b8f19998e6..c6aa5a2a136 100644 --- a/src/map/ai/helpers/gambits_container.cpp +++ b/src/map/ai/helpers/gambits_container.cpp @@ -30,11 +30,11 @@ #include "ai/states/weaponskill_state.h" #include "enmity_container.h" #include "mobskill.h" +#include "notoriety_container.h" #include "spell.h" #include "utils/battleutils.h" #include "utils/trustutils.h" #include "weapon_skill.h" -#include "notoriety_container.h" #include "ai/controllers/player_controller.h" #include "ai/controllers/trust_controller.h" @@ -1334,9 +1334,9 @@ bool CGambitsContainer::CheckTrigger(const CBattleEntity* triggerTarget, Predica } case G_CONDITION::VAL_URIEL_CHECK: { - bool canUseUriel = false; - auto* PMaster = dynamic_cast(POwner->PMaster); - auto* PMob = dynamic_cast(PMaster->GetBattleTarget()); + bool canUseUriel = false; + auto* PMaster = dynamic_cast(POwner->PMaster); + auto* PMob = dynamic_cast(PMaster->GetBattleTarget()); if (PMob != nullptr && PMob->PEnmityContainer != nullptr) { From acfbde8b68e149f3fdcedb4c064732e5932ac0b8 Mon Sep 17 00:00:00 2001 From: MrSent Date: Thu, 7 May 2026 22:35:52 +0100 Subject: [PATCH 5/5] Uriel gambit adjustments and a ws had wrong id --- scripts/actions/spells/trust/valaineral.lua | 68 +++++++++++++-------- sql/mob_skill_lists.sql | 2 +- src/map/ai/helpers/gambits_container.cpp | 2 +- 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/scripts/actions/spells/trust/valaineral.lua b/scripts/actions/spells/trust/valaineral.lua index 68bfe45437c..9e53f5cb094 100644 --- a/scripts/actions/spells/trust/valaineral.lua +++ b/scripts/actions/spells/trust/valaineral.lua @@ -47,33 +47,47 @@ spellObject.onMobSpawn = function(mob) mob:addMod(xi.mod.HPP, 10) -- HP+10% mob:addMod(xi.mod.MPP, 20) -- MP+20% - mob:addGambit(ai.t.TARGET, { ai.c.VAL_URIEL_CHECK, 0 }, { ai.r.MS, ai.s.SPECIFIC, xi.mobSkill.URIEL_BLADE_1 }) - mob:addGambit(ai.t.SELF, { ai.c.ALWAYS, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.PROVOKE }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.MAJESTY }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.MAJESTY }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PROTECT }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.PROTECT }) - mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.DIVINE_EMBLEM }) - mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.FLASH }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.SENTINEL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.SENTINEL }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.REPRISAL }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.REPRISAL }) - mob:addGambit(ai.t.PARTY, { ai.c.HPP_LT, 50 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) - mob:addGambit(ai.t.SELF, { ai.c.HPP_LT, 70 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.ENLIGHT }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.ENLIGHT }) - mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PHALANX }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.PHALANX }) - mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_I }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) - mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_II }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) - mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.MANAFONT }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) - mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.CHAINSPELL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) - mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.ASTRAL_FLOW }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) - mob:addGambit(ai.t.TARGET, { ai.c.CASTING_DEBUFF, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.FEALTY }) -- This needs more work to cover a multitude of triggers - - mob:addGambit(ai.t.SELF, { - { ai.c.JA_ON_COOLDOWN, xi.ja.SENTINEL }, - { ai.c.NOT_STATUS, xi.effect.DEFENDER }, - { ai.c.NOT_STATUS, xi.effect.SENTINEL }, }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.DEFENDER }) - - mob:addGambit(ai.t.SELF, { - { ai.c.MPP_LT, 50 }, - { ai.c.TP_GTE, 1000 }, }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.CHIVALRY }) + if lvl >= 1 then + mob:addGambit(ai.t.TARGET, { ai.c.VAL_URIEL_CHECK, 0 }, { ai.r.MS, ai.s.SPECIFIC, xi.mobSkill.URIEL_BLADE_1 }) + end + + if lvl >= 5 then + mob:addGambit(ai.t.SELF, { ai.c.ALWAYS, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.PROVOKE }) + end + + if lvl >= 30 then + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.SENTINEL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.SENTINEL }) + end + + if lvl >= 50 then + mob:addGambit(ai.t.SELF, { { ai.c.MPP_LT, 50 }, { ai.c.TP_GTE, 1000 } }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.CHIVALRY }) + mob:addGambit(ai.t.SELF, { { ai.c.JA_ON_COOLDOWN, xi.ja.SENTINEL }, { ai.c.NOT_STATUS, xi.effect.SENTINEL } }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.DEFENDER }) + end + + if lvl >= 62 then + mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.MANAFONT }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) + mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.CHAINSPELL }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) + mob:addGambit(ai.t.TARGET, { ai.c.STATUS, xi.effect.ASTRAL_FLOW }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.RAMPART }) + end + + if lvl >= 70 then + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.MAJESTY }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.MAJESTY }) + end + + if lvl >= 75 then + mob:addGambit(ai.t.TARGET, { ai.c.CASTING_DEBUFF, 0 }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.FEALTY }) + mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.JA, ai.s.SPECIFIC, xi.ja.DIVINE_EMBLEM }) + end + + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PROTECT }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.PROTECT }) + mob:addGambit(ai.t.TARGET, { ai.c.NOT_STATUS, xi.effect.FLASH }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.FLASH }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.REPRISAL }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.REPRISAL }) + mob:addGambit(ai.t.PARTY, { ai.c.HPP_LT, 50 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) + mob:addGambit(ai.t.SELF, { ai.c.HPP_LT, 70 }, { ai.r.MA, ai.s.HIGHEST, xi.magic.spellFamily.CURE }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.ENLIGHT }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.ENLIGHT }) + mob:addGambit(ai.t.SELF, { ai.c.NOT_STATUS, xi.effect.PHALANX }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.PHALANX }) + mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_I }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) + mob:addGambit(ai.t.PARTY, { ai.c.STATUS, xi.effect.SLEEP_II }, { ai.r.MA, ai.s.SPECIFIC, xi.magic.spell.CURE }) mob:setTrustTPSkillSettings(ai.tp.OPENER, ai.s.RANDOM, 2000) diff --git a/sql/mob_skill_lists.sql b/sql/mob_skill_lists.sql index 811141297f7..9319a380481 100644 --- a/sql/mob_skill_lists.sql +++ b/sql/mob_skill_lists.sql @@ -3449,7 +3449,7 @@ INSERT INTO `mob_skill_lists` VALUES ('TRUST_Mihli_Aliapoh',1024,162); -- Brain INSERT INTO `mob_skill_lists` VALUES ('TRUST_Mihli_Aliapoh',1024,166); -- True Strike INSERT INTO `mob_skill_lists` VALUES ('TRUST_Mihli_Aliapoh',1024,168); -- Hexastrike INSERT INTO `mob_skill_lists` VALUES ('TRUST_Mihli_Aliapoh',1024,3203); -- Scouring Bubbles -INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,7); -- Circle Blade +INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,38); -- Circle Blade INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,42); -- Savage Blade INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,47); -- Sanguine Blade INSERT INTO `mob_skill_lists` VALUES ('TRUST_Valaineral',1025,238); -- Uriel Blade diff --git a/src/map/ai/helpers/gambits_container.cpp b/src/map/ai/helpers/gambits_container.cpp index c6aa5a2a136..83866abfede 100644 --- a/src/map/ai/helpers/gambits_container.cpp +++ b/src/map/ai/helpers/gambits_container.cpp @@ -1360,7 +1360,7 @@ bool CGambitsContainer::CheckTrigger(const CBattleEntity* triggerTarget, Predica continue; } - if (distance(PMaster->loc.p, PZoneMob->loc.p) > 10.0f) + if (distance(POwner->loc.p, PZoneMob->loc.p) > 10.0f) { continue; }