mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-03-21 17:25:10 -05:00
Refactor Decision -> Action
"Decision" and "Choice" were always kind of unclear, so Decision is now Action. It should now be a lot clearer. Actions are also now strongly typed.
This commit is contained in:
parent
dc7c46b427
commit
f3dbfbe685
|
|
@ -303,7 +303,7 @@ In addition to room messages, battles have their own messages.
|
|||
|
||||
`|request|REQUEST`
|
||||
|
||||
> Gives a JSON object containing a request for a decision (to move or
|
||||
> Gives a JSON object containing a request for a choice (to move or
|
||||
> switch). To assist in your decision, `REQUEST.active` has information
|
||||
> about your active Pokémon, and `REQUEST.side` has information about your
|
||||
> your team as a whole.
|
||||
|
|
|
|||
|
|
@ -420,9 +420,9 @@ exports.BattleAbilities = {
|
|||
|
||||
if (target.side.active.length === 2 && target.position === 1) {
|
||||
// Curse Glitch
|
||||
const decision = this.willMove(target);
|
||||
if (decision && decision.move.id === 'curse') {
|
||||
decision.targetLoc = -1;
|
||||
const action = this.willMove(target);
|
||||
if (action && action.move.id === 'curse') {
|
||||
action.targetLoc = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,10 +285,10 @@ exports.BattleMovedex = {
|
|||
flags: {authentic: 1, mystery: 1},
|
||||
onHit: function (target) {
|
||||
if (target.side.active.length < 2) return false; // fails in singles
|
||||
let decision = this.willMove(target);
|
||||
if (decision) {
|
||||
let action = this.willMove(target);
|
||||
if (action) {
|
||||
this.cancelMove(target);
|
||||
this.queue.unshift(decision);
|
||||
this.queue.unshift(action);
|
||||
this.add('-activate', target, 'move: After You');
|
||||
} else {
|
||||
return false;
|
||||
|
|
@ -4415,7 +4415,7 @@ exports.BattleMovedex = {
|
|||
this.effectData.duration++;
|
||||
}
|
||||
},
|
||||
onOverrideDecision: function (pokemon, target, move) {
|
||||
onOverrideAction: function (pokemon, target, move) {
|
||||
if (move.id !== this.effectData.move) return this.effectData.move;
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
|
|
@ -5045,11 +5045,11 @@ exports.BattleMovedex = {
|
|||
flags: {protect: 1, mirror: 1, nonsky: 1},
|
||||
onPrepareHit: function (target, source, move) {
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
let decision = this.queue[i];
|
||||
if (!decision.move || !decision.pokemon || !decision.pokemon.isActive || decision.pokemon.fainted) continue;
|
||||
if (decision.pokemon.side === source.side && ['grasspledge', 'waterpledge'].includes(decision.move.id)) {
|
||||
this.prioritizeQueue(decision);
|
||||
this.add('-waiting', source, decision.pokemon);
|
||||
let action = this.queue[i];
|
||||
if (!action.move || !action.pokemon || !action.pokemon.isActive || action.pokemon.fainted) continue;
|
||||
if (action.pokemon.side === source.side && ['grasspledge', 'waterpledge'].includes(action.move.id)) {
|
||||
this.prioritizeAction(action);
|
||||
this.add('-waiting', source, action.pokemon);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -6461,11 +6461,11 @@ exports.BattleMovedex = {
|
|||
flags: {protect: 1, mirror: 1, nonsky: 1},
|
||||
onPrepareHit: function (target, source, move) {
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
let decision = this.queue[i];
|
||||
if (!decision.move || !decision.pokemon || !decision.pokemon.isActive || decision.pokemon.fainted) continue;
|
||||
if (decision.pokemon.side === source.side && ['waterpledge', 'firepledge'].includes(decision.move.id)) {
|
||||
this.prioritizeQueue(decision);
|
||||
this.add('-waiting', source, decision.pokemon);
|
||||
let action = this.queue[i];
|
||||
if (!action.move || !action.pokemon || !action.pokemon.isActive || action.pokemon.fainted) continue;
|
||||
if (action.pokemon.side === source.side && ['waterpledge', 'firepledge'].includes(action.move.id)) {
|
||||
this.prioritizeAction(action);
|
||||
this.add('-waiting', source, action.pokemon);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -9926,12 +9926,12 @@ exports.BattleMovedex = {
|
|||
priority: 0,
|
||||
flags: {protect: 1, authentic: 1},
|
||||
onTryHit: function (target, pokemon) {
|
||||
let decision = this.willMove(target);
|
||||
if (decision) {
|
||||
let action = this.willMove(target);
|
||||
if (action) {
|
||||
let noMeFirst = [
|
||||
'chatter', 'counter', 'covet', 'focuspunch', 'mefirst', 'metalburst', 'mirrorcoat', 'struggle', 'thief',
|
||||
];
|
||||
let move = this.getMoveCopy(decision.move.id);
|
||||
let move = this.getMoveCopy(action.move.id);
|
||||
if (move.category !== 'Status' && !noMeFirst.includes(move)) {
|
||||
pokemon.addVolatile('mefirst');
|
||||
this.useMove(move, pokemon, target);
|
||||
|
|
@ -12749,7 +12749,7 @@ exports.BattleMovedex = {
|
|||
this.add('-activate', pokemon, 'move: Pursuit');
|
||||
alreadyAdded = true;
|
||||
}
|
||||
// Run through each decision in queue to check if the Pursuit user is supposed to Mega Evolve this turn.
|
||||
// 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()) {
|
||||
|
|
@ -12784,13 +12784,13 @@ exports.BattleMovedex = {
|
|||
flags: {protect: 1, mirror: 1},
|
||||
onHit: function (target) {
|
||||
if (target.side.active.length < 2) return false; // fails in singles
|
||||
let decision = this.willMove(target);
|
||||
if (decision) {
|
||||
decision.priority = -7.1;
|
||||
let action = this.willMove(target);
|
||||
if (action) {
|
||||
action.priority = -7.1;
|
||||
this.cancelMove(target);
|
||||
for (let i = this.queue.length - 1; i >= 0; i--) {
|
||||
if (this.queue[i].choice === 'residual') {
|
||||
this.queue.splice(i, 0, decision);
|
||||
this.queue.splice(i, 0, action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -13842,10 +13842,10 @@ exports.BattleMovedex = {
|
|||
flags: {protect: 1, mirror: 1, sound: 1, authentic: 1},
|
||||
onTry: function () {
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
let decision = this.queue[i];
|
||||
if (!decision.pokemon || !decision.move) continue;
|
||||
if (decision.move.id === 'round') {
|
||||
this.prioritizeQueue(decision);
|
||||
let action = this.queue[i];
|
||||
if (!action.pokemon || !action.move) continue;
|
||||
if (action.move.id === 'round') {
|
||||
this.prioritizeAction(action);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -16573,8 +16573,8 @@ exports.BattleMovedex = {
|
|||
priority: 1,
|
||||
flags: {contact: 1, protect: 1, mirror: 1},
|
||||
onTry: function (source, target) {
|
||||
let decision = this.willMove(target);
|
||||
if (!decision || decision.choice !== 'move' || (decision.move.category === 'Status' && decision.move.id !== 'mefirst') || target.volatiles.mustrecharge) {
|
||||
let action = this.willMove(target);
|
||||
if (!action || action.choice !== 'move' || (action.move.category === 'Status' && action.move.id !== 'mefirst') || target.volatiles.mustrecharge) {
|
||||
this.attrLastMove('[still]');
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
|
|
@ -17884,9 +17884,9 @@ exports.BattleMovedex = {
|
|||
|
||||
if (target.side.active.length === 2 && target.position === 1) {
|
||||
// Curse Glitch
|
||||
const decision = this.willMove(target);
|
||||
if (decision && decision.move.id === 'curse') {
|
||||
decision.targetLoc = -1;
|
||||
const action = this.willMove(target);
|
||||
if (action && action.move.id === 'curse') {
|
||||
action.targetLoc = -1;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -17926,7 +17926,7 @@ exports.BattleMovedex = {
|
|||
onStart: function (target, source) {
|
||||
this.add('-fieldstart', 'move: Trick Room', '[of] ' + source);
|
||||
},
|
||||
// Speed modification is changed in Pokemon.getDecisionSpeed() in sim/pokemon.js
|
||||
// Speed modification is changed in Pokemon.getActionSpeed() in sim/pokemon.js
|
||||
onResidualOrder: 23,
|
||||
onEnd: function () {
|
||||
this.add('-fieldend', 'move: Trick Room');
|
||||
|
|
@ -18413,11 +18413,11 @@ exports.BattleMovedex = {
|
|||
flags: {protect: 1, mirror: 1, nonsky: 1},
|
||||
onPrepareHit: function (target, source, move) {
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
let decision = this.queue[i];
|
||||
if (!decision.move || !decision.pokemon || !decision.pokemon.isActive || decision.pokemon.fainted) continue;
|
||||
if (decision.pokemon.side === source.side && ['firepledge', 'grasspledge'].includes(decision.move.id)) {
|
||||
this.prioritizeQueue(decision);
|
||||
this.add('-waiting', source, decision.pokemon);
|
||||
let action = this.queue[i];
|
||||
if (!action.move || !action.pokemon || !action.pokemon.isActive || action.pokemon.fainted) continue;
|
||||
if (action.pokemon.side === source.side && ['firepledge', 'grasspledge'].includes(action.move.id)) {
|
||||
this.prioritizeAction(action);
|
||||
this.add('-waiting', source, action.pokemon);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ exports.BattleScripts = {
|
|||
runMove: function (move, pokemon, targetLoc, sourceEffect, zMove, externalMove) {
|
||||
let target = this.getTarget(pokemon, zMove || move, targetLoc);
|
||||
if (!sourceEffect && toId(move) !== 'struggle' && !zMove) {
|
||||
let changedMove = this.runEvent('OverrideDecision', pokemon, target, move);
|
||||
let changedMove = this.runEvent('OverrideAction', pokemon, target, move);
|
||||
if (changedMove && changedMove !== true) {
|
||||
move = changedMove;
|
||||
target = null;
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ exports.BattleMovedex = {
|
|||
this.effectData.duration++;
|
||||
}
|
||||
},
|
||||
onOverrideDecision: function (pokemon) {
|
||||
onOverrideAction: function (pokemon) {
|
||||
return this.effectData.move;
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ exports.BattleScripts = {
|
|||
runMove: function (move, pokemon, targetLoc, sourceEffect) {
|
||||
let target = this.getTarget(pokemon, move, targetLoc);
|
||||
if (!sourceEffect && toId(move) !== 'struggle') {
|
||||
let changedMove = this.runEvent('OverrideDecision', pokemon, target, move);
|
||||
let changedMove = this.runEvent('OverrideAction', pokemon, target, move);
|
||||
if (changedMove && changedMove !== true) {
|
||||
move = changedMove;
|
||||
target = null;
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ exports.BattleStatuses = {
|
|||
let move = this.getMove(this.effectData.move);
|
||||
if (move.id) {
|
||||
this.debug('Forcing into ' + move.id);
|
||||
this.changeDecision(pokemon, {move: move.id});
|
||||
this.changeAction(pokemon, {move: move.id});
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ exports.BattleMovedex = {
|
|||
this.effectData.duration++;
|
||||
}
|
||||
},
|
||||
onOverrideDecision: function (pokemon) {
|
||||
onOverrideAction: function (pokemon) {
|
||||
return this.effectData.move;
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
|
|
|
|||
|
|
@ -39,32 +39,32 @@ exports.BattleItems = {
|
|||
onModifyPriority: function () {},
|
||||
onBeforeTurn: function (pokemon) {
|
||||
if (pokemon.hp <= pokemon.maxhp / 4 || (pokemon.hp <= pokemon.maxhp / 2 && pokemon.ability === 'gluttony')) {
|
||||
let decision = this.willMove(pokemon);
|
||||
if (!decision) return;
|
||||
let action = this.willMove(pokemon);
|
||||
if (!action) return;
|
||||
this.insertQueue({
|
||||
choice: 'event',
|
||||
event: 'Custap',
|
||||
priority: decision.priority + 0.1,
|
||||
pokemon: decision.pokemon,
|
||||
move: decision.move,
|
||||
target: decision.target,
|
||||
priority: action.priority + 0.1,
|
||||
pokemon: action.pokemon,
|
||||
move: action.move,
|
||||
target: action.target,
|
||||
});
|
||||
}
|
||||
},
|
||||
onCustap: function (pokemon) {
|
||||
let decision = this.willMove(pokemon);
|
||||
this.debug('custap decision: ' + decision);
|
||||
if (decision) {
|
||||
let action = this.willMove(pokemon);
|
||||
this.debug('custap action: ' + action);
|
||||
if (action) {
|
||||
pokemon.eatItem();
|
||||
}
|
||||
},
|
||||
onEat: function (pokemon) {
|
||||
let decision = this.willMove(pokemon);
|
||||
this.debug('custap eaten: ' + decision);
|
||||
if (decision) {
|
||||
this.cancelDecision(pokemon);
|
||||
let action = this.willMove(pokemon);
|
||||
this.debug('custap eaten: ' + action);
|
||||
if (action) {
|
||||
this.cancelAction(pokemon);
|
||||
this.add('-message', "Custap Berry activated.");
|
||||
this.runDecision(decision);
|
||||
this.runAction(action);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ exports.BattleMovedex = {
|
|||
this.effectData.duration++;
|
||||
}
|
||||
},
|
||||
onOverrideDecision: function (pokemon) {
|
||||
onOverrideAction: function (pokemon) {
|
||||
return this.effectData.move;
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
|
|
@ -1094,8 +1094,8 @@ exports.BattleMovedex = {
|
|||
inherit: true,
|
||||
desc: "Fails if the target did not select a physical or special attack for use this turn, or if the target moves before the user.",
|
||||
onTry: function (source, target) {
|
||||
let decision = this.willMove(target);
|
||||
if (!decision || decision.choice !== 'move' || decision.move.category === 'Status' || target.volatiles.mustrecharge) {
|
||||
let action = this.willMove(target);
|
||||
if (!action || action.choice !== 'move' || action.move.category === 'Status' || target.volatiles.mustrecharge) {
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ exports.BattleMovedex = {
|
|||
this.effectData.duration++;
|
||||
}
|
||||
},
|
||||
onOverrideDecision: function (pokemon, target, move) {
|
||||
onOverrideAction: function (pokemon, target, move) {
|
||||
if (move.id !== this.effectData.move) return this.effectData.move;
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
|
|
|
|||
387
sim/battle.js
387
sim/battle.js
|
|
@ -22,20 +22,59 @@ const Pokemon = require('./pokemon');
|
|||
*/
|
||||
|
||||
/**
|
||||
* An object representing a single action that can be chosen.
|
||||
* A move action
|
||||
*
|
||||
* @typedef {Object} Action
|
||||
* @property {string} choice - a choice
|
||||
* @property {Pokemon} [pokemon] - the pokemon making the choice
|
||||
* @property {number} [targetLoc] - location of the target, relative to pokemon's side
|
||||
* @property {string} [move] - a move to use
|
||||
* @property {Pokemon} [target] - the target of the choice
|
||||
* @property {number} [index] - the chosen index in team preview
|
||||
* @property {number} [priority] - priority of the chosen index
|
||||
* @property {Side} [side] - the pokemon's side
|
||||
* @property {?boolean} [mega] - true if megaing or ultra bursting
|
||||
* @property {?boolean} [zmove] - true if zmoving
|
||||
* @typedef {Object} MoveAction
|
||||
* @property {'move' | 'beforeTurnMove'} choice - action type
|
||||
* @property {number} priority - priority of the action (lower first)
|
||||
* @property {number} speed - speed of pokemon using move (higher first if priority tie)
|
||||
* @property {Pokemon} pokemon - the pokemon doing the move
|
||||
* @property {number} targetLoc - location of the target, relative to pokemon's side
|
||||
* @property {string} moveid - a move to use (move action only)
|
||||
* @property {Move} move - a move to use (move action only)
|
||||
* @property {boolean | 'done'} mega - true if megaing or ultra bursting
|
||||
* @property {boolean} zmove - true if zmoving
|
||||
* @property {Effect?} sourceEffect - effect that did the action
|
||||
*/
|
||||
/**
|
||||
* A switch action
|
||||
*
|
||||
* @typedef {Object} SwitchAction
|
||||
* @property {'switch' | 'instaswitch'} choice - action type
|
||||
* @property {number} priority - priority of the action (lower first)
|
||||
* @property {number} speed - speed of pokemon switching (higher first if priority tie)
|
||||
* @property {Pokemon} pokemon - the pokemon doing the switch
|
||||
* @property {Pokemon} target - pokemon to switch to
|
||||
*/
|
||||
/**
|
||||
* A Team Preview choice action
|
||||
*
|
||||
* @typedef {Object} TeamAction
|
||||
* @property {'team'} choice - action type
|
||||
* @property {number} priority - priority of the action (lower first)
|
||||
* @property {1} speed - unused for this action type
|
||||
* @property {Pokemon} pokemon - the pokemon switching
|
||||
* @property {number} index - new index
|
||||
*/
|
||||
/**
|
||||
* A generic action not done by a pokemon
|
||||
*
|
||||
* @typedef {Object} FieldAction
|
||||
* @property {'start' | 'residual' | 'pass' | 'beforeTurn'} choice - action type
|
||||
* @property {number} priority - priority of the action (lower first)
|
||||
* @property {1} speed - unused for this action type
|
||||
* @property {null} pokemon - unused for this action type
|
||||
*/
|
||||
/**
|
||||
* A generic action done by a single pokemon
|
||||
*
|
||||
* @typedef {Object} PokemonAction
|
||||
* @property {'megaEvo' | 'shift' | 'runPrimal' | 'runSwitch' | 'event' | 'runUnnerve'} choice - action type
|
||||
* @property {number} priority - priority of the action (lower first)
|
||||
* @property {number} speed - speed of pokemon doing action (higher first if priority tie)
|
||||
* @property {Pokemon} pokemon - the pokemon doing action
|
||||
*/
|
||||
/** @typedef {MoveAction | SwitchAction | TeamAction | FieldAction | PokemonAction} Action */
|
||||
|
||||
class Battle extends Dex.ModdedDex {
|
||||
/**
|
||||
|
|
@ -77,7 +116,7 @@ class Battle extends Dex.ModdedDex {
|
|||
this.reportExactHP = !!format.debug;
|
||||
this.replayExactHP = !format.team;
|
||||
|
||||
/**@type {AnyObject[]} */
|
||||
/**@type {Action[]} */
|
||||
this.queue = [];
|
||||
/**@type {FaintedPokemon[]} */
|
||||
this.faintQueue = [];
|
||||
|
|
@ -1730,7 +1769,7 @@ class Battle extends Dex.ModdedDex {
|
|||
|
||||
this.residualEvent('TeamPreview');
|
||||
|
||||
this.addQueue({choice: 'start'});
|
||||
this.addToQueue({choice: 'start'});
|
||||
this.midTurn = true;
|
||||
if (!this.currentRequest) this.go();
|
||||
}
|
||||
|
|
@ -2432,7 +2471,7 @@ class Battle extends Dex.ModdedDex {
|
|||
this.cancelMove(pokemon);
|
||||
} else {
|
||||
// in gen 3, fainting skips all moves and switches
|
||||
this.cancelDecision(pokemon);
|
||||
this.cancelAction(pokemon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2454,15 +2493,20 @@ class Battle extends Dex.ModdedDex {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {AnyObject} decision
|
||||
* Takes an object describing an action, and fills it out into a full
|
||||
* Action object.
|
||||
*
|
||||
* @param {AnyObject} action
|
||||
* @param {boolean} [midTurn]
|
||||
* @return {Action}
|
||||
*/
|
||||
resolvePriority(decision, midTurn = false) {
|
||||
if (!decision) return;
|
||||
resolveAction(action, midTurn = false) {
|
||||
if (!action) throw new Error(`Action not passed to resolveAction`);
|
||||
|
||||
if (!decision.side && decision.pokemon) decision.side = decision.pokemon.side;
|
||||
if (!decision.choice && decision.move) decision.choice = 'move';
|
||||
if (!decision.priority && decision.priority !== 0) {
|
||||
if (!action.side && action.pokemon) action.side = action.pokemon.side;
|
||||
if (!action.move && action.moveid) action.move = this.getMoveCopy(action.moveid);
|
||||
if (!action.choice && action.move) action.choice = 'move';
|
||||
if (!action.priority && action.priority !== 0) {
|
||||
let priorities = {
|
||||
'beforeTurn': 100,
|
||||
'beforeTurnMove': 99,
|
||||
|
|
@ -2476,77 +2520,85 @@ class Battle extends Dex.ModdedDex {
|
|||
'team': 102,
|
||||
'start': 101,
|
||||
};
|
||||
if (decision.choice in priorities) {
|
||||
decision.priority = priorities[decision.choice];
|
||||
if (action.choice in priorities) {
|
||||
action.priority = priorities[action.choice];
|
||||
}
|
||||
}
|
||||
if (!midTurn) {
|
||||
if (decision.choice === 'move') {
|
||||
if (!decision.zmove && this.getMove(decision.move).beforeTurnCallback) {
|
||||
this.addQueue({choice: 'beforeTurnMove', pokemon: decision.pokemon, move: decision.move, targetLoc: decision.targetLoc});
|
||||
if (action.choice === 'move') {
|
||||
if (!action.zmove && action.move.beforeTurnCallback) {
|
||||
this.addToQueue({choice: 'beforeTurnMove', pokemon: action.pokemon, move: action.move, targetLoc: action.targetLoc});
|
||||
}
|
||||
if (decision.mega) {
|
||||
if (action.mega) {
|
||||
// TODO: Check that the Pokémon is not affected by Sky Drop.
|
||||
// (This is currently being done in `runMegaEvo`).
|
||||
this.addQueue({
|
||||
this.addToQueue({
|
||||
choice: 'megaEvo',
|
||||
pokemon: decision.pokemon,
|
||||
pokemon: action.pokemon,
|
||||
});
|
||||
}
|
||||
} else if (decision.choice === 'switch' || decision.choice === 'instaswitch') {
|
||||
if (decision.pokemon.switchFlag && decision.pokemon.switchFlag !== true) {
|
||||
decision.pokemon.switchCopyFlag = decision.pokemon.switchFlag;
|
||||
} else if (action.choice === 'switch' || action.choice === 'instaswitch') {
|
||||
if (action.pokemon.switchFlag && action.pokemon.switchFlag !== true) {
|
||||
action.pokemon.switchCopyFlag = action.pokemon.switchFlag;
|
||||
}
|
||||
decision.pokemon.switchFlag = false;
|
||||
if (!decision.speed) decision.speed = decision.pokemon.getDecisionSpeed();
|
||||
action.pokemon.switchFlag = false;
|
||||
if (!action.speed) action.speed = action.pokemon.getActionSpeed();
|
||||
}
|
||||
}
|
||||
|
||||
let deferPriority = this.gen >= 7 && decision.mega && decision.mega !== 'done';
|
||||
if (decision.move) {
|
||||
let deferPriority = this.gen >= 7 && action.mega && action.mega !== 'done';
|
||||
if (action.move) {
|
||||
let target = null;
|
||||
action.move = this.getMoveCopy(action.move);
|
||||
|
||||
if (!decision.targetLoc) {
|
||||
target = this.resolveTarget(decision.pokemon, decision.move);
|
||||
decision.targetLoc = this.getTargetLoc(target, decision.pokemon);
|
||||
if (!action.targetLoc) {
|
||||
target = this.resolveTarget(action.pokemon, action.move);
|
||||
action.targetLoc = this.getTargetLoc(target, action.pokemon);
|
||||
}
|
||||
|
||||
decision.move = this.getMoveCopy(decision.move);
|
||||
if (!decision.priority && !deferPriority) {
|
||||
let move = decision.move;
|
||||
if (decision.zmove) {
|
||||
if (!action.priority && !deferPriority) {
|
||||
let move = action.move;
|
||||
if (action.zmove) {
|
||||
// @ts-ignore
|
||||
let zMoveName = this.getZMove(decision.move, decision.pokemon, true);
|
||||
let zMoveName = this.getZMove(action.move, action.pokemon, true);
|
||||
let zMove = this.getMove(zMoveName);
|
||||
if (zMove.exists) {
|
||||
move = zMove;
|
||||
}
|
||||
}
|
||||
let priority = this.runEvent('ModifyPriority', decision.pokemon, target, move, move.priority);
|
||||
decision.priority = priority;
|
||||
let priority = this.runEvent('ModifyPriority', action.pokemon, target, move, move.priority);
|
||||
action.priority = priority;
|
||||
// In Gen 6, Quick Guard blocks moves with artificially enhanced priority.
|
||||
if (this.gen > 5) decision.move.priority = priority;
|
||||
if (this.gen > 5) action.move.priority = priority;
|
||||
}
|
||||
}
|
||||
if (!decision.pokemon && !decision.speed) decision.speed = 1;
|
||||
if (!decision.speed && (decision.choice === 'switch' || decision.choice === 'instaswitch') && decision.target) decision.speed = decision.target.getDecisionSpeed();
|
||||
if (!decision.speed && !deferPriority) decision.speed = decision.pokemon.getDecisionSpeed();
|
||||
if (!action.speed) {
|
||||
if ((action.choice === 'switch' || action.choice === 'instaswitch') && action.target) {
|
||||
action.speed = action.target.getActionSpeed();
|
||||
} else if (!action.pokemon) {
|
||||
action.speed = 1;
|
||||
} else if (!deferPriority) {
|
||||
action.speed = action.pokemon.getActionSpeed();
|
||||
}
|
||||
}
|
||||
return /** @type {any} */ (action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the action last in the queue. Mostly used before sortQueue.
|
||||
*
|
||||
* @param {AnyObject | AnyObject[]} action
|
||||
*/
|
||||
addQueue(action) {
|
||||
addToQueue(action) {
|
||||
if (Array.isArray(action)) {
|
||||
for (let i = 0; i < action.length; i++) {
|
||||
this.addQueue(action[i]);
|
||||
this.addToQueue(action[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (action.choice === 'pass') return;
|
||||
this.resolvePriority(action);
|
||||
this.queue.push(action);
|
||||
this.queue.push(this.resolveAction(action));
|
||||
}
|
||||
|
||||
sortQueue() {
|
||||
|
|
@ -2554,52 +2606,58 @@ class Battle extends Dex.ModdedDex {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {AnyObject | AnyObject[]} decision
|
||||
* Inserts the passed action into the action queue when it normally
|
||||
* would have happened (sorting by priority/speed), without
|
||||
* re-sorting the existing actions.
|
||||
*
|
||||
* @param {AnyObject | AnyObject[]} chosenAction
|
||||
* @param {boolean} [midTurn]
|
||||
*/
|
||||
insertQueue(decision, midTurn = false) {
|
||||
if (Array.isArray(decision)) {
|
||||
for (let i = 0; i < decision.length; i++) {
|
||||
this.insertQueue(decision[i]);
|
||||
insertQueue(chosenAction, midTurn = false) {
|
||||
if (Array.isArray(chosenAction)) {
|
||||
for (const subAction of chosenAction) {
|
||||
this.insertQueue(subAction);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (decision.pokemon) decision.pokemon.updateSpeed();
|
||||
this.resolvePriority(decision, midTurn);
|
||||
if (chosenAction.pokemon) chosenAction.pokemon.updateSpeed();
|
||||
const action = this.resolveAction(chosenAction, midTurn);
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
if (Battle.comparePriority(decision, this.queue[i]) < 0) {
|
||||
this.queue.splice(i, 0, decision);
|
||||
if (Battle.comparePriority(action, this.queue[i]) < 0) {
|
||||
this.queue.splice(i, 0, action);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.queue.push(decision);
|
||||
this.queue.push(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AnyObject} decision
|
||||
* Makes the passed move action happen next (skipping speed order).
|
||||
*
|
||||
* @param {MoveAction} action
|
||||
* @param {Pokemon} [source]
|
||||
* @param {Effect} [sourceEffect]
|
||||
*/
|
||||
prioritizeQueue(decision, source, sourceEffect) {
|
||||
prioritizeAction(action, source, sourceEffect) {
|
||||
if (this.event) {
|
||||
if (!source) source = this.event.source;
|
||||
if (!sourceEffect) sourceEffect = this.effect;
|
||||
}
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
if (this.queue[i] === decision) {
|
||||
for (const [i, curAction] of this.queue.entries()) {
|
||||
if (curAction === action) {
|
||||
this.queue.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
decision.sourceEffect = sourceEffect;
|
||||
this.queue.unshift(decision);
|
||||
action.sourceEffect = sourceEffect;
|
||||
this.queue.unshift(action);
|
||||
}
|
||||
|
||||
willAct() {
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
if (this.queue[i].choice === 'move' || this.queue[i].choice === 'switch' || this.queue[i].choice === 'instaswitch' || this.queue[i].choice === 'shift') {
|
||||
return this.queue[i];
|
||||
for (const action of this.queue) {
|
||||
if (action.choice === 'move' || action.choice === 'switch' || action.choice === 'instaswitch' || action.choice === 'shift') {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
@ -2610,9 +2668,9 @@ class Battle extends Dex.ModdedDex {
|
|||
*/
|
||||
willMove(pokemon) {
|
||||
if (pokemon.fainted) return false;
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
if (this.queue[i].choice === 'move' && this.queue[i].pokemon === pokemon) {
|
||||
return this.queue[i];
|
||||
for (const action of this.queue) {
|
||||
if (action.choice === 'move' && action.pokemon === pokemon) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
@ -2621,7 +2679,7 @@ class Battle extends Dex.ModdedDex {
|
|||
/**
|
||||
* @param {Pokemon} pokemon
|
||||
*/
|
||||
cancelDecision(pokemon) {
|
||||
cancelAction(pokemon) {
|
||||
let success = false;
|
||||
this.queue = this.queue.filter(action => {
|
||||
if (action.pokemon === pokemon && action.priority >= -100) {
|
||||
|
|
@ -2637,8 +2695,8 @@ class Battle extends Dex.ModdedDex {
|
|||
* @param {Pokemon} pokemon
|
||||
*/
|
||||
cancelMove(pokemon) {
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
if (this.queue[i].choice === 'move' && this.queue[i].pokemon === pokemon) {
|
||||
for (const [i, action] of this.queue.entries()) {
|
||||
if (action.choice === 'move' && action.pokemon === pokemon) {
|
||||
this.queue.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2650,20 +2708,20 @@ class Battle extends Dex.ModdedDex {
|
|||
* @param {Pokemon} pokemon
|
||||
*/
|
||||
willSwitch(pokemon) {
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
if ((this.queue[i].choice === 'switch' || this.queue[i].choice === 'instaswitch') && this.queue[i].pokemon === pokemon) {
|
||||
return this.queue[i];
|
||||
for (const action of this.queue) {
|
||||
if ((action.choice === 'switch' || action.choice === 'instaswitch') && action.pokemon === pokemon) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AnyObject} decision
|
||||
* @param {Action} action
|
||||
*/
|
||||
runDecision(decision) {
|
||||
runAction(action) {
|
||||
// returns whether or not we ended in a callback
|
||||
switch (decision.choice) {
|
||||
switch (action.choice) {
|
||||
case 'start': {
|
||||
// I GIVE UP, WILL WRESTLE WITH EVENT SYSTEM LATER
|
||||
let format = this.getFormat();
|
||||
|
|
@ -2700,56 +2758,54 @@ class Battle extends Dex.ModdedDex {
|
|||
}
|
||||
|
||||
case 'move':
|
||||
if (!decision.pokemon.isActive) return false;
|
||||
if (decision.pokemon.fainted) return false;
|
||||
if (!action.pokemon.isActive) return false;
|
||||
if (action.pokemon.fainted) return false;
|
||||
// @ts-ignore
|
||||
this.runMove(decision.move, decision.pokemon, decision.targetLoc, decision.sourceEffect, decision.zmove);
|
||||
this.runMove(action.move, action.pokemon, action.targetLoc, action.sourceEffect, action.zmove);
|
||||
break;
|
||||
case 'megaEvo':
|
||||
// @ts-ignore
|
||||
this.runMegaEvo(decision.pokemon);
|
||||
this.runMegaEvo(action.pokemon);
|
||||
break;
|
||||
case 'beforeTurnMove': {
|
||||
if (!decision.pokemon.isActive) return false;
|
||||
if (decision.pokemon.fainted) return false;
|
||||
this.debug('before turn callback: ' + decision.move.id);
|
||||
let target = this.getTarget(decision.pokemon, decision.move, decision.targetLoc);
|
||||
if (!action.pokemon.isActive) return false;
|
||||
if (action.pokemon.fainted) return false;
|
||||
this.debug('before turn callback: ' + action.move.id);
|
||||
let target = this.getTarget(action.pokemon, action.move, action.targetLoc);
|
||||
if (!target) return false;
|
||||
decision.move.beforeTurnCallback.call(this, decision.pokemon, target);
|
||||
if (!action.move.beforeTurnCallback) throw new Error(`beforeTurnMove has no beforeTurnCallback`);
|
||||
action.move.beforeTurnCallback.call(this, action.pokemon, target);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'event':
|
||||
this.runEvent(decision.event, decision.pokemon);
|
||||
// @ts-ignore Easier than defining a custom event attribute tbh
|
||||
this.runEvent(action.event, action.pokemon);
|
||||
break;
|
||||
case 'team': {
|
||||
decision.side.pokemon.splice(decision.index, 0, decision.pokemon);
|
||||
decision.pokemon.position = decision.index;
|
||||
action.pokemon.side.pokemon.splice(action.index, 0, action.pokemon);
|
||||
action.pokemon.position = action.index;
|
||||
// we return here because the update event would crash since there are no active pokemon yet
|
||||
return;
|
||||
}
|
||||
|
||||
case 'pass':
|
||||
if (!decision.priority || decision.priority <= 101) return;
|
||||
if (decision.pokemon) {
|
||||
decision.pokemon.switchFlag = false;
|
||||
}
|
||||
break;
|
||||
return;
|
||||
case 'instaswitch':
|
||||
case 'switch':
|
||||
if (decision.choice === 'switch' && decision.pokemon.status && this.data.Abilities.naturalcure) {
|
||||
this.singleEvent('CheckShow', this.getAbility('naturalcure'), null, decision.pokemon);
|
||||
if (action.choice === 'switch' && action.pokemon.status && this.data.Abilities.naturalcure) {
|
||||
this.singleEvent('CheckShow', this.getAbility('naturalcure'), null, action.pokemon);
|
||||
}
|
||||
if (decision.pokemon.hp) {
|
||||
decision.pokemon.beingCalledBack = true;
|
||||
let lastMove = this.getMove(decision.pokemon.lastMove);
|
||||
if (action.pokemon.hp) {
|
||||
action.pokemon.beingCalledBack = true;
|
||||
let lastMove = this.getMove(action.pokemon.lastMove);
|
||||
if (lastMove.selfSwitch !== 'copyvolatile') {
|
||||
this.runEvent('BeforeSwitchOut', decision.pokemon);
|
||||
this.runEvent('BeforeSwitchOut', action.pokemon);
|
||||
if (this.gen >= 5) {
|
||||
this.eachEvent('Update');
|
||||
}
|
||||
}
|
||||
if (!this.runEvent('SwitchOut', decision.pokemon)) {
|
||||
if (!this.runEvent('SwitchOut', action.pokemon)) {
|
||||
// Warning: DO NOT interrupt a switch-out
|
||||
// if you just want to trap a pokemon.
|
||||
// To trap a pokemon and prevent it from switching out,
|
||||
|
|
@ -2761,14 +2817,14 @@ class Battle extends Dex.ModdedDex {
|
|||
break;
|
||||
}
|
||||
}
|
||||
decision.pokemon.illusion = null;
|
||||
this.singleEvent('End', this.getAbility(decision.pokemon.ability), decision.pokemon.abilityData, decision.pokemon);
|
||||
if (!decision.pokemon.hp && !decision.pokemon.fainted) {
|
||||
action.pokemon.illusion = null;
|
||||
this.singleEvent('End', this.getAbility(action.pokemon.ability), action.pokemon.abilityData, action.pokemon);
|
||||
if (!action.pokemon.hp && !action.pokemon.fainted) {
|
||||
// a pokemon fainted from Pursuit before it could switch
|
||||
if (this.gen <= 4) {
|
||||
// in gen 2-4, the switch still happens
|
||||
decision.priority = -101;
|
||||
this.queue.unshift(decision);
|
||||
action.priority = -101;
|
||||
this.queue.unshift(action);
|
||||
this.add('-hint', 'Pursuit target fainted, switch continues in gen 2-4');
|
||||
break;
|
||||
}
|
||||
|
|
@ -2776,51 +2832,51 @@ class Battle extends Dex.ModdedDex {
|
|||
this.debug('A Pokemon can\'t switch between when it runs out of HP and when it faints');
|
||||
break;
|
||||
}
|
||||
if (decision.target.isActive) {
|
||||
if (action.target.isActive) {
|
||||
this.add('-hint', 'Switch failed; switch target is already active');
|
||||
break;
|
||||
}
|
||||
if (decision.choice === 'switch' && decision.pokemon.activeTurns === 1) {
|
||||
let foeActive = decision.pokemon.side.foe.active;
|
||||
if (action.choice === 'switch' && action.pokemon.activeTurns === 1) {
|
||||
let foeActive = action.pokemon.side.foe.active;
|
||||
for (let i = 0; i < foeActive.length; i++) {
|
||||
if (foeActive[i].isStale >= 2) {
|
||||
decision.pokemon.isStaleCon++;
|
||||
decision.pokemon.isStaleSource = 'switch';
|
||||
action.pokemon.isStaleCon++;
|
||||
action.pokemon.isStaleSource = 'switch';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.switchIn(decision.target, decision.pokemon.position);
|
||||
this.switchIn(action.target, action.pokemon.position);
|
||||
break;
|
||||
case 'runUnnerve':
|
||||
this.singleEvent('PreStart', decision.pokemon.getAbility(), decision.pokemon.abilityData, decision.pokemon);
|
||||
this.singleEvent('PreStart', action.pokemon.getAbility(), action.pokemon.abilityData, action.pokemon);
|
||||
break;
|
||||
case 'runSwitch':
|
||||
this.runEvent('SwitchIn', decision.pokemon);
|
||||
if (this.gen <= 2 && !decision.pokemon.side.faintedThisTurn && decision.pokemon.draggedIn !== this.turn) this.runEvent('AfterSwitchInSelf', decision.pokemon);
|
||||
if (!decision.pokemon.hp) break;
|
||||
decision.pokemon.isStarted = true;
|
||||
if (!decision.pokemon.fainted) {
|
||||
this.singleEvent('Start', decision.pokemon.getAbility(), decision.pokemon.abilityData, decision.pokemon);
|
||||
decision.pokemon.abilityOrder = this.abilityOrder++;
|
||||
this.singleEvent('Start', decision.pokemon.getItem(), decision.pokemon.itemData, decision.pokemon);
|
||||
this.runEvent('SwitchIn', action.pokemon);
|
||||
if (this.gen <= 2 && !action.pokemon.side.faintedThisTurn && action.pokemon.draggedIn !== this.turn) this.runEvent('AfterSwitchInSelf', action.pokemon);
|
||||
if (!action.pokemon.hp) break;
|
||||
action.pokemon.isStarted = true;
|
||||
if (!action.pokemon.fainted) {
|
||||
this.singleEvent('Start', action.pokemon.getAbility(), action.pokemon.abilityData, action.pokemon);
|
||||
action.pokemon.abilityOrder = this.abilityOrder++;
|
||||
this.singleEvent('Start', action.pokemon.getItem(), action.pokemon.itemData, action.pokemon);
|
||||
}
|
||||
delete decision.pokemon.draggedIn;
|
||||
delete action.pokemon.draggedIn;
|
||||
break;
|
||||
case 'runPrimal':
|
||||
if (!decision.pokemon.transformed) this.singleEvent('Primal', decision.pokemon.getItem(), decision.pokemon.itemData, decision.pokemon);
|
||||
if (!action.pokemon.transformed) this.singleEvent('Primal', action.pokemon.getItem(), action.pokemon.itemData, action.pokemon);
|
||||
break;
|
||||
case 'shift': {
|
||||
if (!decision.pokemon.isActive) return false;
|
||||
if (decision.pokemon.fainted) return false;
|
||||
decision.pokemon.activeTurns--;
|
||||
this.swapPosition(decision.pokemon, 1);
|
||||
let foeActive = decision.pokemon.side.foe.active;
|
||||
if (!action.pokemon.isActive) return false;
|
||||
if (action.pokemon.fainted) return false;
|
||||
action.pokemon.activeTurns--;
|
||||
this.swapPosition(action.pokemon, 1);
|
||||
let foeActive = action.pokemon.side.foe.active;
|
||||
for (let i = 0; i < foeActive.length; i++) {
|
||||
if (foeActive[i].isStale >= 2) {
|
||||
decision.pokemon.isStaleCon++;
|
||||
decision.pokemon.isStaleSource = 'switch';
|
||||
action.pokemon.isStaleCon++;
|
||||
action.pokemon.isStaleSource = 'switch';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -2837,9 +2893,6 @@ class Battle extends Dex.ModdedDex {
|
|||
this.residualEvent('Residual');
|
||||
this.add('upkeep');
|
||||
break;
|
||||
|
||||
case 'skip':
|
||||
throw new Error("Decision illegally skipped!");
|
||||
}
|
||||
|
||||
// phazing (Roar, etc)
|
||||
|
|
@ -2871,17 +2924,14 @@ class Battle extends Dex.ModdedDex {
|
|||
// in gen 3 or earlier, switching in fainted pokemon is done after
|
||||
// every move, rather than only at the end of the turn.
|
||||
this.checkFainted();
|
||||
} else if (decision.choice === 'pass') {
|
||||
} else if (action.choice === 'megaEvo' && this.gen >= 7) {
|
||||
this.eachEvent('Update');
|
||||
return false;
|
||||
} else if (decision.choice === 'megaEvo' && this.gen >= 7) {
|
||||
this.eachEvent('Update');
|
||||
// In Gen 7, the decision order is recalculated for a Pokémon that mega evolves.
|
||||
const moveIndex = this.queue.findIndex(queuedDecision => queuedDecision.pokemon === decision.pokemon && queuedDecision.choice === 'move');
|
||||
// In Gen 7, the action order is recalculated for a Pokémon that mega evolves.
|
||||
const moveIndex = this.queue.findIndex(queuedAction => queuedAction.pokemon === action.pokemon && queuedAction.choice === 'move');
|
||||
if (moveIndex >= 0) {
|
||||
const moveDecision = this.queue.splice(moveIndex, 1)[0];
|
||||
moveDecision.mega = 'done';
|
||||
this.insertQueue(moveDecision, true);
|
||||
const moveAction = /** @type {MoveAction} */ (this.queue.splice(moveIndex, 1)[0]);
|
||||
moveAction.mega = 'done';
|
||||
this.insertQueue(moveAction, true);
|
||||
}
|
||||
return false;
|
||||
} else if (this.queue.length && this.queue[0].choice === 'instaswitch') {
|
||||
|
|
@ -2924,16 +2974,16 @@ class Battle extends Dex.ModdedDex {
|
|||
}
|
||||
|
||||
if (!this.midTurn) {
|
||||
this.queue.push({choice: 'residual', priority: -100});
|
||||
this.queue.unshift({choice: 'beforeTurn', priority: 100});
|
||||
this.queue.push(this.resolveAction({choice: 'residual'}));
|
||||
this.queue.unshift(this.resolveAction({choice: 'beforeTurn'}));
|
||||
this.midTurn = true;
|
||||
}
|
||||
|
||||
while (this.queue.length) {
|
||||
let decision = this.queue[0];
|
||||
let action = this.queue[0];
|
||||
this.queue.shift();
|
||||
|
||||
this.runDecision(decision);
|
||||
this.runAction(action);
|
||||
|
||||
if (this.currentRequest) {
|
||||
return;
|
||||
|
|
@ -2948,19 +2998,19 @@ class Battle extends Dex.ModdedDex {
|
|||
}
|
||||
|
||||
/**
|
||||
* Changes a pokemon's decision, and inserts its new decision
|
||||
* Changes a pokemon's action, and inserts its new action
|
||||
* in priority order.
|
||||
*
|
||||
* You'd normally want the OverrideDecision event (which doesn't
|
||||
* You'd normally want the OverrideAction event (which doesn't
|
||||
* change priority order).
|
||||
*
|
||||
* @param {Pokemon} pokemon
|
||||
* @param {AnyObject} decision
|
||||
* @param {AnyObject} action
|
||||
*/
|
||||
changeDecision(pokemon, decision) {
|
||||
this.cancelDecision(pokemon);
|
||||
if (!decision.pokemon) decision.pokemon = pokemon;
|
||||
this.insertQueue(decision);
|
||||
changeAction(pokemon, action) {
|
||||
this.cancelAction(pokemon);
|
||||
if (!action.pokemon) action.pokemon = pokemon;
|
||||
this.insertQueue(action);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2977,7 +3027,7 @@ class Battle extends Dex.ModdedDex {
|
|||
|
||||
if (!side.choose(input)) return false;
|
||||
|
||||
this.checkDecisions();
|
||||
this.checkActions();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3009,7 +3059,7 @@ class Battle extends Dex.ModdedDex {
|
|||
this.LEGACY_API_DO_NOT_USE = oldFlag;
|
||||
this.add('choice', this.p1.getChoice, this.p2.getChoice);
|
||||
for (const side of this.sides) {
|
||||
this.addQueue(side.choice.actions);
|
||||
this.addToQueue(side.choice.actions);
|
||||
}
|
||||
|
||||
this.sortQueue();
|
||||
|
|
@ -3042,17 +3092,17 @@ class Battle extends Dex.ModdedDex {
|
|||
/**
|
||||
* returns true if both decisions are complete
|
||||
*/
|
||||
checkDecisions() {
|
||||
let totalDecisions = 0;
|
||||
checkActions() {
|
||||
let totalActions = 0;
|
||||
if (this.p1.isChoiceDone()) {
|
||||
if (!this.supportCancel) this.p1.choice.cantUndo = true;
|
||||
totalDecisions++;
|
||||
totalActions++;
|
||||
}
|
||||
if (this.p2.isChoiceDone()) {
|
||||
if (!this.supportCancel) this.p2.choice.cantUndo = true;
|
||||
totalDecisions++;
|
||||
totalActions++;
|
||||
}
|
||||
if (totalDecisions >= this.sides.length) {
|
||||
if (totalActions >= this.sides.length) {
|
||||
this.commitDecisions();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3277,7 +3327,6 @@ class Battle extends Dex.ModdedDex {
|
|||
this.p2 = null;
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
delete this.queue[i].pokemon;
|
||||
delete this.queue[i].side;
|
||||
}
|
||||
this.queue = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ class Pokemon {
|
|||
}
|
||||
|
||||
updateSpeed() {
|
||||
this.speed = this.getDecisionSpeed();
|
||||
this.speed = this.getActionSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -346,7 +346,7 @@ class Pokemon {
|
|||
return stat;
|
||||
}
|
||||
|
||||
getDecisionSpeed() {
|
||||
getActionSpeed() {
|
||||
let speed = this.getStat('spe', false, false);
|
||||
if (speed > 10000) speed = 10000;
|
||||
if (this.battle.getPseudoWeather('trickroom')) {
|
||||
|
|
@ -514,14 +514,17 @@ class Pokemon {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string | null}
|
||||
*/
|
||||
getLockedMove() {
|
||||
let lockedMove = this.battle.runEvent('LockMove', this);
|
||||
if (lockedMove === true) lockedMove = false;
|
||||
if (lockedMove === true) lockedMove = null;
|
||||
return lockedMove;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [lockedMove]
|
||||
* @param {string?} [lockedMove]
|
||||
* @param {boolean} [restrictData]
|
||||
*/
|
||||
getMoves(lockedMove, restrictData) {
|
||||
|
|
|
|||
40
sim/side.js
40
sim/side.js
|
|
@ -11,17 +11,17 @@ const Pokemon = require('./pokemon');
|
|||
/**
|
||||
* An object representing a single action that can be chosen.
|
||||
*
|
||||
* @typedef {Object} Action
|
||||
* @property {string} choice - a choice
|
||||
* @property {Pokemon} [pokemon] - the pokemon making the choice
|
||||
* @property {number} [targetLoc] - location of the target, relative to pokemon's side
|
||||
* @property {string} [move] - a move to use
|
||||
* @property {Pokemon} [target] - the target of the choice
|
||||
* @property {number} [index] - the chosen index in team preview
|
||||
* @property {number} [priority] - priority of the chosen index
|
||||
* @property {Side} [side] - the pokemon's side
|
||||
* @typedef {Object} ChosenAction
|
||||
* @property {'move' | 'switch' | 'instaswitch' | 'team' | 'shift' | 'pass'} choice - action type
|
||||
* @property {Pokemon} [pokemon] - the pokemon doing the action
|
||||
* @property {number} [targetLoc] - relative location of the target to pokemon (move action only)
|
||||
* @property {string} [moveid] - a move to use (move action only)
|
||||
* @property {Pokemon} [target] - the target of the action
|
||||
* @property {number} [index] - the chosen index in Team Preview
|
||||
* @property {Side} [side] - the action's side
|
||||
* @property {?boolean} [mega] - true if megaing or ultra bursting
|
||||
* @property {?boolean} [zmove] - true if zmoving
|
||||
* @property {number} [priority] - priority of the action
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -30,7 +30,7 @@ const Pokemon = require('./pokemon');
|
|||
* @typedef {Object} Choice
|
||||
* @property {boolean} cantUndo - true if the choice can't be cancelled because of the maybeTrapped issue
|
||||
* @property {string} error - contains error text in the case of a choice error
|
||||
* @property {Action[]} actions - array of chosen actions
|
||||
* @property {ChosenAction[]} actions - array of chosen actions
|
||||
* @property {number} forcedSwitchesLeft - number of switches left that need to be performed
|
||||
* @property {number} forcedPassesLeft - number of passes left that need to be performed
|
||||
* @property {Set<number>} switchIns - indexes of pokemon chosen to switch in
|
||||
|
|
@ -128,7 +128,7 @@ class Side {
|
|||
if (action.targetLoc && this.active.length > 1) details += ` ${action.targetLoc}`;
|
||||
if (action.mega) details += ` mega`;
|
||||
if (action.zmove) details += ` zmove`;
|
||||
return `move ${toId(action.move)}${details}`;
|
||||
return `move ${action.moveid}${details}`;
|
||||
case 'switch':
|
||||
case 'instaswitch':
|
||||
return `switch ${action.target.position + 1}`;
|
||||
|
|
@ -307,7 +307,7 @@ class Side {
|
|||
if (!targetLoc) targetLoc = 0;
|
||||
|
||||
// Parse moveText (name or index)
|
||||
// If the move is not found, the decision is invalid without requiring further inspection.
|
||||
// If the move is not found, the action is invalid without requiring further inspection.
|
||||
|
||||
const requestMoves = pokemon.getRequestData().moves;
|
||||
let moveid = '';
|
||||
|
|
@ -390,11 +390,11 @@ class Side {
|
|||
choice: 'move',
|
||||
pokemon: pokemon,
|
||||
targetLoc: lockedMoveTarget || 0,
|
||||
move: lockedMove,
|
||||
moveid: toId(lockedMove),
|
||||
});
|
||||
return true;
|
||||
} else if (!moves.length && !zMove) {
|
||||
// Override decision and use Struggle if there are no enabled moves with PP
|
||||
// Override action and use Struggle if there are no enabled moves with PP
|
||||
// Gen 4 and earlier announce a Pokemon has no moves left before the turn begins, and only to that player's side.
|
||||
if (this.battle.gen <= 4) this.send('-activate', pokemon, 'move: Struggle');
|
||||
moveid = 'struggle';
|
||||
|
|
@ -445,7 +445,7 @@ class Side {
|
|||
choice: 'move',
|
||||
pokemon: pokemon,
|
||||
targetLoc: targetLoc,
|
||||
move: moveid,
|
||||
moveid: moveid,
|
||||
mega: mega || ultra,
|
||||
zmove: zMove,
|
||||
});
|
||||
|
|
@ -458,7 +458,7 @@ class Side {
|
|||
if (ultra) this.choice.ultra = true;
|
||||
if (zMove) this.choice.zMove = true;
|
||||
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkDecisions()) return this;
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkActions()) return this;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -534,7 +534,7 @@ class Side {
|
|||
target: targetPokemon,
|
||||
});
|
||||
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkDecisions()) return this;
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkActions()) return this;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -586,7 +586,7 @@ class Side {
|
|||
});
|
||||
}
|
||||
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkDecisions()) return this;
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkActions()) return this;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -610,7 +610,7 @@ class Side {
|
|||
pokemon: pokemon,
|
||||
});
|
||||
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkDecisions()) return this;
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkActions()) return this;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -765,7 +765,7 @@ class Side {
|
|||
this.choice.actions.push({
|
||||
choice: 'pass',
|
||||
});
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkDecisions()) return this;
|
||||
if (this.battle.LEGACY_API_DO_NOT_USE && !this.battle.checkActions()) return this;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ for every move:
|
|||
[ModifyPriority]
|
||||
move's [BeforeTurn]
|
||||
|
||||
runDecision() - runs runSwitch, runAfterSwitch, and runMove in priority order, then residual at end {
|
||||
runAction() - runs runSwitch, runAfterSwitch, and runMove in priority order, then residual at end {
|
||||
runSwitch() {
|
||||
[BeforeSwitch]
|
||||
switch
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ const RULE_FLAGS = {
|
|||
preview: 4,
|
||||
sleepClause: 8,
|
||||
cancel: 16,
|
||||
partialDecisions: 32,
|
||||
};
|
||||
|
||||
function capitalize(word) {
|
||||
|
|
@ -86,7 +85,6 @@ class TestTools {
|
|||
if (options.preview) format.ruleset.push('Team Preview');
|
||||
if (options.sleepClause) format.ruleset.push('Sleep Clause Mod');
|
||||
if (options.cancel) format.ruleset.push('Cancel Mod');
|
||||
// if (options.partialDecisions) format.ruleset.push('Partial Decisions');
|
||||
|
||||
this.dex.installFormat(formatId, format);
|
||||
return format;
|
||||
|
|
@ -115,7 +113,6 @@ class TestTools {
|
|||
prng
|
||||
);
|
||||
battle.LEGACY_API_DO_NOT_USE = true;
|
||||
if (options && options.partialDecisions) battle.supportPartialDecisions = true;
|
||||
if (teams) {
|
||||
for (let i = 0; i < teams.length; i++) {
|
||||
assert(Array.isArray(teams[i]), "Team provided is not an array");
|
||||
|
|
|
|||
|
|
@ -14,15 +14,15 @@ describe('Choice parser', function () {
|
|||
[{species: "Rhydon", ability: 'prankster', moves: ['splash']}],
|
||||
]);
|
||||
|
||||
const validDecision = 'team 1';
|
||||
assert(battle.choose('p1', validDecision));
|
||||
const validChoice = 'team 1';
|
||||
assert(battle.choose('p1', validChoice));
|
||||
battle.p1.clearChoice();
|
||||
assert(battle.choose('p2', validDecision));
|
||||
assert(battle.choose('p2', validChoice));
|
||||
battle.p1.clearChoice();
|
||||
|
||||
const badDecisions = ['move 1', 'move 2 mega', 'switch 1', 'pass', 'shift'];
|
||||
for (const badDecision of badDecisions) {
|
||||
assert.false(battle.choose('p1', badDecision), `Decision '${badDecision}' should be rejected`);
|
||||
const badChoices = ['move 1', 'move 2 mega', 'switch 1', 'pass', 'shift'];
|
||||
for (const badChoice of badChoices) {
|
||||
assert.false(battle.choose('p1', badChoice), `Choice '${badChoice}' should be rejected`);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -68,13 +68,13 @@ describe('Choice parser', function () {
|
|||
|
||||
battle.commitDecisions();
|
||||
|
||||
const badDecisions = ['move 1', 'move 2 mega', 'team 1', 'pass', 'shift'];
|
||||
for (const badDecision of badDecisions) {
|
||||
assert.false(battle.choose('p1', badDecision), `Decision '${badDecision}' should be rejected`);
|
||||
const badChoices = ['move 1', 'move 2 mega', 'team 1', 'pass', 'shift'];
|
||||
for (const badChoice of badChoices) {
|
||||
assert.false(battle.choose('p1', badChoice), `Choice '${badChoice}' should be rejected`);
|
||||
}
|
||||
|
||||
const validDecision = 'switch Bulbasaur';
|
||||
assert(battle.choose('p1', validDecision));
|
||||
const validChoice = 'switch Bulbasaur';
|
||||
assert(battle.choose('p1', validChoice));
|
||||
battle.p1.clearChoice();
|
||||
});
|
||||
});
|
||||
|
|
@ -94,12 +94,12 @@ describe('Choice parser', function () {
|
|||
]);
|
||||
battle.commitDecisions(); // Both p1 active Pokémon faint
|
||||
|
||||
const badDecisions = ['move 1', 'move 2 mega', 'team 1', 'shift'];
|
||||
for (const badDecision of badDecisions) {
|
||||
assert.false(battle.choose('p1', badDecision), `Decision '${badDecision}' should be rejected`);
|
||||
const badChoices = ['move 1', 'move 2 mega', 'team 1', 'shift'];
|
||||
for (const badChoice of badChoices) {
|
||||
assert.false(battle.choose('p1', badChoice), `Choice '${badChoice}' should be rejected`);
|
||||
}
|
||||
|
||||
assert(battle.choose('p1', `pass, switch 3`), `Decision 'pass, switch 3' should be valid`);
|
||||
assert(battle.choose('p1', `pass, switch 3`), `Choice 'pass, switch 3' should be valid`);
|
||||
});
|
||||
|
||||
it('should reject choice details for `pass` choices', function () {
|
||||
|
|
@ -150,15 +150,15 @@ describe('Choice parser', function () {
|
|||
{species: "Charmander", ability: 'blaze', moves: ['tackle', 'growl']},
|
||||
]);
|
||||
|
||||
const validDecisions = ['move 1', 'move 2', 'switch 2'];
|
||||
for (const decision of validDecisions) {
|
||||
assert(battle.choose('p1', decision), `Decision '${decision}' should be valid`);
|
||||
const validChoices = ['move 1', 'move 2', 'switch 2'];
|
||||
for (const action of validChoices) {
|
||||
assert(battle.choose('p1', action), `Choice '${action}' should be valid`);
|
||||
battle.p1.clearChoice();
|
||||
}
|
||||
|
||||
const badDecisions = ['move 1 zmove', 'move 2 mega', 'team 1', 'pass', 'shift'];
|
||||
for (const badDecision of badDecisions) {
|
||||
assert.false(battle.choose('p1', badDecision), `Decision '${badDecision}' should be rejected`);
|
||||
const badChoices = ['move 1 zmove', 'move 2 mega', 'team 1', 'pass', 'shift'];
|
||||
for (const badChoice of badChoices) {
|
||||
assert.false(battle.choose('p1', badChoice), `Choice '${badChoice}' should be rejected`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -183,7 +183,7 @@ describe('Choice parser', function () {
|
|||
assert.false.fainted(p1.active[1]);
|
||||
|
||||
assert(battle.choose('p1', 'move smog 2'));
|
||||
assert.strictEqual(battle.p1.getChoice(true), `pass, move smog 2`, `Decision mismatch`);
|
||||
assert.strictEqual(battle.p1.getChoice(true), `pass, move smog 2`, `Choice mismatch`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -202,18 +202,18 @@ describe('Choice parser', function () {
|
|||
{species: "Golem", ability: 'sturdy', moves: ['defensecurl']},
|
||||
]);
|
||||
|
||||
const validDecisions = ['move 1', 'switch 4'];
|
||||
const validChoices = ['move 1', 'switch 4'];
|
||||
|
||||
validDecisions.forEach(decision => {
|
||||
const choiceString = `move 1, ${decision}, move 1 1`;
|
||||
assert(battle.choose('p1', choiceString), `Decision '${choiceString}' should be valid`);
|
||||
validChoices.forEach(action => {
|
||||
const choiceString = `move 1, ${action}, move 1 1`;
|
||||
assert(battle.choose('p1', choiceString), `Choice '${choiceString}' should be valid`);
|
||||
battle.p1.clearChoice();
|
||||
});
|
||||
|
||||
const badDecisions = ['move 1 zmove', 'move 2 mega', 'team 1', 'pass', 'shift'];
|
||||
for (const badDecision of badDecisions) {
|
||||
const choiceString = `move 1, ${badDecision}, move 1 1`;
|
||||
assert.false(battle.choose('p1', choiceString), `Decision '${choiceString}' should be rejected`);
|
||||
const badChoices = ['move 1 zmove', 'move 2 mega', 'team 1', 'pass', 'shift'];
|
||||
for (const badChoice of badChoices) {
|
||||
const choiceString = `move 1, ${badChoice}, move 1 1`;
|
||||
assert.false(battle.choose('p1', choiceString), `Choice '${choiceString}' should be rejected`);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -232,18 +232,18 @@ describe('Choice parser', function () {
|
|||
{species: "Magnezone", ability: 'magnetpull', moves: ['discharge']},
|
||||
]);
|
||||
|
||||
const validDecisions = ['move 1', 'switch 4', 'shift'];
|
||||
const validChoices = ['move 1', 'switch 4', 'shift'];
|
||||
|
||||
validDecisions.forEach(decision => {
|
||||
const choiceString = `${decision}, move 1, move 1 1`;
|
||||
assert(battle.choose('p1', choiceString), `Decision '${choiceString}' should be valid`);
|
||||
validChoices.forEach(action => {
|
||||
const choiceString = `${action}, move 1, move 1 1`;
|
||||
assert(battle.choose('p1', choiceString), `Choice '${choiceString}' should be valid`);
|
||||
battle.p1.clearChoice();
|
||||
});
|
||||
|
||||
const badDecisions = ['move 1 zmove', 'move 2 mega', 'team 1', 'pass'];
|
||||
for (const badDecision of badDecisions) {
|
||||
const choiceString = `${badDecision}, move 1, move 1 1`;
|
||||
assert.false(battle.choose('p1', choiceString), `Decision '${choiceString}' should be rejected`);
|
||||
const badChoices = ['move 1 zmove', 'move 2 mega', 'team 1', 'pass'];
|
||||
for (const badChoice of badChoices) {
|
||||
const choiceString = `${badChoice}, move 1, move 1 1`;
|
||||
assert.false(battle.choose('p1', choiceString), `Choice '${choiceString}' should be rejected`);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -262,18 +262,18 @@ describe('Choice parser', function () {
|
|||
{species: "Magnezone", ability: 'magnetpull', moves: ['discharge']},
|
||||
]);
|
||||
|
||||
const validDecisions = ['move 1 1', 'switch 4', 'shift'];
|
||||
const validChoices = ['move 1 1', 'switch 4', 'shift'];
|
||||
|
||||
validDecisions.forEach(decision => {
|
||||
const choiceString = `move 1, move 1, ${decision}`;
|
||||
assert(battle.choose('p1', choiceString), `Decision '${choiceString}' should be valid`);
|
||||
validChoices.forEach(action => {
|
||||
const choiceString = `move 1, move 1, ${action}`;
|
||||
assert(battle.choose('p1', choiceString), `Choice '${choiceString}' should be valid`);
|
||||
battle.p1.clearChoice();
|
||||
});
|
||||
|
||||
const badDecisions = ['move 1 zmove', 'move 2 mega', 'team 1', 'pass', 'shift blah'];
|
||||
for (const badDecision of badDecisions) {
|
||||
const choiceString = `move 1, move 1, ${badDecision}`;
|
||||
assert.false(battle.choose('p1', choiceString), `Decision '${choiceString}' should be rejected`);
|
||||
const badChoices = ['move 1 zmove', 'move 2 mega', 'team 1', 'pass', 'shift blah'];
|
||||
for (const badChoice of badChoices) {
|
||||
const choiceString = `move 1, move 1, ${badChoice}`;
|
||||
assert.false(battle.choose('p1', choiceString), `Choice '${choiceString}' should be rejected`);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -295,18 +295,18 @@ describe('Choice parser', function () {
|
|||
p1.choosePass().chooseSwitch(4).chooseDefault(); // Forretress switches in to slot #2
|
||||
assert.species(p1.active[1], 'Forretress');
|
||||
|
||||
const validDecisions = ['move spikes', 'move 1'];
|
||||
validDecisions.forEach(decision => {
|
||||
battle.choose('p1', decision);
|
||||
const validChoices = ['move spikes', 'move 1'];
|
||||
validChoices.forEach(action => {
|
||||
battle.choose('p1', action);
|
||||
assert.strictEqual(battle.p1.getChoice(true), `pass, move spikes, pass`);
|
||||
battle.p1.clearChoice();
|
||||
battle.choose('p1', `pass, ${decision}, pass`);
|
||||
battle.choose('p1', `pass, ${action}, pass`);
|
||||
assert.strictEqual(battle.p1.getChoice(true), `pass, move spikes, pass`);
|
||||
battle.p1.clearChoice();
|
||||
battle.choose('p1', `pass, ${decision}`);
|
||||
battle.choose('p1', `pass, ${action}`);
|
||||
assert.strictEqual(battle.p1.getChoice(true), `pass, move spikes, pass`);
|
||||
battle.p1.clearChoice();
|
||||
battle.choose('p1', `${decision}, pass`);
|
||||
battle.choose('p1', `${action}, pass`);
|
||||
assert.strictEqual(battle.p1.getChoice(true), `pass, move spikes, pass`);
|
||||
battle.p1.clearChoice();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -98,13 +98,13 @@ const TRIPLES_TEAMS = {
|
|||
|
||||
let battle;
|
||||
|
||||
describe('Decisions', function () {
|
||||
describe('Choices', function () {
|
||||
afterEach(function () {
|
||||
battle.destroy();
|
||||
});
|
||||
|
||||
describe('Generic', function () {
|
||||
it('should wait for players to send their decisions and run them as soon as they are all received', function (done) {
|
||||
it('should wait for players to send their choicess and run them as soon as they are all received', function (done) {
|
||||
battle = common.createBattle();
|
||||
battle.join('p1', 'Guest 1', 1, [{species: "Mew", ability: 'synchronize', moves: ['recover']}]);
|
||||
battle.join('p2', 'Guest 2', 1, [{species: "Rhydon", ability: 'prankster', moves: ['sketch']}]);
|
||||
|
|
@ -499,7 +499,7 @@ describe('Decisions', function () {
|
|||
}
|
||||
});
|
||||
|
||||
it('should autocomplete a single-slot decision in Singles for no Illusion', function () {
|
||||
it('should autocomplete a single-slot action in Singles for no Illusion', function () {
|
||||
// Backwards-compatibility with the client. It should be useful for 3rd party bots/clients (Android?)
|
||||
for (let i = 0; i < 5; i++) {
|
||||
battle = common.createBattle({preview: true}, SINGLES_TEAMS.full);
|
||||
|
|
@ -736,11 +736,11 @@ describe('Decisions', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Decision extensions', function () {
|
||||
describe('Choice extensions', function () {
|
||||
describe('Undo', function () {
|
||||
const MODES = ['revoke', 'override'];
|
||||
for (const mode of MODES) {
|
||||
it(`should disallow to ${mode} decisions after every player has sent an unrevoked decision`, function () {
|
||||
it(`should disallow to ${mode} decisions after every player has sent an unrevoked action`, function () {
|
||||
battle = common.createBattle({cancel: true});
|
||||
battle.join('p1', 'Guest 1', 1, [{species: "Bulbasaur", ability: 'overgrow', moves: ['tackle', 'growl']}]);
|
||||
battle.join('p2', 'Guest 2', 1, [{species: "Charmander", ability: 'blaze', moves: ['tackle', 'growl']}]);
|
||||
|
|
@ -1113,7 +1113,7 @@ describe('Decision extensions', function () {
|
|||
['Deoxys-Attack', 'Chikorita'].forEach((species, index) => assert.species(battle.p1.active[index], species));
|
||||
});
|
||||
|
||||
it(`should support to ${mode} team order decision on team preview requests`, function () {
|
||||
it(`should support to ${mode} team order action on team preview requests`, function () {
|
||||
battle = common.createBattle({preview: true, cancel: true}, [
|
||||
[{species: 'Bulbasaur', ability: 'overgrow', moves: ['tackle']}, {species: 'Ivysaur', ability: 'overgrow', moves: ['tackle']}],
|
||||
[{species: 'Charmander', ability: 'blaze', moves: ['scratch']}, {species: 'Charmeleon', ability: 'blaze', moves: ['scratch']}],
|
||||
|
|
@ -1140,7 +1140,7 @@ describe('Decision extensions', function () {
|
|||
['Bulbasaur', 'Ivysaur'].forEach((species, index) => assert.species(battle.p1.pokemon[index], species));
|
||||
});
|
||||
|
||||
it(`should disallow to ${mode} team order decision on team preview requests by default`, function () {
|
||||
it(`should disallow to ${mode} team order action on team preview requests by default`, function () {
|
||||
battle = common.createBattle({preview: true}, [
|
||||
[{species: 'Bulbasaur', ability: 'overgrow', moves: ['tackle']}, {species: 'Ivysaur', ability: 'overgrow', moves: ['tackle']}],
|
||||
[{species: 'Charmander', ability: 'blaze', moves: ['scratch']}, {species: 'Charmeleon', ability: 'blaze', moves: ['scratch']}],
|
||||
|
|
@ -1157,7 +1157,7 @@ describe('Decision extensions', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Decision internals', function () {
|
||||
describe('Choice internals', function () {
|
||||
afterEach(function () {
|
||||
battle.destroy();
|
||||
});
|
||||
|
|
@ -1248,7 +1248,7 @@ describe('Decision internals', function () {
|
|||
assert.strictEqual(p1.active[1].name, 'Ekans');
|
||||
});
|
||||
|
||||
it('should empty the decisions list when undoing a move', function () {
|
||||
it('should empty the actions list when undoing a move', function () {
|
||||
battle = common.createBattle({gameType: 'doubles', cancel: true});
|
||||
const p1 = battle.join('p1', 'Guest 1', 1, [
|
||||
{species: "Pineco", ability: 'sturdy', moves: ['selfdestruct']},
|
||||
|
|
@ -1271,7 +1271,7 @@ describe('Decision internals', function () {
|
|||
assert.fainted(p1.active[1]);
|
||||
});
|
||||
|
||||
it('should empty the decisions list when undoing a switch', function () {
|
||||
it('should empty the actions list when undoing a switch', function () {
|
||||
battle = common.createBattle({gameType: 'doubles', cancel: true});
|
||||
const p1 = battle.join('p1', 'Guest 1', 1, [
|
||||
{species: "Pineco", ability: 'sturdy', moves: ['selfdestruct']},
|
||||
|
|
@ -1295,7 +1295,7 @@ describe('Decision internals', function () {
|
|||
assert.species(p1.active[1], 'Koffing');
|
||||
});
|
||||
|
||||
it('should empty the decisions list when undoing a pass', function () {
|
||||
it('should empty the actions list when undoing a pass', function () {
|
||||
battle = common.createBattle({gameType: 'doubles', cancel: true});
|
||||
const p1 = battle.join('p1', 'Guest 1', 1, [
|
||||
{species: "Pineco", ability: 'sturdy', moves: ['selfdestruct']},
|
||||
|
|
@ -1319,7 +1319,7 @@ describe('Decision internals', function () {
|
|||
assert.species(p1.active[1], 'Koffing');
|
||||
});
|
||||
|
||||
it('should empty the decisions list when undoing a shift', function () {
|
||||
it('should empty the actions list when undoing a shift', function () {
|
||||
battle = common.createBattle({gameType: 'triples', cancel: true});
|
||||
battle.supportCancel = true;
|
||||
const p1 = battle.join('p1', 'Guest 1', 1, [
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user