Compare commits

..

No commits in common. "589d06c15ec7ef7661838581be8ac805b4e7ba91" and "92c4f2d9abe8d351a2ff2e9a920a86efce3dc0bb" have entirely different histories.

14 changed files with 48 additions and 215 deletions

View File

@ -31,11 +31,6 @@ body {
transform-origin: top !important; transform-origin: top !important;
} }
/* Need adjust input font-size */
input {
font-size: 3.2rem;
}
#touchControls:not(.visible) { #touchControls:not(.visible) {
display: none; display: none;
} }
@ -248,4 +243,4 @@ input:-internal-autofill-selected {
-webkit-animation: blink normal 4s infinite ease-in-out; /* Webkit */ -webkit-animation: blink normal 4s infinite ease-in-out; /* Webkit */
-ms-animation: blink normal 4s infinite ease-in-out; /* IE */ -ms-animation: blink normal 4s infinite ease-in-out; /* IE */
animation: blink normal 4s infinite ease-in-out; /* Opera and prob css3 final iteration */ animation: blink normal 4s infinite ease-in-out; /* Opera and prob css3 final iteration */
} }

View File

@ -9,7 +9,7 @@ import { BattlerTag } from "./battler-tags";
import { BattlerTagType } from "./enums/battler-tag-type"; import { BattlerTagType } from "./enums/battler-tag-type";
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
import { Gender } from "./gender"; import { Gender } from "./gender";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move"; import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type"; import { ArenaTagType } from "./enums/arena-tag-type";
import { Stat, getStatName } from "./pokemon-stat"; import { Stat, getStatName } from "./pokemon-stat";
@ -357,7 +357,6 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr {
} }
/** /**
* Applies immunity if this ability grants immunity to the type of the given move.
* @param pokemon {@linkcode Pokemon} the defending Pokemon * @param pokemon {@linkcode Pokemon} the defending Pokemon
* @param passive N/A * @param passive N/A
* @param attacker {@linkcode Pokemon} the attacking Pokemon * @param attacker {@linkcode Pokemon} the attacking Pokemon
@ -367,12 +366,7 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr {
* @param args [1] {@linkcode Utils.NumberHolder} type of move being defended against in case it has changed from default type * @param args [1] {@linkcode Utils.NumberHolder} type of move being defended against in case it has changed from default type
*/ */
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
// Field moves should ignore immunity if ((move instanceof AttackMove || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => attr.immuneType === this.immuneType)) && move.type === this.immuneType) {
if ([ MoveTarget.BOTH_SIDES, MoveTarget.ENEMY_SIDE, MoveTarget.USER_SIDE ].includes(move.moveTarget)) {
return false;
}
if (move.type === this.immuneType) {
(args[0] as Utils.NumberHolder).value = 0; (args[0] as Utils.NumberHolder).value = 0;
return true; return true;
} }

View File

