From 9a4381c7766482b3996d29ced5dfe79dc8fed2f4 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:58:06 -0700 Subject: [PATCH 1/5] Re-Add MovePriorityModifier --- src/data/abilities/ability.ts | 25 +++++++++++++++++++++++-- src/data/moves/move.ts | 13 ++++++++----- src/data/terrain.ts | 2 +- src/enums/move-priority-modifier.ts | 13 +++++++++++++ src/queues/move-phase-priority-queue.ts | 7 +++++++ test/arena/psychic-terrain.test.ts | 4 ++-- 6 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 src/enums/move-priority-modifier.ts diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 301016d899b..180ba0f3e90 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -34,6 +34,7 @@ import { MoveCategory } from "#enums/move-category"; import { MoveFlags } from "#enums/move-flags"; import { MoveId } from "#enums/move-id"; import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier"; +import { MovePriorityModifier } from "#enums/move-priority-modifier"; import { MoveResult } from "#enums/move-result"; import { MoveTarget } from "#enums/move-target"; import { MoveUseMode } from "#enums/move-use-mode"; @@ -4142,6 +4143,25 @@ export class ChangeMovePriorityAbAttr extends AbAttr { } } +export class ChangeMovePriorityModifierAbAttr extends AbAttr { + private readonly newModifier: MovePriorityModifier; + private readonly moveFunc: (pokemon: Pokemon, move: Move) => boolean; + + constructor(moveFunc: (pokemon: Pokemon, move: Move) => boolean, newModifier: MovePriorityModifier) { + super(false); + this.newModifier = newModifier; + this.moveFunc = moveFunc; + } + + override canApply({ pokemon, move }: ChangeMovePriorityAbAttrParams): boolean { + return this.moveFunc(pokemon, move); + } + + override apply({ priority }: ChangeMovePriorityAbAttrParams): void { + priority.value = this.newModifier; + } +} + export class IgnoreContactAbAttr extends AbAttr { private declare readonly _: never; } @@ -6721,6 +6741,7 @@ const AbilityAttrs = Object.freeze({ BlockStatusDamageAbAttr, BlockOneHitKOAbAttr, ChangeMovePriorityAbAttr, + ChangeMovePriorityModifierAbAttr, IgnoreContactAbAttr, PreWeatherEffectAbAttr, PreWeatherDamageAbAttr, @@ -7238,7 +7259,7 @@ export function initAbilities() { .attr(DoubleBattleChanceAbAttr) .build(), new AbBuilder(AbilityId.STALL, 4) - .attr(ChangeMovePriorityAbAttr, (_pokemon, _move: Move) => true, -0.2) + .attr(ChangeMovePriorityModifierAbAttr, (_pokemon, _move: Move) => true, MovePriorityModifier.LAST_IN_BRACKET) .build(), new AbBuilder(AbilityId.TECHNICIAN, 4) .attr(MovePowerBoostAbAttr, (user, target, move) => { @@ -8185,7 +8206,7 @@ export function initAbilities() { .ignorable() .build(), new AbBuilder(AbilityId.MYCELIUM_MIGHT, 9) - .attr(ChangeMovePriorityAbAttr, (_pokemon, move) => move.category === MoveCategory.STATUS, -0.2) + .attr(ChangeMovePriorityModifierAbAttr, (_pokemon, move) => move.category === MoveCategory.STATUS, MovePriorityModifier.LAST_IN_BRACKET) .attr(PreventBypassSpeedChanceAbAttr, (_pokemon, move) => move.category === MoveCategory.STATUS) .attr(MoveAbilityBypassAbAttr, (_pokemon, move: Move) => move.category === MoveCategory.STATUS) .build(), diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index b32ed6bbee4..44240d7e358 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -101,6 +101,7 @@ import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier"; import { inSpeedOrder } from "#utils/speed-order-generator"; import { canSpeciesTera, willTerastallize } from "#utils/pokemon-utils"; import type { ReadonlyGenericUint8Array } from "#types/typed-arrays"; +import { MovePriorityModifier } from "#enums/move-priority-modifier"; /** * A function used to conditionally determine execution of a given {@linkcode MoveAttr}. @@ -1060,17 +1061,19 @@ export abstract class Move implements Localizable { getPriority(user: Pokemon, simulated: boolean = true) { const priority = new NumberHolder(this.priority); - applyMoveAttrs("IncrementMovePriorityAttr", user, null, this, priority); applyAbAttrs("ChangeMovePriorityAbAttr", {pokemon: user, simulated, move: this, priority}); - if (user.getTag(BattlerTagType.BYPASS_SPEED)) { - priority.value += 0.2; - } - return priority.value; } + public getPriorityModifier(user: Pokemon, simulated = true) { + const modifierHolder = new NumberHolder(MovePriorityModifier.NORMAL); + applyAbAttrs("ChangeMovePriorityModifierAbAttr", {pokemon: user, simulated: simulated, move: this, priority: modifierHolder}); + modifierHolder.value = user.getTag(BattlerTagType.BYPASS_SPEED) ? MovePriorityModifier.FIRST_IN_BRACKET : modifierHolder.value; + return modifierHolder.value; + } + /** * Calculate the [Expected Power](https://en.wikipedia.org/wiki/Expected_value) per turn * of this move, taking into account multi hit moves, accuracy, and the number of turns it diff --git a/src/data/terrain.ts b/src/data/terrain.ts index bd90f3985b4..54b5aeffb6a 100644 --- a/src/data/terrain.ts +++ b/src/data/terrain.ts @@ -67,7 +67,7 @@ export class Terrain { return ( !isFieldTargeted(move) && !isSpreadMove(move) - && move.getPriority(user) > 0.2 // fractional priority is used by quick claw etc and is not blocked by terrain + && move.getPriority(user) > 0 && user.getOpponents(true).some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()) ); } diff --git a/src/enums/move-priority-modifier.ts b/src/enums/move-priority-modifier.ts new file mode 100644 index 00000000000..3e51aaec0a3 --- /dev/null +++ b/src/enums/move-priority-modifier.ts @@ -0,0 +1,13 @@ +import type { ObjectValues } from "#types/type-helpers"; + +/** + * Enum representing modifiers for Move priorities. + */ +export const MovePriorityModifier = Object.freeze({ + /** Used when moves go last in their priority bracket, but before moves of lower priority. */ + LAST_IN_BRACKET: 0, + NORMAL: 1, + /** Used when moves go first in their priority bracket, but before moves of lower priority. */ + FIRST_IN_BRACKET: 2, +}); +export type MovePriorityModifier = ObjectValues; diff --git a/src/queues/move-phase-priority-queue.ts b/src/queues/move-phase-priority-queue.ts index 5f0b20c3c2e..a30162158f3 100644 --- a/src/queues/move-phase-priority-queue.ts +++ b/src/queues/move-phase-priority-queue.ts @@ -92,11 +92,18 @@ export class MovePhasePriorityQueue extends PokemonPhasePriorityQueue }); const timingModifiers = [a, b].map(movePhase => movePhase.timingModifier); + const priorityModifiers = [a, b].map(movePhase => + movePhase.move.getMove().getPriorityModifier(movePhase.pokemon), + ); if (timingModifiers[0] !== timingModifiers[1]) { return timingModifiers[1] - timingModifiers[0]; } + if (priority[0] === priority[1] && priorityModifiers[0] !== priorityModifiers[1]) { + return priorityModifiers[1] - priorityModifiers[0]; + } + return priority[1] - priority[0]; }); } diff --git a/test/arena/psychic-terrain.test.ts b/test/arena/psychic-terrain.test.ts index 6112db41cd8..9e1e5fc9d8e 100644 --- a/test/arena/psychic-terrain.test.ts +++ b/test/arena/psychic-terrain.test.ts @@ -72,7 +72,7 @@ describe("Arena - Psychic Terrain", () => { await game.phaseInterceptor.to("MovePhase", false); const feebas = game.field.getPlayerPokemon(); - expect(allMoves[MoveId.POUND].getPriority(feebas)).toBe(0.2); + expect(allMoves[MoveId.POUND].getPriority(feebas)).toBe(0); await game.toEndOfTurn(); @@ -93,7 +93,7 @@ describe("Arena - Psychic Terrain", () => { await game.phaseInterceptor.to("MovePhase", false); const feebas = game.field.getPlayerPokemon(); - expect(allMoves[MoveId.QUICK_ATTACK].getPriority(feebas)).toBe(1.2); + expect(allMoves[MoveId.QUICK_ATTACK].getPriority(feebas)).toBe(1); await game.toEndOfTurn(); From 6bda024b7eb07bd2207502ed1895e19ffa81e989 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Fri, 31 Oct 2025 13:10:11 -0700 Subject: [PATCH 2/5] Only run speed bypass code for fight commands --- src/phases/turn-start-phase.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index 1f1b78af0ad..c9774c5873a 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -69,6 +69,10 @@ export class TurnStartPhase extends FieldPhase { const phaseManager = globalScene.phaseManager; for (const pokemon of inSpeedOrder(ArenaTagSide.BOTH)) { + if (globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()]?.command !== Command.FIGHT) { + continue; + } + applyAbAttrs("BypassSpeedChanceAbAttr", { pokemon }); globalScene.applyModifiers(BypassSpeedChanceModifier, pokemon.isPlayer(), pokemon); } From 5c8c2151a834077f3bb4c8bf4cd6653c056c992f Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:58:35 -0700 Subject: [PATCH 3/5] Update src/data/moves/move.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/moves/move.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 44240d7e358..43baf361d5e 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -1068,9 +1068,11 @@ export abstract class Move implements Localizable { } public getPriorityModifier(user: Pokemon, simulated = true) { + if (user.getTag(BattlerTagType.BYPASS_SPEED)) { + return MovePriorityModifier.FIRST_IN_BRACKET; + } const modifierHolder = new NumberHolder(MovePriorityModifier.NORMAL); - applyAbAttrs("ChangeMovePriorityModifierAbAttr", {pokemon: user, simulated: simulated, move: this, priority: modifierHolder}); - modifierHolder.value = user.getTag(BattlerTagType.BYPASS_SPEED) ? MovePriorityModifier.FIRST_IN_BRACKET : modifierHolder.value; + applyAbAttrs("ChangeMovePriorityModifierAbAttr", { pokemon: user, simulated, move: this, priority: modifierHolder }); return modifierHolder.value; } From c33f9723f543ccb0693b7fc6966ea406da2c1f86 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Fri, 31 Oct 2025 16:21:38 -0700 Subject: [PATCH 4/5] Update enum name --- src/data/abilities/ability.ts | 14 +++++++------- src/data/moves/move.ts | 8 ++++---- src/enums/move-priority-modifier.ts | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 180ba0f3e90..d3c646b9321 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -34,7 +34,7 @@ import { MoveCategory } from "#enums/move-category"; import { MoveFlags } from "#enums/move-flags"; import { MoveId } from "#enums/move-id"; import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier"; -import { MovePriorityModifier } from "#enums/move-priority-modifier"; +import { MovePriorityInBracket } from "#enums/move-priority-modifier"; import { MoveResult } from "#enums/move-result"; import { MoveTarget } from "#enums/move-target"; import { MoveUseMode } from "#enums/move-use-mode"; @@ -4143,11 +4143,11 @@ export class ChangeMovePriorityAbAttr extends AbAttr { } } -export class ChangeMovePriorityModifierAbAttr extends AbAttr { - private readonly newModifier: MovePriorityModifier; +export class ChangeMovePriorityInBracketAbAttr extends AbAttr { + private readonly newModifier: MovePriorityInBracket; private readonly moveFunc: (pokemon: Pokemon, move: Move) => boolean; - constructor(moveFunc: (pokemon: Pokemon, move: Move) => boolean, newModifier: MovePriorityModifier) { + constructor(moveFunc: (pokemon: Pokemon, move: Move) => boolean, newModifier: MovePriorityInBracket) { super(false); this.newModifier = newModifier; this.moveFunc = moveFunc; @@ -6741,7 +6741,7 @@ const AbilityAttrs = Object.freeze({ BlockStatusDamageAbAttr, BlockOneHitKOAbAttr, ChangeMovePriorityAbAttr, - ChangeMovePriorityModifierAbAttr, + ChangeMovePriorityInBracketAbAttr, IgnoreContactAbAttr, PreWeatherEffectAbAttr, PreWeatherDamageAbAttr, @@ -7259,7 +7259,7 @@ export function initAbilities() { .attr(DoubleBattleChanceAbAttr) .build(), new AbBuilder(AbilityId.STALL, 4) - .attr(ChangeMovePriorityModifierAbAttr, (_pokemon, _move: Move) => true, MovePriorityModifier.LAST_IN_BRACKET) + .attr(ChangeMovePriorityInBracketAbAttr, (_pokemon, _move: Move) => true, MovePriorityInBracket.LAST) .build(), new AbBuilder(AbilityId.TECHNICIAN, 4) .attr(MovePowerBoostAbAttr, (user, target, move) => { @@ -8206,7 +8206,7 @@ export function initAbilities() { .ignorable() .build(), new AbBuilder(AbilityId.MYCELIUM_MIGHT, 9) - .attr(ChangeMovePriorityModifierAbAttr, (_pokemon, move) => move.category === MoveCategory.STATUS, MovePriorityModifier.LAST_IN_BRACKET) + .attr(ChangeMovePriorityInBracketAbAttr, (_pokemon, move) => move.category === MoveCategory.STATUS, MovePriorityInBracket.LAST) .attr(PreventBypassSpeedChanceAbAttr, (_pokemon, move) => move.category === MoveCategory.STATUS) .attr(MoveAbilityBypassAbAttr, (_pokemon, move: Move) => move.category === MoveCategory.STATUS) .build(), diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 43baf361d5e..417ae7c3b93 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -101,7 +101,7 @@ import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier"; import { inSpeedOrder } from "#utils/speed-order-generator"; import { canSpeciesTera, willTerastallize } from "#utils/pokemon-utils"; import type { ReadonlyGenericUint8Array } from "#types/typed-arrays"; -import { MovePriorityModifier } from "#enums/move-priority-modifier"; +import { MovePriorityInBracket } from "#enums/move-priority-modifier"; /** * A function used to conditionally determine execution of a given {@linkcode MoveAttr}. @@ -1069,10 +1069,10 @@ export abstract class Move implements Localizable { public getPriorityModifier(user: Pokemon, simulated = true) { if (user.getTag(BattlerTagType.BYPASS_SPEED)) { - return MovePriorityModifier.FIRST_IN_BRACKET; + return MovePriorityInBracket.FIRST; } - const modifierHolder = new NumberHolder(MovePriorityModifier.NORMAL); - applyAbAttrs("ChangeMovePriorityModifierAbAttr", { pokemon: user, simulated, move: this, priority: modifierHolder }); + const modifierHolder = new NumberHolder(MovePriorityInBracket.NORMAL); + applyAbAttrs("ChangeMovePriorityInBracketAbAttr", { pokemon: user, simulated, move: this, priority: modifierHolder }); return modifierHolder.value; } diff --git a/src/enums/move-priority-modifier.ts b/src/enums/move-priority-modifier.ts index 3e51aaec0a3..ea314fda0e4 100644 --- a/src/enums/move-priority-modifier.ts +++ b/src/enums/move-priority-modifier.ts @@ -3,11 +3,11 @@ import type { ObjectValues } from "#types/type-helpers"; /** * Enum representing modifiers for Move priorities. */ -export const MovePriorityModifier = Object.freeze({ +export const MovePriorityInBracket = Object.freeze({ /** Used when moves go last in their priority bracket, but before moves of lower priority. */ - LAST_IN_BRACKET: 0, + LAST: 0, NORMAL: 1, /** Used when moves go first in their priority bracket, but before moves of lower priority. */ - FIRST_IN_BRACKET: 2, + FIRST: 2, }); -export type MovePriorityModifier = ObjectValues; +export type MovePriorityInBracket = ObjectValues; From f928ca9bdf1d37c7e842df9bc2e9d74d6d02abe6 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Fri, 31 Oct 2025 16:23:57 -0700 Subject: [PATCH 5/5] Update enum filename --- src/data/abilities/ability.ts | 2 +- src/data/moves/move.ts | 2 +- .../{move-priority-modifier.ts => move-priority-in-bracket.ts} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/enums/{move-priority-modifier.ts => move-priority-in-bracket.ts} (100%) diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index d3c646b9321..90adcd86b5d 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -34,7 +34,7 @@ import { MoveCategory } from "#enums/move-category"; import { MoveFlags } from "#enums/move-flags"; import { MoveId } from "#enums/move-id"; import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier"; -import { MovePriorityInBracket } from "#enums/move-priority-modifier"; +import { MovePriorityInBracket } from "#enums/move-priority-in-bracket"; import { MoveResult } from "#enums/move-result"; import { MoveTarget } from "#enums/move-target"; import { MoveUseMode } from "#enums/move-use-mode"; diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 417ae7c3b93..8637c65966b 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -101,7 +101,7 @@ import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier"; import { inSpeedOrder } from "#utils/speed-order-generator"; import { canSpeciesTera, willTerastallize } from "#utils/pokemon-utils"; import type { ReadonlyGenericUint8Array } from "#types/typed-arrays"; -import { MovePriorityInBracket } from "#enums/move-priority-modifier"; +import { MovePriorityInBracket } from "#enums/move-priority-in-bracket"; /** * A function used to conditionally determine execution of a given {@linkcode MoveAttr}. diff --git a/src/enums/move-priority-modifier.ts b/src/enums/move-priority-in-bracket.ts similarity index 100% rename from src/enums/move-priority-modifier.ts rename to src/enums/move-priority-in-bracket.ts