diff --git a/data/mods/gen4/items.ts b/data/mods/gen4/items.ts index 336dc8a778..0651f08cd2 100644 --- a/data/mods/gen4/items.ts +++ b/data/mods/gen4/items.ts @@ -82,6 +82,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = { this.queue.insertChoice({ choice: 'event', event: 'Custap', + order: action.order, priority: action.priority + 0.1, pokemon: action.pokemon, move: action.move, diff --git a/data/mods/gen7/moves.ts b/data/mods/gen7/moves.ts index 5a9fa8c69e..26e9f081c5 100644 --- a/data/mods/gen7/moves.ts +++ b/data/mods/gen7/moves.ts @@ -747,24 +747,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { inherit: true, isNonstandard: null, }, - quash: { - inherit: true, - onHit(target) { - if (this.activePerHalf === 1) return false; // fails in singles - const action = this.queue.willMove(target); - if (!action) return false; - - action.priority = -7.1; - this.queue.cancelMove(target); - for (let i = this.queue.list.length - 1; i >= 0; i--) { - if (this.queue.list[i].choice === 'residual') { - this.queue.list.splice(i, 0, action); - break; - } - } - this.add('-activate', target, 'move: Quash'); - }, - }, rage: { inherit: true, isNonstandard: null, diff --git a/data/moves.ts b/data/moves.ts index 9bf3581ce9..4c41863788 100644 --- a/data/moves.ts +++ b/data/moves.ts @@ -9650,7 +9650,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { pp: 15, priority: 0, flags: { protect: 1, bypasssub: 1, allyanim: 1, failinstruct: 1 }, - onHit(target, source) { + onHit(target, source, move) { if (!target.lastMove || target.volatiles['dynamax']) return false; const lastMove = target.lastMove; const moveSlot = target.getMoveData(lastMove.id); @@ -9668,7 +9668,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { pokemon: target, moveid: target.lastMove.id, targetLoc: target.lastMoveTargetLoc!, - })[0] as MoveAction); + })[0] as MoveAction, move); }, target: "normal", type: "Psychic", @@ -14460,7 +14460,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { const action = this.queue.willMove(target); if (!action) return false; - action.order = 201; + this.queue.prioritizeAction(action, undefined, true); this.add('-activate', target, 'move: Quash'); }, target: "normal", @@ -15510,7 +15510,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { for (const action of this.queue.list as MoveAction[]) { if (!action.pokemon || !action.move || action.maxMove || action.zmove) continue; if (action.move.id === 'round') { - this.queue.prioritizeAction(action, move); + this.queue.prioritizeAction(action); return; } } diff --git a/sim/battle-queue.ts b/sim/battle-queue.ts index 59e5f80650..2678443310 100644 --- a/sim/battle-queue.ts +++ b/sim/battle-queue.ts @@ -25,7 +25,7 @@ import type { Battle } from './battle'; export interface MoveAction { /** action type */ choice: 'move' | 'beforeTurnMove' | 'priorityChargeMove'; - order: 3 | 5 | 200 | 201 | 199 | 106; + order: 5 | 105 | 199 | 200 | 201; /** priority of the action (higher first) */ priority: number; /** fractional priority of the action (higher first) */ @@ -56,7 +56,7 @@ export interface MoveAction { export interface SwitchAction { /** action type */ choice: 'switch' | 'instaswitch' | 'revivalblessing'; - order: 3 | 6 | 103; + order: 3 | 6 | 101; /** priority of the action (higher first) */ priority: number; /** speed of pokemon switching (higher first if priority tie) */ @@ -73,6 +73,7 @@ export interface SwitchAction { export interface TeamAction { /** action type */ choice: 'team'; + order: 1; /** priority of the action (higher first) */ priority: number; /** unused for this action type */ @@ -87,6 +88,7 @@ export interface TeamAction { export interface FieldAction { /** action type */ choice: 'start' | 'residual' | 'pass' | 'beforeTurn'; + order: 2 | 4 | 300; /** priority of the action (higher first) */ priority: number; /** unused for this action type */ @@ -99,6 +101,7 @@ export interface FieldAction { export interface PokemonAction { /** action type */ choice: 'megaEvo' | 'megaEvoX' | 'megaEvoY' | 'shift' | 'runSwitch' | 'event' | 'runDynamax' | 'terastallize'; + order: 100 | 102 | 103 | 104 | 200 | number; /** priority of the action (higher first) */ priority: number; /** speed of pokemon doing action (higher first if priority tie) */ @@ -133,6 +136,26 @@ export interface ActionChoice { export class BattleQueue { battle: Battle; list: Action[]; + readonly orders: { [choice: string]: number } = { + team: 1, + start: 2, + instaswitch: 3, + beforeTurn: 4, + beforeTurnMove: 5, + revivalblessing: 6, + + runSwitch: 100, + switch: 101, + megaEvo: 102, megaEvoX: 102, megaEvoY: 102, + runDynamax: 103, + terastallize: 104, + priorityChargeMove: 105, + + shift: 200, + move: 200, + + residual: 300, + }; constructor(battle: Battle) { this.battle = battle; this.list = []; @@ -171,35 +194,9 @@ export class BattleQueue { if (!action.side && action.pokemon) action.side = action.pokemon.side; if (!action.move && action.moveid) action.move = this.battle.dex.getActiveMove(action.moveid); if (!action.order) { - const orders: { [choice: string]: number } = { - team: 1, - start: 2, - instaswitch: 3, - beforeTurn: 4, - beforeTurnMove: 5, - revivalblessing: 6, - - runSwitch: 101, - switch: 103, - megaEvo: 104, - megaEvoX: 104, - megaEvoY: 104, - runDynamax: 105, - terastallize: 106, - priorityChargeMove: 107, - - shift: 200, - // default is 200 (for moves) - - residual: 300, - }; - if (action.choice in orders) { - action.order = orders[action.choice]; - } else { - action.order = 200; - if (!['move', 'event'].includes(action.choice)) { - throw new Error(`Unexpected orderless action ${action.choice}`); - } + action.order = this.orders[action.choice]; + if (!action.order) { + throw new Error(`Unexpected orderless action ${action.choice}`); } } if (!midTurn) { @@ -274,7 +271,7 @@ export class BattleQueue { /** * Makes the passed action happen next (skipping speed order). */ - prioritizeAction(action: MoveAction | SwitchAction, sourceEffect?: Effect) { + prioritizeAction(action: MoveAction, sourceEffect?: Effect, decreasePriority = false) { for (const [i, curAction] of this.list.entries()) { if (curAction === action) { this.list.splice(i, 1); @@ -282,8 +279,18 @@ export class BattleQueue { } } action.sourceEffect = sourceEffect; - action.order = 3; - this.list.unshift(action); + action.order = decreasePriority ? 201 : 199; + + // before Gen 8, prioritization follows insertion order + // in Gens 8+, the queue is sorted after every action + for (const [i, curAction] of this.list.entries()) { + if ((!decreasePriority && curAction.order >= action.order) || + (decreasePriority && curAction.order > action.order)) { + this.list.splice(i, 0, action); + return; + } + } + this.list.push(action); } /** diff --git a/sim/global-types.ts b/sim/global-types.ts index 4b18ade384..1e1ba31cde 100644 --- a/sim/global-types.ts +++ b/sim/global-types.ts @@ -348,6 +348,7 @@ interface ModdedBattlePokemon { interface ModdedBattleQueue extends Partial { inherit?: true; + orders?: { [choice: string]: number }; resolveAction?: (this: BattleQueue, action: ActionChoice, midTurn?: boolean) => Action[]; }