@ -1111,7 +1111,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return undefined; return undefined;
} }
return this.getAttackMoveEffectiveness(source, move, !this.battleData?.abilityRevealed); return this.getAttackMoveEffectiveness(source, move, true);
} }
/** /**
@ -1146,9 +1146,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let multiplier = types.map(defType => { let multiplier = types.map(defType => {
if (source) { if (source) {
const ignoreImmunity = new Utils.BooleanHolder(false); const ignoreImmunity = new Utils.BooleanHolder(false);
if (source.isActive(true) && source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr)) { applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, moveType, defType);
applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, moveType, defType);
}
if (ignoreImmunity.value) { if (ignoreImmunity.value) {
return 1; return 1;
} }
@ -2527,9 +2525,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* Resets the status of a pokemon. * Resets the status of a pokemon.
* @param revive Whether revive should be cured; defaults to true. * @param revive Whether revive should be cured; defaults to true.
* @param confusion Whether resetStatus should include confusion or not; defaults to false. * @param confusion Whether resetStatus should include confusion or not; defaults to false.
* @param reloadAssets Whether to reload the assets or not; defaults to false.
*/ */
resetStatus(revive: boolean = true, confusion: boolean = false, reloadAssets: boolean = false): void { resetStatus(revive: boolean = true, confusion: boolean = false): void {
const lastStatus = this.status?.effect; const lastStatus = this.status?.effect;
if (!revive && lastStatus === StatusEffect.FAINT) { if (!revive && lastStatus === StatusEffect.FAINT) {
return; return;
@ -2546,9 +2543,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.lapseTag(BattlerTagType.CONFUSED); this.lapseTag(BattlerTagType.CONFUSED);
} }
} }
if (reloadAssets) {
this.loadAssets(false).then(() => this.playAnim());
}
} }
primeSummonData(summonDataPrimer: PokemonSummonData): void { primeSummonData(summonDataPrimer: PokemonSummonData): void {
@ -3827,7 +3821,6 @@ export class PokemonBattleData {
public endured: boolean = false; public endured: boolean = false;
public berriesEaten: BerryType[] = []; public berriesEaten: BerryType[] = [];
public abilitiesApplied: Abilities[] = []; public abilitiesApplied: Abilities[] = [];
public abilityRevealed: boolean = false;
} }
export class PokemonBattleSummonData { export class PokemonBattleSummonData {

View File

@ -61,5 +61,5 @@ export const battle: SimpleTranslationEntries = {
"useMove": "¡{{pokemonNameWithAffix}} usó {{moveName}}!", "useMove": "¡{{pokemonNameWithAffix}} usó {{moveName}}!",
"drainMessage": "¡{{pokemonName}} tuvo su\nenergía absorbida!", "drainMessage": "¡{{pokemonName}} tuvo su\nenergía absorbida!",
"regainHealth": "¡{{pokemonName}} recuperó\nPS!", "regainHealth": "¡{{pokemonName}} recuperó\nPS!",
"fainted": {{pokemonNameWithAffix}} se debilitó!" "fainted": El {{pokemonNameWithAffix}} se debilitó!"
} as const; } as const;

View File

@ -4,6 +4,6 @@ export const fightUiHandler: SimpleTranslationEntries = {
"pp": "PP", "pp": "PP",
"power": "Potencia", "power": "Potencia",
"accuracy": "Precisión", "accuracy": "Precisión",
"abilityFlyInText": " {{passive}}{{pokemonName}}\n{{abilityName}}", "abilityFlyInText": " {{pokemonName}}'s {{passive}}{{abilityName}}",
"passive": "Pasiva de ", // The space at the end is important "passive": "Passive ", // The space at the end is important
} as const; } as const;

View File

@ -36,26 +36,26 @@ export const PGMdialogue: DialogueTranslationEntries = {
}, },
"lass": { "lass": {
"encounter": { "encounter": {
1: "Affrontons-nous, d'accord ?", 1: "Let's have a battle, shall we?",
2: "Tu as l'air d'un nouveau dresseur. Battons nous !", 2: "You look like a new trainer. Let's have a battle!",
3: "Je ne te reconnais pas. Que dirais-tu de te battre ?", 3: "I don't recognize you. How about a battle?",
4: "Amusons-nous pendant ce combat Pokémon !", 4: "Let's have a fun Pokémon battle!",
5: "Je vais t'apprendre à te battre avec des Pokémon !", 5: "I'll show you the ropes of how to really use Pokémon!",
6: "Un combat doit être pris au sérieux. Es-tu prêt à te battre ?", 6: "A serious battle starts from a serious beginning! Are you sure you're ready?",
7: "Tu ne seras pas jeune éternellement. Tu n'auras qu'une chance pendant un combat. Bientôt, tu ne seras plus qu'un souvenir.", 7: "You're only young once. And you only get one shot at a given battle. Soon, you'll be nothing but a memory.",
8: "Tu ferais mieux d'y aller doucement avec moi. Mais je vais me battre sérieusement !", 8: "You'd better go easy on me, OK? Though I'll be seriously fighting!",
9: "Je m'ennuie à l'école. Je n'ai rien à faire. *Baille*. Je me bats juste pour passer le temps." 9: "School is boring. I've got nothing to do. Yawn. I'm only battling to kill the time."
}, },
"victory": { "victory": {
1: "Wow, c'était impressionnant. J'ai beaucoup à apprendre.", 1: "That was impressive! I've got a lot to learn.",
2: "Je ne pensais pas que je perdrais comme ça…", 2: "I didn't think you'd beat me that bad…",
3: "J'espère que j'aurai ma revanche un jour.", 3: "I hope we get to have a rematch some day.",
4: "C'était super amusant ! Ce combat m'a épuisé…", 4: "That was pretty amazingly fun! You've totally exhausted me…",
5: "Tu m'as appris une belle leçon ! Tu es vraiment incroyable !", 5: "You actually taught me a lesson! You're pretty amazing!",
6: "Vraiment ? J'ai perdu… C'est des choses qui arrivent, ça me déprime mais tu es vraiment très cool.", 6: "Seriously, I lost. That is, like, seriously depressing, but you were seriously cool.",
7: "Je n'ai pas besoin de souvenirs comme ça. *Suppression de la mémoire…*", 7: "I don't need memories like this. Deleting memory…",
8: "Hé ! Je t'avais dit d'y aller doucement avec moi ! Mais tu es vraiment trop cool quand tu te bats sérieusement.", 8: "Hey! I told you to go easy on me! Still, you're pretty cool when you're serious.",
9: "J'en ai marre des combats Pokémon… Il doit y avoir de nouvelles choses à faire…" 9: "I'm actually getting tired of battling… There's gotta be something new to do…"
} }
}, },
"breeder": { "breeder": {
@ -118,14 +118,14 @@ export const PGMdialogue: DialogueTranslationEntries = {
}, },
"swimmer": { "swimmer": {
"encounter": { "encounter": {
1: "C'est l'heure de plonger dans le combat !", 1: "Time to dive in!",
2: "Je vais surfer sur les vagues de la victoire !", 2: "Let's ride the waves of victory!",
3: "Je vais t'éclabousser de mon talent !", 3: "Ready to make a splash!",
}, },
"victory": { "victory": {
1: "Tu m'as complètement séché", 1: "Drenched in defeat!",
2: "Il semblerait que j'ai surfé sur les vagues de la défaite...", 2: "A wave of defeat!",
3: "Retour sur la terre ferme je suppose", 3: "Back to shore, I guess.",
}, },
}, },
"backpacker": { "backpacker": {

View File

@ -4,6 +4,6 @@ export const fightUiHandler: SimpleTranslationEntries = {
"pp": "PP", "pp": "PP",
"power": "Poder", "power": "Poder",
"accuracy": "Precisão", "accuracy": "Precisão",
"abilityFlyInText": " {{passive}}{{pokemonName}}\n{{abilityName}}", "abilityFlyInText": " {{pokemonName}}'s {{passive}}{{abilityName}}",
"passive": "Passiva de ", // The space at the end is important "passive": "Passive ", // The space at the end is important
} as const; } as const;

View File

@ -13,12 +13,6 @@ export const titles: SimpleTranslationEntries = {
"rival": "Rival", "rival": "Rival",
"professor": "Professor", "professor": "Professor",
"frontier_brain": "Cérebro da Fronteira", "frontier_brain": "Cérebro da Fronteira",
"rocket_boss": "Chefe da Equipe Rocket",
"magma_boss": "Chefe da Equipe Magma",
"aqua_boss": "Chefe da Equipe Aqua",
"galactic_boss": "Chefe da Equipe Galáctica",
"plasma_boss": "Chefe da Equipe Plasma",
"flare_boss": "Chefe da Equipe Flare",
// Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc.
} as const; } as const;
@ -125,18 +119,6 @@ export const trainerClasses: SimpleTranslationEntries = {
"worker_female": "Operária", "worker_female": "Operária",
"workers": "Operários", "workers": "Operários",
"youngster": "Jovem", "youngster": "Jovem",
"rocket_grunt": "Recruta da Equipe Rocket",
"rocket_grunt_female": "Recruta da Equipe Rocket",
"magma_grunt": "Recruta da Equipe Magma",
"magma_grunt_female": "Recruta da Equipe Magma",
"aqua_grunt": "Recruta da Equipe Aqua",
"aqua_grunt_female": "Recruta da Equipe Aqua",
"galactic_grunt": "Recruta da Equipe Galáctica",
"galactic_grunt_female": "Recruta da Equipe Galáctica",
"plasma_grunt": "Recruta da Equipe Plasma",
"plasma_grunt_female": "Recruta da Equipe Plasma",
"flare_grunt": "Recruta da Equipe Flare",
"flare_grunt_female": "Recruta da Equipe Flare",
} as const; } as const;
// Names of special trainers like gym leaders, elite four, and the champion // Names of special trainers like gym leaders, elite four, and the champion
@ -265,11 +247,6 @@ export const trainerNames: SimpleTranslationEntries = {
"leon": "Leon", "leon": "Leon",
"rival": "Finn", "rival": "Finn",
"rival_female": "Ivy", "rival_female": "Ivy",
"maxie": "Maxie",
"archie": "Archie",
"cyrus": "Cyrus",
"ghetsis": "Ghetsis",
"lysandre": "Lysandre",
// Double Names // Double Names
"blue_red_double": "Blue & Red", "blue_red_double": "Blue & Red",

View File

@ -1091,7 +1091,8 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier {
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
Math.max(Math.floor(pokemon.getMaxHp() / 2), 1), getPokemonMessage(pokemon, ` was revived\nby its ${this.type.name}!`), false, false, true)); Math.max(Math.floor(pokemon.getMaxHp() / 2), 1), getPokemonMessage(pokemon, ` was revived\nby its ${this.type.name}!`), false, false, true));
pokemon.resetStatus(true, false, true); pokemon.resetStatus();
return true; return true;
} }

