[Move] Fully Implement Round (#4783)
This commit is contained in:
parent
3f97c9e39f
commit
c3d832aaca
|
@ -4161,6 +4161,60 @@ export class CombinedPledgeStabBoostAttr extends MoveAttr {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Variable Power attribute for {@link https://bulbapedia.bulbagarden.net/wiki/Round_(move) | Round}.
|
||||
* Doubles power if another Pokemon has previously selected Round this turn.
|
||||
* @extends VariablePowerAttr
|
||||
*/
|
||||
export class RoundPowerAttr extends VariablePowerAttr {
|
||||
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const power = args[0];
|
||||
if (!(power instanceof Utils.NumberHolder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (user.turnData?.joinedRound) {
|
||||
power.value *= 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute for the "combo" effect of {@link https://bulbapedia.bulbagarden.net/wiki/Round_(move) | Round}.
|
||||
* Preempts the next move in the turn order with the first instance of any Pokemon
|
||||
* using Round. Also marks the Pokemon using the cued Round to double the move's power.
|
||||
* @extends MoveEffectAttr
|
||||
* @see {@linkcode RoundPowerAttr}
|
||||
*/
|
||||
export class CueNextRoundAttr extends MoveEffectAttr {
|
||||
constructor() {
|
||||
super(true, { lastHitOnly: true });
|
||||
}
|
||||
|
||||
override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean {
|
||||
const nextRoundPhase = user.scene.findPhase<MovePhase>(phase =>
|
||||
phase instanceof MovePhase && phase.move.moveId === Moves.ROUND
|
||||
);
|
||||
|
||||
if (!nextRoundPhase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the phase queue so that the next Pokemon using Round moves next
|
||||
const nextRoundIndex = user.scene.phaseQueue.indexOf(nextRoundPhase);
|
||||
const nextMoveIndex = user.scene.phaseQueue.findIndex(phase => phase instanceof MovePhase);
|
||||
if (nextRoundIndex !== nextMoveIndex) {
|
||||
user.scene.prependToPhase(user.scene.phaseQueue.splice(nextRoundIndex, 1)[0], MovePhase);
|
||||
}
|
||||
|
||||
// Mark the corresponding Pokemon as having "joined the Round" (for doubling power later)
|
||||
nextRoundPhase.pokemon.turnData.joinedRound = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class VariableAtkAttr extends MoveAttr {
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -8960,8 +9014,9 @@ export function initMoves() {
|
|||
.condition((user, target, move) => !target.turnData.acted)
|
||||
.attr(AfterYouAttr),
|
||||
new AttackMove(Moves.ROUND, Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 5)
|
||||
.soundBased()
|
||||
.partial(), // No effect implemented
|
||||
.attr(CueNextRoundAttr)
|
||||
.attr(RoundPowerAttr)
|
||||
.soundBased(),
|
||||
new AttackMove(Moves.ECHOED_VOICE, Type.NORMAL, MoveCategory.SPECIAL, 40, 100, 15, -1, 0, 5)
|
||||
.attr(ConsecutiveUseMultiBasePowerAttr, 5, false)
|
||||
.soundBased(),
|
||||
|
|
|
@ -5194,6 +5194,7 @@ export class PokemonTurnData {
|
|||
public combiningPledge?: Moves;
|
||||
public switchedInThisTurn: boolean = false;
|
||||
public failedRunAway: boolean = false;
|
||||
public joinedRound: boolean = false;
|
||||
}
|
||||
|
||||
export enum AiType {
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import { BattlerIndex } from "#app/battle";
|
||||
import { allMoves } from "#app/data/move";
|
||||
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
describe("Moves - Round", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([ Moves.SPLASH, Moves.ROUND ])
|
||||
.ability(Abilities.BALL_FETCH)
|
||||
.battleType("double")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyMoveset([ Moves.SPLASH, Moves.ROUND ])
|
||||
.startingLevel(100)
|
||||
.enemyLevel(100);
|
||||
});
|
||||
|
||||
it("should cue other instances of Round together in Speed order", async () => {
|
||||
await game.classicMode.startBattle([ Species.MAGIKARP, Species.FEEBAS ]);
|
||||
|
||||
const round = allMoves[Moves.ROUND];
|
||||
const spy = vi.spyOn(round, "calculateBattlePower");
|
||||
|
||||
game.move.select(Moves.ROUND, 0, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.ROUND, 1, BattlerIndex.ENEMY_2);
|
||||
|
||||
await game.forceEnemyMove(Moves.ROUND, BattlerIndex.PLAYER);
|
||||
await game.forceEnemyMove(Moves.SPLASH);
|
||||
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]);
|
||||
|
||||
const actualTurnOrder: BattlerIndex[] = [];
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
await game.phaseInterceptor.to("MoveEffectPhase", false);
|
||||
actualTurnOrder.push((game.scene.getCurrentPhase() as MoveEffectPhase).getUserPokemon()!.getBattlerIndex());
|
||||
await game.phaseInterceptor.to("MoveEndPhase");
|
||||
}
|
||||
|
||||
expect(actualTurnOrder).toEqual([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||
const powerResults = spy.mock.results.map(result => result.value);
|
||||
expect(powerResults).toEqual( [ 60, 120, 120 ]);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue