From 4bce7000e0cd16037710ec581d4c392ebe666176 Mon Sep 17 00:00:00 2001 From: andrebastosdias Date: Sun, 8 Feb 2026 17:23:20 +0000 Subject: [PATCH 1/3] Fix Pursuit interaction with Encore --- data/mods/gen1/conditions.ts | 7 ---- data/mods/gen2/conditions.ts | 7 ---- data/mods/gen2/moves.ts | 55 +++++++++++--------------- data/mods/gen3/moves.ts | 45 +++++++++++++++------ data/mods/gen4/moves.ts | 59 +++++++++++----------------- data/moves.ts | 62 +++++++++++++---------------- sim/pokemon.ts | 2 +- test/sim/moves/pursuit.js | 76 ++++++++++++++++++++++++++++++++++++ 8 files changed, 183 insertions(+), 130 deletions(-) diff --git a/data/mods/gen1/conditions.ts b/data/mods/gen1/conditions.ts index c62ee6e2ed..0837f9b064 100644 --- a/data/mods/gen1/conditions.ts +++ b/data/mods/gen1/conditions.ts @@ -289,13 +289,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa onLockMove() { return this.effectState.move; }, - onBeforeTurn(pokemon) { - const move = this.dex.moves.get(this.effectState.move); - if (move.id) { - this.debug('Forcing into ' + move.id); - this.queue.changeAction(pokemon, { choice: 'move', moveid: move.id }); - } - }, onAfterMove(pokemon) { if (pokemon.volatiles['lockedmove'].time <= 0) { pokemon.removeVolatile('lockedmove'); diff --git a/data/mods/gen2/conditions.ts b/data/mods/gen2/conditions.ts index 55812c82af..93db7ccca8 100644 --- a/data/mods/gen2/conditions.ts +++ b/data/mods/gen2/conditions.ts @@ -193,13 +193,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa onMoveAborted(pokemon) { delete pokemon.volatiles['lockedmove']; }, - onBeforeTurn(pokemon) { - const move = this.dex.moves.get(this.effectState.move); - if (move.id) { - this.debug('Forcing into ' + move.id); - this.queue.changeAction(pokemon, { choice: 'move', moveid: move.id }); - } - }, }, futuremove: { inherit: true, diff --git a/data/mods/gen2/moves.ts b/data/mods/gen2/moves.ts index a93ee5c525..10c2f63483 100644 --- a/data/mods/gen2/moves.ts +++ b/data/mods/gen2/moves.ts @@ -198,9 +198,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { } this.effectState.move = lockedMove; this.add('-start', target, 'Encore'); + if (this.effectState.move === 'pursuit') target.addVolatile('pursuit', target); }, - onOverrideAction(pokemon) { - return this.effectState.move; + onOverrideAction(pokemon, target, move) { + if (move.id !== this.effectState.move) return this.effectState.move; }, onResidualOrder: 13, onResidual(target) { @@ -573,44 +574,32 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { }, pursuit: { inherit: true, - beforeTurnCallback(pokemon, target) { - if (pokemon.isAlly(target)) return; - target.addVolatile('pursuit'); - const data = target.volatiles['pursuit']; - if (!data.sources) { - data.sources = []; - } - data.sources.push(pokemon); - }, onModifyMove() {}, condition: { duration: 1, - onBeforeSwitchOut(pokemon) { + onFoeBeforeSwitchOut(pokemon) { + const source: Pokemon = this.effectState.source; this.debug('Pursuit start'); - let alreadyAdded = false; - for (const source of this.effectState.sources) { - if (source.speed < pokemon.speed || (source.speed === pokemon.speed && this.randomChance(1, 2))) { - // Destiny Bond ends if the switch action "outspeeds" the attacker, regardless of host - pokemon.removeVolatile('destinybond'); - } - if (!this.queue.cancelMove(source) || !source.hp) continue; - if (!alreadyAdded) { - this.add('-activate', pokemon, 'move: Pursuit'); - alreadyAdded = true; - } - // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. - // If it is, then Mega Evolve before moving. - if (source.canMegaEvo || source.canUltraBurst) { - for (const [actionIndex, action] of this.queue.entries()) { - if (action.pokemon === source && action.choice === 'megaEvo') { - this.actions.runMegaEvo(source); - this.queue.list.splice(actionIndex, 1); - break; - } + if (this.effectState.targetLoc !== source.getLocOf(pokemon) || + !source.isAdjacent(pokemon) || !source.hp || ( + source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit' + ) || !this.queue.cancelMove(source)) return; + // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. + // If it is, then Mega Evolve before moving. + if (source.canMegaEvo || source.canUltraBurst) { + for (const [actionIndex, action] of this.queue.entries()) { + if (action.pokemon === source && action.choice === 'megaEvo') { + this.actions.runMegaEvo(source); + this.queue.list.splice(actionIndex, 1); + break; } } - this.actions.runMove('pursuit', source, source.getLocOf(pokemon)); } + if (source.speed < pokemon.speed || (source.speed === pokemon.speed && this.randomChance(1, 2))) { + // Destiny Bond ends if the switch action "outspeeds" the attacker, regardless of host + pokemon.removeVolatile('destinybond'); + } + this.actions.runMove('pursuit', source, source.getLocOf(pokemon)); }, }, }, diff --git a/data/mods/gen3/moves.ts b/data/mods/gen3/moves.ts index 191b050808..2cfab2b5c2 100644 --- a/data/mods/gen3/moves.ts +++ b/data/mods/gen3/moves.ts @@ -321,9 +321,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { } this.effectState.move = target.lastMove.id; this.add('-start', target, 'Encore'); + if (this.effectState.move === 'pursuit') target.addVolatile('pursuit', target); }, - onOverrideAction(pokemon) { - return this.effectState.move; + onOverrideAction(pokemon, target, move) { + if (move.id !== this.effectState.move) return this.effectState.move; }, onResidualOrder: 10, onResidualSubOrder: 14, @@ -581,15 +582,37 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { pursuit: { inherit: true, beforeTurnCallback(pokemon, target) { - if (['frz', 'slp'].includes(pokemon.status) || - (pokemon.hasAbility('truant') && pokemon.truantTurn)) return; - if (pokemon.isAlly(target)) return; - target.addVolatile('pursuit'); - const data = target.volatiles['pursuit']; - if (!data.sources) { - data.sources = []; - } - data.sources.push(pokemon); + pokemon.addVolatile('pursuit'); + pokemon.volatiles['pursuit'].targetLoc = pokemon.getLocOf(target); + }, + condition: { + duration: 1, + onFoeBeforeSwitchOut(pokemon) { + const source: Pokemon = this.effectState.source; + this.debug('Pursuit start'); + if (this.effectState.targetLoc !== source.getLocOf(pokemon) || + ['frz', 'slp'].includes(source.status) || (source.hasAbility('truant') && source.truantTurn) || + !source.isAdjacent(pokemon) || !source.hp || ( + source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit' + ) || !this.queue.cancelMove(source)) return; + // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. + // If it is, then Mega Evolve before moving. + if (source.canMegaEvo || source.canUltraBurst) { + for (const [actionIndex, action] of this.queue.entries()) { + if (action.pokemon === source && action.choice === 'megaEvo') { + this.actions.runMegaEvo(source); + this.queue.list.splice(actionIndex, 1); + break; + } + } + } + const move = this.dex.getActiveMove('pursuit'); + source.deductPP(move.id); + source.moveUsed(move, pokemon.position); + if (this.actions.useMove(move, source, { target: pokemon }) && source.getItem().isChoice) { + source.addVolatile('choicelock'); + } + }, }, }, recover: { diff --git a/data/mods/gen4/moves.ts b/data/mods/gen4/moves.ts index 1e5db1ae5e..62848722d7 100644 --- a/data/mods/gen4/moves.ts +++ b/data/mods/gen4/moves.ts @@ -477,9 +477,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { } this.effectState.move = target.lastMove.id; this.add('-start', target, 'Encore'); + if (this.effectState.move === 'pursuit') target.addVolatile('pursuit', target); }, - onOverrideAction(pokemon) { - return this.effectState.move; + onOverrideAction(pokemon, target, move) { + if (move.id !== this.effectState.move) return this.effectState.move; }, onResidualOrder: 10, onResidualSubOrder: 14, @@ -1332,45 +1333,31 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { }, pursuit: { inherit: true, - beforeTurnCallback(pokemon) { - if (['frz', 'slp'].includes(pokemon.status) || - (pokemon.hasAbility('truant') && pokemon.volatiles['truant'])) return; - for (const target of pokemon.foes()) { - target.addVolatile('pursuit'); - const data = target.volatiles['pursuit']; - if (!data.sources) { - data.sources = []; - } - data.sources.push(pokemon); - } - }, condition: { duration: 1, - onBeforeSwitchOut(pokemon) { + onFoeBeforeSwitchOut(pokemon) { + const source: Pokemon = this.effectState.source; this.debug('Pursuit start'); - let alreadyAdded = false; - for (const source of this.effectState.sources) { - if (!this.queue.cancelMove(source) || !source.hp) continue; - if (!alreadyAdded) { - this.add('-activate', pokemon, 'move: Pursuit'); - alreadyAdded = true; - } - // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. - // If it is, then Mega Evolve before moving. - if (source.canMegaEvo || source.canUltraBurst) { - for (const [actionIndex, action] of this.queue.entries()) { - if (action.pokemon === source && action.choice === 'megaEvo') { - this.actions.runMegaEvo(source); - this.queue.list.splice(actionIndex, 1); - break; - } + if (['frz', 'slp'].includes(source.status) || (source.hasAbility('truant') && source.volatiles['truant']) || + !source.isAdjacent(pokemon) || !source.hp || ( + source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit' + ) || !this.queue.cancelMove(source)) return; + // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. + // If it is, then Mega Evolve before moving. + if (source.canMegaEvo || source.canUltraBurst) { + for (const [actionIndex, action] of this.queue.entries()) { + if (action.pokemon === source && action.choice === 'megaEvo') { + this.actions.runMegaEvo(source); + this.queue.list.splice(actionIndex, 1); + break; } } - const move = this.dex.getActiveMove('pursuit'); - source.moveUsed(move, pokemon.position); - if (this.actions.useMove(move, source, { target: pokemon }) && source.getItem().isChoice) { - source.addVolatile('choicelock'); - } + } + const move = this.dex.getActiveMove('pursuit'); + source.deductPP(move.id); + source.moveUsed(move, pokemon.position); + if (this.actions.useMove(move, source, { target: pokemon }) && source.getItem().isChoice) { + source.addVolatile('choicelock'); } }, }, diff --git a/data/moves.ts b/data/moves.ts index 8004f48dfb..dfde9d94c3 100644 --- a/data/moves.ts +++ b/data/moves.ts @@ -14913,51 +14913,43 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { pp: 20, priority: 0, flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 }, - beforeTurnCallback(pokemon) { - for (const target of pokemon.foes()) { - target.addVolatile('pursuit'); - const data = target.volatiles['pursuit']; - if (!data.sources) { - data.sources = []; - } - data.sources.push(pokemon); - } + beforeTurnCallback(pokemon, target) { + pokemon.addVolatile('pursuit'); }, onModifyMove(move, source, target) { - if (target?.beingCalledBack || target?.switchFlag) move.accuracy = true; + if (target?.beingCalledBack || target?.switchFlag) { + move.accuracy = true; + move.tracksTarget = true; + } }, condition: { duration: 1, - onBeforeSwitchOut(pokemon) { + onFoeBeforeSwitchOut(pokemon) { + const source: Pokemon = this.effectState.source; this.debug('Pursuit start'); - let alreadyAdded = false; - pokemon.removeVolatile('destinybond'); - for (const source of this.effectState.sources) { - if (!source.isAdjacent(pokemon) || !this.queue.cancelMove(source) || !source.hp) continue; - if (!alreadyAdded) { - this.add('-activate', pokemon, 'move: Pursuit'); - alreadyAdded = true; - } - // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. - // If it is, then Mega Evolve before moving. - if (source.canMegaEvo || source.canUltraBurst || source.canTerastallize) { - for (const [actionIndex, action] of this.queue.entries()) { - if (action.pokemon === source) { - if (action.choice === 'megaEvo') { - this.actions.runMegaEvo(source); - } else if (action.choice === 'terastallize') { - // Also a "forme" change that happens before moves, though only possible in NatDex - this.actions.terastallize(source); - } else { - continue; - } - this.queue.list.splice(actionIndex, 1); - break; + if (!source.isAdjacent(pokemon) || !source.hp || ( + source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit' + ) || !this.queue.cancelMove(source)) return; + // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. + // If it is, then Mega Evolve before moving. + if (source.canMegaEvo || source.canUltraBurst || source.canTerastallize) { + for (const [actionIndex, action] of this.queue.entries()) { + if (action.pokemon === source) { + if (action.choice === 'megaEvo') { + this.actions.runMegaEvo(source); + } else if (action.choice === 'terastallize') { + // Also a "forme" change that happens before moves, though only possible in NatDex + this.actions.terastallize(source); + } else { + continue; } + this.queue.list.splice(actionIndex, 1); + break; } } - this.actions.runMove('pursuit', source, source.getLocOf(pokemon)); } + pokemon.removeVolatile('destinybond'); + this.actions.runMove('pursuit', source, source.getLocOf(pokemon), { sourceEffect: this.effect }); }, }, secondary: null, diff --git a/sim/pokemon.ts b/sim/pokemon.ts index 418bdc3bd2..9af5702fb9 100644 --- a/sim/pokemon.ts +++ b/sim/pokemon.ts @@ -815,7 +815,7 @@ export class Pokemon { !(move.id.startsWith('solarb') && ['sunnyday', 'desolateland'].includes(this.effectiveWeather())) && !(move.id === 'electroshot' && ['raindance', 'primordialsea'].includes(this.effectiveWeather())) && !(this.hasItem('powerherb') && move.id !== 'skydrop'); - if (!isCharging && !(move.id === 'pursuit' && (target.beingCalledBack || target.switchFlag))) { + if (!isCharging) { target = this.battle.priorityEvent('RedirectTarget', this, this, move, target); } } diff --git a/test/sim/moves/pursuit.js b/test/sim/moves/pursuit.js index f3d634df71..797b851f14 100644 --- a/test/sim/moves/pursuit.js +++ b/test/sim/moves/pursuit.js @@ -190,6 +190,44 @@ describe(`Pursuit`, () => { assert.fullHP(jolteon); }); + it(`should not activate if Encored into Pursuit`, () => { + battle = common.createBattle({ gameType: 'doubles' }, [[ + { species: "Empoleon", moves: ['tackle', 'pursuit'] }, + { species: "Carnivine", moves: ['sleeptalk'] }, + ], [ + { species: "Deoxys", moves: ['sleeptalk', 'encore'] }, + { species: "Infernape", moves: ['sleeptalk', 'uturn'] }, + { species: "Carnivine", moves: ['sleeptalk'] }, + ]]); + const [deoxys, infernape] = battle.p2.active; + battle.makeChoices('move pursuit 1, move sleeptalk', 'move sleeptalk, move sleeptalk'); + deoxys.hp = deoxys.maxhp; + battle.makeChoices('move tackle 1, move sleeptalk', 'move encore 1, move uturn 2'); + assert.fullHP(deoxys); + assert.fullHP(infernape); + battle.makeChoices('', 'switch 3'); + assert.false.fullHP(deoxys); + }); + + it(`should not activate other move if Encored out of Pursuit`, () => { + battle = common.createBattle({ gameType: 'doubles' }, [[ + { species: "Empoleon", moves: ['tackle', 'pursuit'] }, + { species: "Carnivine", moves: ['sleeptalk'] }, + ], [ + { species: "Deoxys", moves: ['sleeptalk', 'encore'] }, + { species: "Infernape", moves: ['sleeptalk', 'uturn'] }, + { species: "Carnivine", moves: ['sleeptalk'] }, + ]]); + const [deoxys, infernape] = battle.p2.active; + battle.makeChoices('move tackle 1, move sleeptalk', 'move sleeptalk, move sleeptalk'); + deoxys.hp = deoxys.maxhp; + battle.makeChoices('move pursuit 1, move sleeptalk', 'move encore 1, move uturn 2'); + assert.fullHP(deoxys); + assert.fullHP(infernape); + battle.makeChoices('', 'switch 3'); + assert.false.fullHP(deoxys); + }); + describe(`[Gen 4]`, () => { it(`should continue the switch`, () => { battle = common.gen(4).createBattle([[ @@ -233,6 +271,44 @@ describe(`Pursuit`, () => { battle.makeChoices('move pursuit', 'switch 2'); assert.false.fullHP(jolteon); }); + + it(`should activate if Encored into Pursuit`, () => { + battle = common.gen(4).createBattle({ gameType: 'doubles' }, [[ + { species: "Empoleon", moves: ['tackle', 'pursuit'] }, + { species: "Carnivine", moves: ['sleeptalk'] }, + ], [ + { species: "Deoxys", moves: ['sleeptalk', 'encore'] }, + { species: "Infernape", moves: ['sleeptalk', 'uturn'] }, + { species: "Carnivine", moves: ['sleeptalk'] }, + ]]); + const [deoxys, infernape] = battle.p2.active; + battle.makeChoices('move pursuit 1, move sleeptalk', 'move sleeptalk, move sleeptalk'); + deoxys.hp = deoxys.maxhp; + battle.makeChoices('move tackle 1, move sleeptalk', 'move encore 1, move uturn 2'); + assert.fullHP(deoxys); + assert.false.fullHP(infernape); + battle.makeChoices('', 'switch 3'); + assert.fullHP(deoxys); + }); + + it(`should not activate other move if Encored out of Pursuit`, () => { + battle = common.gen(4).createBattle({ gameType: 'doubles' }, [[ + { species: "Empoleon", moves: ['tackle', 'pursuit'] }, + { species: "Carnivine", moves: ['sleeptalk'] }, + ], [ + { species: "Deoxys", moves: ['sleeptalk', 'encore'] }, + { species: "Infernape", moves: ['sleeptalk', 'uturn'] }, + { species: "Carnivine", moves: ['sleeptalk'] }, + ]]); + const [deoxys, infernape] = battle.p2.active; + battle.makeChoices('move tackle 1, move sleeptalk', 'move sleeptalk, move sleeptalk'); + deoxys.hp = deoxys.maxhp; + battle.makeChoices('move pursuit 1, move sleeptalk', 'move encore 1, move uturn 2'); + assert.fullHP(deoxys); + assert.fullHP(infernape); + battle.makeChoices('', 'switch 3'); + assert.false.fullHP(deoxys); + }); }); describe(`[Gen 3]`, () => { From 5f502b77dcf9b81e2e84f330ff081cb6b981d4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= <80102738+andrebastosdias@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:37:09 +0000 Subject: [PATCH 2/3] Reformat code --- data/mods/gen2/moves.ts | 6 +++--- data/mods/gen3/moves.ts | 6 +++--- data/mods/gen4/moves.ts | 6 +++--- data/moves.ts | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/data/mods/gen2/moves.ts b/data/mods/gen2/moves.ts index 10c2f63483..dd731742ac 100644 --- a/data/mods/gen2/moves.ts +++ b/data/mods/gen2/moves.ts @@ -581,9 +581,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { const source: Pokemon = this.effectState.source; this.debug('Pursuit start'); if (this.effectState.targetLoc !== source.getLocOf(pokemon) || - !source.isAdjacent(pokemon) || !source.hp || ( - source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit' - ) || !this.queue.cancelMove(source)) return; + !source.isAdjacent(pokemon) || !source.hp || + (source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit') || + !this.queue.cancelMove(source)) return; // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. // If it is, then Mega Evolve before moving. if (source.canMegaEvo || source.canUltraBurst) { diff --git a/data/mods/gen3/moves.ts b/data/mods/gen3/moves.ts index 2cfab2b5c2..a40aac6997 100644 --- a/data/mods/gen3/moves.ts +++ b/data/mods/gen3/moves.ts @@ -592,9 +592,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { this.debug('Pursuit start'); if (this.effectState.targetLoc !== source.getLocOf(pokemon) || ['frz', 'slp'].includes(source.status) || (source.hasAbility('truant') && source.truantTurn) || - !source.isAdjacent(pokemon) || !source.hp || ( - source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit' - ) || !this.queue.cancelMove(source)) return; + !source.isAdjacent(pokemon) || !source.hp || + (source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit') || + !this.queue.cancelMove(source)) return; // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. // If it is, then Mega Evolve before moving. if (source.canMegaEvo || source.canUltraBurst) { diff --git a/data/mods/gen4/moves.ts b/data/mods/gen4/moves.ts index 2a01f12966..feed9f4298 100644 --- a/data/mods/gen4/moves.ts +++ b/data/mods/gen4/moves.ts @@ -1338,9 +1338,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { const source: Pokemon = this.effectState.source; this.debug('Pursuit start'); if (['frz', 'slp'].includes(source.status) || (source.hasAbility('truant') && source.volatiles['truant']) || - !source.isAdjacent(pokemon) || !source.hp || ( - source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit' - ) || !this.queue.cancelMove(source)) return; + !source.isAdjacent(pokemon) || !source.hp || + (source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit') || + !this.queue.cancelMove(source)) return; // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. // If it is, then Mega Evolve before moving. if (source.canMegaEvo || source.canUltraBurst) { diff --git a/data/moves.ts b/data/moves.ts index dfde9d94c3..cff83bc491 100644 --- a/data/moves.ts +++ b/data/moves.ts @@ -14927,9 +14927,9 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { onFoeBeforeSwitchOut(pokemon) { const source: Pokemon = this.effectState.source; this.debug('Pursuit start'); - if (!source.isAdjacent(pokemon) || !source.hp || ( - source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit' - ) || !this.queue.cancelMove(source)) return; + if (!source.isAdjacent(pokemon) || !source.hp || + (source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit') || + !this.queue.cancelMove(source)) return; // Run through each action in queue to check if the Pursuit user is supposed to Mega Evolve this turn. // If it is, then Mega Evolve before moving. if (source.canMegaEvo || source.canUltraBurst || source.canTerastallize) { From 532d295dd2b02908eb253644b684fbdabd03ae9c Mon Sep 17 00:00:00 2001 From: andrebastosdias Date: Thu, 19 Mar 2026 20:45:45 +0000 Subject: [PATCH 3/3] Use Truant volatile in Gen 3 --- data/mods/gen3/abilities.ts | 11 +++++++++++ data/mods/gen3/moves.ts | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/data/mods/gen3/abilities.ts b/data/mods/gen3/abilities.ts index ebb37c42d0..b23357fffe 100644 --- a/data/mods/gen3/abilities.ts +++ b/data/mods/gen3/abilities.ts @@ -205,6 +205,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa onStart() {}, onSwitchIn(pokemon) { pokemon.truantTurn = this.turn !== 0; + // it is unnecessary to keep a volatile, but it helps with cross-gen implementation + if (pokemon.truantTurn) { + pokemon.addVolatile('truant'); + } else { + pokemon.removeVolatile('truant'); + } }, onBeforeMove(pokemon) { if (pokemon.truantTurn) { @@ -215,6 +221,11 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa onResidualOrder: 27, onResidual(pokemon) { pokemon.truantTurn = !pokemon.truantTurn; + if (pokemon.truantTurn) { + pokemon.addVolatile('truant'); + } else { + pokemon.removeVolatile('truant'); + } }, }, voltabsorb: { diff --git a/data/mods/gen3/moves.ts b/data/mods/gen3/moves.ts index 4daf02cda6..7c0491b104 100644 --- a/data/mods/gen3/moves.ts +++ b/data/mods/gen3/moves.ts @@ -488,7 +488,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { const source: Pokemon = this.effectState.source; this.debug('Pursuit start'); if (this.effectState.targetLoc !== source.getLocOf(pokemon) || - ['frz', 'slp'].includes(source.status) || (source.hasAbility('truant') && source.truantTurn) || + ['frz', 'slp'].includes(source.status) || (source.hasAbility('truant') && source.volatiles['truant']) || !source.isAdjacent(pokemon) || !source.hp || (source.volatiles['encore'] && source.volatiles['encore'].move !== 'pursuit') || !this.queue.cancelMove(source)) return;