View File

@ -3122,12 +3122,7 @@ export class ShowAbilityPhase extends PokemonPhase {
start() { start() {
super.start(); super.start();
const pokemon = this.getPokemon(); this.scene.abilityBar.showAbility(this.getPokemon(), this.passive);
this.scene.abilityBar.showAbility(pokemon, this.passive);
if (pokemon.battleData) {
pokemon.battleData.abilityRevealed = true;
}
this.end(); this.end();
} }

View File

@ -56,9 +56,7 @@ describe("Abilities - Intimidate", () => {
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1);
game.doSwitchPokemon(1); await game.switchPokemon(1);
await game.phaseInterceptor.run(CommandPhase);
await game.phaseInterceptor.to(CommandPhase);
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA); expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA);
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -83,9 +81,7 @@ describe("Abilities - Intimidate", () => {
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1);
game.doSwitchPokemon(1); await game.switchPokemon(1);
await game.phaseInterceptor.run(CommandPhase);
await game.phaseInterceptor.to(CommandPhase);
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA); expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA);
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -110,9 +106,7 @@ describe("Abilities - Intimidate", () => {
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1);
game.doSwitchPokemon(1); await game.switchPokemon(1);
await game.phaseInterceptor.run(CommandPhase);
await game.phaseInterceptor.to(CommandPhase);
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA); expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA);
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;

