Skip to content

Commit

Permalink
Support and document /move max mindstorm
Browse files Browse the repository at this point in the history
Dynamax and Z move decisions can now be input by naming the max move
or z-move involved.

Fix #6425
  • Loading branch information
Zarel committed Mar 22, 2020
1 parent 0d06b22 commit 90c5037
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 13 deletions.
2 changes: 2 additions & 0 deletions sim/SIM-PROTOCOL.md
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,8 @@ To be exact, `CHOICE` is one of:

- `move MOVESPEC zmove`, to use a z-move version of a move

- `move MOVESPEC max`, to Dynamax/Gigantamax and make a move

- `switch SWITCHSPEC`, to make a switch

`MOVESPEC` is:
Expand Down
2 changes: 1 addition & 1 deletion sim/pokemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ export class Pokemon {
if (this.canUltraBurst) data.canUltraBurst = true;
const canZMove = this.battle.canZMove(this);
if (canZMove) data.canZMove = canZMove;
// TODO interaction between dynamax and choice locked moves?

if (this.battle.canDynamax(this)) data.canDynamax = true;
if (data.canDynamax || this.volatiles['dynamax']) data.maxMoves = this.battle.canDynamax(this, true);
}
Expand Down
50 changes: 38 additions & 12 deletions sim/side.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ export class Side {
return this.choice.actions.length >= this.active.length;
}

chooseMove(moveText?: string | number, targetLoc?: number, megaDynaOrZ?: boolean | string) {
chooseMove(moveText?: string | number, targetLoc = 0, megaDynaOrZ: 'mega' | 'zmove' | 'ultra' | 'dynamax' | '' = '') {
if (this.requestState !== 'move') {
return this.emitChoiceError(`Can't move: You need a ${this.requestState} response`);
}
Expand All @@ -338,44 +338,62 @@ export class Side {
const autoChoose = !moveText;
const pokemon: Pokemon = this.active[index];

if (megaDynaOrZ === true) megaDynaOrZ = 'mega';
if (!targetLoc) targetLoc = 0;

// Parse moveText (name or index)
// If the move is not found, the action is invalid without requiring further inspection.

const requestMoves = pokemon.getMoveRequestData().moves;
const request = pokemon.getMoveRequestData();
let moveid = '';
let targetType = '';
if (autoChoose) moveText = 1;
if (typeof moveText === 'number' || (moveText && /^[0-9]+$/.test(moveText))) {
// Parse a one-based move index.
const moveIndex = +moveText - 1;
if (moveIndex < 0 || moveIndex >= requestMoves.length || !requestMoves[moveIndex]) {
const moveIndex = Number(moveText) - 1;
if (moveIndex < 0 || moveIndex >= request.moves.length || !request.moves[moveIndex]) {
return this.emitChoiceError(`Can't move: Your ${pokemon.name} doesn't have a move ${moveIndex + 1}`);
}
moveid = requestMoves[moveIndex].id;
targetType = requestMoves[moveIndex].target!;
moveid = request.moves[moveIndex].id;
targetType = request.moves[moveIndex].target!;
} else {
// Parse a move ID.
// Move names are also allowed, but may cause ambiguity (see client issue #167).
moveid = toID(moveText);
if (moveid.startsWith('hiddenpower')) {
moveid = 'hiddenpower';
}
for (const move of requestMoves) {
for (const move of request.moves) {
if (move.id !== moveid) continue;
targetType = move.target || 'normal';
break;
}
if (!targetType && ['', 'dynamax'].includes(megaDynaOrZ) && request.maxMoves) {
for (const [i, moveRequest] of request.maxMoves.maxMoves.entries()) {
if (moveid === moveRequest.move) {
moveid = request.moves[i].id;
targetType = moveRequest.target;
megaDynaOrZ = 'dynamax';
break;
}
}
}
if (!targetType && ['', 'zmove'].includes(megaDynaOrZ) && request.canZMove) {
for (const [i, moveRequest] of request.canZMove.entries()) {
if (!moveRequest) continue;
if (moveid === toID(moveRequest.move)) {
moveid = request.moves[i].id;
targetType = moveRequest.target;
megaDynaOrZ = 'zmove';
break;
}
}
}
if (!targetType) {
return this.emitChoiceError(`Can't move: Your ${pokemon.name} doesn't have a move matching ${moveid}`);
}
}

const moves = pokemon.getMoves();
if (autoChoose) {
for (const [i, move] of requestMoves.entries()) {
for (const [i, move] of request.moves.entries()) {
if (move.disabled) continue;
if (i < moves.length && move.id === moves[i].id && moves[i].disabled) continue;
moveid = move.id;
Expand Down Expand Up @@ -759,7 +777,7 @@ export class Side {
const original = data;
const error = () => this.emitChoiceError(`Conflicting arguments for "move": ${original}`);
let targetLoc: number | undefined;
let megaDynaOrZ = '';
let megaDynaOrZ: 'mega' | 'zmove' | 'ultra' | 'dynamax' | '' = '';
while (true) {
// If data ends with a number, treat it as a target location.
// We need to special case 'Conversion 2' so it doesn't get
Expand All @@ -785,6 +803,14 @@ export class Side {
if (megaDynaOrZ) return error();
megaDynaOrZ = 'dynamax';
data = data.slice(0, -8);
} else if (data.endsWith(' gigantamax')) {
if (megaDynaOrZ) return error();
megaDynaOrZ = 'dynamax';
data = data.slice(0, -11);
} else if (data.endsWith(' max')) {
if (megaDynaOrZ) return error();
megaDynaOrZ = 'dynamax';
data = data.slice(0, -4);
} else {
break;
}
Expand Down
12 changes: 12 additions & 0 deletions test/sim/choice-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ describe('Choice parser', function () {
assert(battle.choose('p2', `move Blaze Kick zmove 1, move irondefense`));
});

it('should allow Dynamax use in multiple possible formats', function () {
battle = common.createBattle([[
{species: "Mew", moves: ['psychic']},
], [
{species: "Mew", moves: ['psychic']},
]]);

battle.makeChoices(`move max mindstorm`, `move psychic max`);
assert(battle.p1.active[0].volatiles['dynamax']);
assert(battle.p2.active[0].volatiles['dynamax']);
});

it('should handle Conversion 2', function () {
battle = common.createBattle({gameType: 'doubles'});
battle.setPlayer('p1', {team: [
Expand Down

0 comments on commit 90c5037

Please sign in to comment.