View File

@ -1,116 +0,0 @@
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
import Phaser from "phaser";
import GameManager from "#app/test/utils/gameManager";
import * as overrides from "#app/overrides";
import {Species} from "#app/data/enums/species";
import {
CommandPhase,
EnemyCommandPhase, TurnEndPhase,
} from "#app/phases";
import {Mode} from "#app/ui/ui";
import {Moves} from "#app/data/enums/moves";
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
import {Command} from "#app/ui/command-ui-handler";
import { Abilities } from "#app/data/enums/abilities.js";
import { BattleStat } from "#app/data/battle-stat.js";
import { TerrainType } from "#app/data/terrain.js";
// See also: ArenaTypeAbAttr
describe("Abilities - Sap Sipper", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "NEVER_CRIT_OVERRIDE", "get").mockReturnValue(true);
});
it("raise attack 1 level and block effects when activated against a grass attack", async() => {
const moveToUse = Moves.LEAFAGE;
const enemyAbility = Abilities.SAP_SIPPER;
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.NONE, Moves.NONE, Moves.NONE]);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.DUSKULL);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(enemyAbility);
await game.startBattle();
const startingOppHp = game.scene.currentBattle.enemyParty[0].hp;
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase);
expect(startingOppHp - game.scene.getEnemyParty()[0].hp).toBe(0);
expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1);
});
it("raise attack 1 level and block effects when activated against a grass status move", async() => {
const moveToUse = Moves.SPORE;
const enemyAbility = Abilities.SAP_SIPPER;
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.NONE, Moves.NONE, Moves.NONE]);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(enemyAbility);
await game.startBattle();
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase);
expect(game.scene.getEnemyParty()[0].status).toBeUndefined();
expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1);
});
it("do not activate against status moves that target the field", async() => {
const moveToUse = Moves.GRASSY_TERRAIN;
const enemyAbility = Abilities.SAP_SIPPER;
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.NONE, Moves.NONE, Moves.NONE]);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(enemyAbility);
await game.startBattle();
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase);
expect(game.scene.arena.terrain).toBeDefined();
expect(game.scene.arena.terrain.terrainType).toBe(TerrainType.GRASSY);
expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(0);
});
});

View File

@ -74,11 +74,11 @@ describe("Moves - Spikes", () => {
await game.phaseInterceptor.to(CommandPhase, false); await game.phaseInterceptor.to(CommandPhase, false);
const initialHp = game.scene.getParty()[0].hp; const initialHp = game.scene.getParty()[0].hp;
game.doSwitchPokemon(1); await game.switchPokemon(1, false);
await game.phaseInterceptor.run(CommandPhase); await game.phaseInterceptor.run(CommandPhase);
await game.phaseInterceptor.to(CommandPhase, false); await game.phaseInterceptor.to(CommandPhase, false);
game.doSwitchPokemon(1); await game.switchPokemon(1, false);
await game.phaseInterceptor.run(CommandPhase); await game.phaseInterceptor.run(CommandPhase);
await game.phaseInterceptor.to(CommandPhase, false); await game.phaseInterceptor.to(CommandPhase, false);

View File

@ -290,16 +290,16 @@ export default class GameManager {
}); });
} }
/** async switchPokemon(pokemonIndex: number, toNext: boolean = true) {
* Switch pokemon and transition to the enemy command phase
* @param pokemonIndex the index of the pokemon in your party to switch to
*/
doSwitchPokemon(pokemonIndex: number) {
this.onNextPrompt("CommandPhase", Mode.COMMAND, () => { this.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
this.scene.ui.setMode(Mode.PARTY, PartyUiMode.SWITCH, (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getFieldIndex(), null, PartyUiHandler.FilterNonFainted); this.scene.ui.setMode(Mode.PARTY, PartyUiMode.SWITCH, (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getFieldIndex(), null, PartyUiHandler.FilterNonFainted);
}); });
this.onNextPrompt("CommandPhase", Mode.PARTY, () => { this.onNextPrompt("CommandPhase", Mode.PARTY, () => {
(this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.POKEMON, pokemonIndex, false); (this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.POKEMON, pokemonIndex, false);
}); });
if (toNext) {
await this.phaseInterceptor.run(CommandPhase);
await this.phaseInterceptor.to(CommandPhase);
}
} }
} }