mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-12 03:12:18 +02:00
Merge branch 'beta' into learnMovePhase
This commit is contained in:
commit
fe032bcf71
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.3 KiB |
@ -3475,12 +3475,12 @@ export class MoodyAbAttr extends PostTurnAbAttr {
|
|||||||
|
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
if (canRaise.length > 0) {
|
if (canRaise.length > 0) {
|
||||||
const raisedStat = Utils.randSeedItem(canRaise);
|
const raisedStat = canRaise[pokemon.randSeedInt(canRaise.length)];
|
||||||
canLower = canRaise.filter(s => s !== raisedStat);
|
canLower = canRaise.filter(s => s !== raisedStat);
|
||||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ raisedStat ], 2));
|
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ raisedStat ], 2));
|
||||||
}
|
}
|
||||||
if (canLower.length > 0) {
|
if (canLower.length > 0) {
|
||||||
const loweredStat = Utils.randSeedItem(canLower);
|
const loweredStat = canLower[pokemon.randSeedInt(canLower.length)];
|
||||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ loweredStat ], -1));
|
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ loweredStat ], -1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import {pokemonEvolutions, SpeciesFormEvolution} from "./pokemon-evolutions";
|
import { pokemonEvolutions, SpeciesFormEvolution } from "./pokemon-evolutions";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { Biome } from "#enums/biome";
|
import { Biome } from "#enums/biome";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
@ -46,7 +46,7 @@ export const biomeLinks: BiomeLinks = {
|
|||||||
[Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 3 ] ],
|
[Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 3 ] ],
|
||||||
[Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.WASTELAND, 2 ], [ Biome.SPACE, 3 ] ],
|
[Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.WASTELAND, 2 ], [ Biome.SPACE, 3 ] ],
|
||||||
[Biome.BADLANDS]: [ Biome.DESERT, Biome.MOUNTAIN ],
|
[Biome.BADLANDS]: [ Biome.DESERT, Biome.MOUNTAIN ],
|
||||||
[Biome.CAVE]: [ Biome.BADLANDS, Biome.LAKE [ Biome.LABORATORY, 2 ] ],
|
[Biome.CAVE]: [ Biome.BADLANDS, Biome.LAKE, [ Biome.LABORATORY, 2 ] ],
|
||||||
[Biome.DESERT]: [ Biome.RUINS, [ Biome.CONSTRUCTION_SITE, 2 ] ],
|
[Biome.DESERT]: [ Biome.RUINS, [ Biome.CONSTRUCTION_SITE, 2 ] ],
|
||||||
[Biome.ICE_CAVE]: Biome.SNOWY_FOREST,
|
[Biome.ICE_CAVE]: Biome.SNOWY_FOREST,
|
||||||
[Biome.MEADOW]: [ Biome.PLAINS, Biome.FAIRY_CAVE ],
|
[Biome.MEADOW]: [ Biome.PLAINS, Biome.FAIRY_CAVE ],
|
||||||
|
@ -2675,7 +2675,7 @@ export class AcupressureStatStageChangeAttr extends MoveEffectAttr {
|
|||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
|
||||||
const randStats = BATTLE_STATS.filter(s => target.getStatStage(s) < 6);
|
const randStats = BATTLE_STATS.filter(s => target.getStatStage(s) < 6);
|
||||||
if (randStats.length > 0) {
|
if (randStats.length > 0) {
|
||||||
const boostStat = [randStats[Utils.randInt(randStats.length)]];
|
const boostStat = [randStats[user.randSeedInt(randStats.length)]];
|
||||||
user.scene.unshiftPhase(new StatStageChangePhase(user.scene, target.getBattlerIndex(), this.selfTarget, boostStat, 2));
|
user.scene.unshiftPhase(new StatStageChangePhase(user.scene, target.getBattlerIndex(), this.selfTarget, boostStat, 2));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -944,7 +944,7 @@ export function initSpecies() {
|
|||||||
new PokemonSpecies(Species.METAPOD, 1, false, false, false, "Cocoon Pokémon", Type.BUG, null, 0.7, 9.9, Abilities.SHED_SKIN, Abilities.NONE, Abilities.SHED_SKIN, 205, 50, 20, 55, 25, 25, 30, 120, 50, 72, GrowthRate.MEDIUM_FAST, 50, false),
|
new PokemonSpecies(Species.METAPOD, 1, false, false, false, "Cocoon Pokémon", Type.BUG, null, 0.7, 9.9, Abilities.SHED_SKIN, Abilities.NONE, Abilities.SHED_SKIN, 205, 50, 20, 55, 25, 25, 30, 120, 50, 72, GrowthRate.MEDIUM_FAST, 50, false),
|
||||||
new PokemonSpecies(Species.BUTTERFREE, 1, false, false, false, "Butterfly Pokémon", Type.BUG, Type.FLYING, 1.1, 32, Abilities.COMPOUND_EYES, Abilities.NONE, Abilities.TINTED_LENS, 395, 60, 45, 50, 90, 80, 70, 45, 50, 198, GrowthRate.MEDIUM_FAST, 50, true, true,
|
new PokemonSpecies(Species.BUTTERFREE, 1, false, false, false, "Butterfly Pokémon", Type.BUG, Type.FLYING, 1.1, 32, Abilities.COMPOUND_EYES, Abilities.NONE, Abilities.TINTED_LENS, 395, 60, 45, 50, 90, 80, 70, 45, 50, 198, GrowthRate.MEDIUM_FAST, 50, true, true,
|
||||||
new PokemonForm("Normal", "", Type.BUG, Type.FLYING, 1.1, 32, Abilities.COMPOUND_EYES, Abilities.NONE, Abilities.TINTED_LENS, 395, 60, 45, 50, 90, 80, 70, 45, 50, 198, true, null, true),
|
new PokemonForm("Normal", "", Type.BUG, Type.FLYING, 1.1, 32, Abilities.COMPOUND_EYES, Abilities.NONE, Abilities.TINTED_LENS, 395, 60, 45, 50, 90, 80, 70, 45, 50, 198, true, null, true),
|
||||||
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.BUG, Type.FLYING, 17, 32, Abilities.TINTED_LENS, Abilities.TINTED_LENS, Abilities.TINTED_LENS, 495, 85, 35, 80, 120, 90, 85, 45, 50, 198, true),
|
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.BUG, Type.FLYING, 17, 32, Abilities.COMPOUND_EYES, Abilities.COMPOUND_EYES, Abilities.COMPOUND_EYES, 495, 85, 35, 80, 120, 90, 85, 45, 50, 198, true),
|
||||||
),
|
),
|
||||||
new PokemonSpecies(Species.WEEDLE, 1, false, false, false, "Hairy Bug Pokémon", Type.BUG, Type.POISON, 0.3, 3.2, Abilities.SHIELD_DUST, Abilities.NONE, Abilities.RUN_AWAY, 195, 40, 35, 30, 20, 20, 50, 255, 70, 39, GrowthRate.MEDIUM_FAST, 50, false),
|
new PokemonSpecies(Species.WEEDLE, 1, false, false, false, "Hairy Bug Pokémon", Type.BUG, Type.POISON, 0.3, 3.2, Abilities.SHIELD_DUST, Abilities.NONE, Abilities.RUN_AWAY, 195, 40, 35, 30, 20, 20, 50, 255, 70, 39, GrowthRate.MEDIUM_FAST, 50, false),
|
||||||
new PokemonSpecies(Species.KAKUNA, 1, false, false, false, "Cocoon Pokémon", Type.BUG, Type.POISON, 0.6, 10, Abilities.SHED_SKIN, Abilities.NONE, Abilities.SHED_SKIN, 205, 45, 25, 50, 25, 25, 35, 120, 70, 72, GrowthRate.MEDIUM_FAST, 50, false),
|
new PokemonSpecies(Species.KAKUNA, 1, false, false, false, "Cocoon Pokémon", Type.BUG, Type.POISON, 0.6, 10, Abilities.SHED_SKIN, Abilities.NONE, Abilities.SHED_SKIN, 205, 45, 25, 50, 25, 25, 35, 120, 70, 72, GrowthRate.MEDIUM_FAST, 50, false),
|
||||||
|
@ -246,7 +246,7 @@ export class LoadingScene extends SceneBase {
|
|||||||
} else {
|
} else {
|
||||||
this.loadAtlas("types", "");
|
this.loadAtlas("types", "");
|
||||||
}
|
}
|
||||||
const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es", "pt_BR", "zh_CN"];
|
const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN"];
|
||||||
if (lang && availableLangs.includes(lang)) {
|
if (lang && availableLangs.includes(lang)) {
|
||||||
this.loadImage("september-update-"+lang, "events");
|
this.loadImage("september-update-"+lang, "events");
|
||||||
} else {
|
} else {
|
||||||
|
@ -94,5 +94,6 @@
|
|||||||
"retryBattle": "Möchtest du vom Beginn des Kampfes neustarten?",
|
"retryBattle": "Möchtest du vom Beginn des Kampfes neustarten?",
|
||||||
"unlockedSomething": "{{unlockedThing}} wurde freigeschaltet.",
|
"unlockedSomething": "{{unlockedThing}} wurde freigeschaltet.",
|
||||||
"congratulations": "Glückwunsch!",
|
"congratulations": "Glückwunsch!",
|
||||||
"beatModeFirstTime": "{{speciesName}} hat den {{gameMode}} Modus zum ersten Mal beendet! Du erhältst {{newModifier}}!"
|
"beatModeFirstTime": "{{speciesName}} hat den {{gameMode}} Modus zum ersten Mal beendet! Du erhältst {{newModifier}}!",
|
||||||
|
"eggSkipPrompt": "Zur Ei-Zusammenfassung springen?"
|
||||||
}
|
}
|
@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"noneSelected": "Keine ausgewählt",
|
||||||
"title": "Herausforderungsmodifikatoren",
|
"title": "Herausforderungsmodifikatoren",
|
||||||
"illegalEvolution": "{{pokemon}} hat sich in ein Pokémon verwandelt, dass für diese Herausforderung nicht zulässig ist!",
|
"illegalEvolution": "{{pokemon}} hat sich in ein Pokémon verwandelt, dass für diese Herausforderung nicht zulässig ist!",
|
||||||
"singleGeneration": {
|
"singleGeneration": {
|
||||||
"name": "Mono-Generation",
|
"name": "Mono-Generation",
|
||||||
"desc": "Du kannst nur Pokémon aus der {{gen}} Generation verwenden.",
|
"desc": "Du kannst nur Pokémon aus der {{gen}} Generation verwenden.",
|
||||||
"desc_default": "Du kannst nur Pokémon gewählten Generation verwenden.",
|
"desc_default": "Du kannst nur Pokémon aus der gewählten Generation verwenden.",
|
||||||
"gen_1": "ersten",
|
"gen_1": "ersten",
|
||||||
"gen_2": "zweiten",
|
"gen_2": "zweiten",
|
||||||
"gen_3": "dritten",
|
"gen_3": "dritten",
|
||||||
|
@ -25,5 +25,6 @@
|
|||||||
"unlinkGoogle": "Google trennen",
|
"unlinkGoogle": "Google trennen",
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"losingProgressionWarning": "Du wirst jeglichen Fortschritt seit Anfang dieses Kampfes verlieren. Fortfahren?",
|
"losingProgressionWarning": "Du wirst jeglichen Fortschritt seit Anfang dieses Kampfes verlieren. Fortfahren?",
|
||||||
"noEggs": "Du brütest aktuell keine Eier aus!"
|
"noEggs": "Du brütest aktuell keine Eier aus!",
|
||||||
|
"donate": "Spenden"
|
||||||
}
|
}
|
@ -94,5 +94,6 @@
|
|||||||
"retryBattle": "Voulez-vous réessayer depuis le début du combat ?",
|
"retryBattle": "Voulez-vous réessayer depuis le début du combat ?",
|
||||||
"unlockedSomething": "{{unlockedThing}}\na été débloqué.",
|
"unlockedSomething": "{{unlockedThing}}\na été débloqué.",
|
||||||
"congratulations": "Félicitations !",
|
"congratulations": "Félicitations !",
|
||||||
"beatModeFirstTime": "{{speciesName}} a battu le mode {{gameMode}} pour la première fois !\nVous avez reçu {{newModifier}} !"
|
"beatModeFirstTime": "{{speciesName}} a battu le mode {{gameMode}} pour la première fois !\nVous avez reçu {{newModifier}} !",
|
||||||
}
|
"eggSkipPrompt": "Aller directement au résumé des Œufs éclos ?"
|
||||||
|
}
|
||||||
|
@ -25,5 +25,6 @@
|
|||||||
"unlinkGoogle": "Délier Google",
|
"unlinkGoogle": "Délier Google",
|
||||||
"cancel": "Retour",
|
"cancel": "Retour",
|
||||||
"losingProgressionWarning": "Vous allez perdre votre progression depuis le début du combat. Continuer ?",
|
"losingProgressionWarning": "Vous allez perdre votre progression depuis le début du combat. Continuer ?",
|
||||||
"noEggs": "Vous ne faites actuellement\néclore aucun Œuf !"
|
"noEggs": "Vous ne faites actuellement\néclore aucun Œuf !",
|
||||||
}
|
"donate": "Faire un don"
|
||||||
|
}
|
||||||
|
@ -161,9 +161,11 @@ export class EncounterPhase extends BattlePhase {
|
|||||||
return this.scene.reset(true);
|
return this.scene.reset(true);
|
||||||
}
|
}
|
||||||
this.doEncounter();
|
this.doEncounter();
|
||||||
|
this.scene.resetSeed();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.doEncounter();
|
this.doEncounter();
|
||||||
|
this.scene.resetSeed();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -946,7 +946,7 @@ export class GameData {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSessionSaveData(scene: BattleScene): SessionSaveData {
|
public getSessionSaveData(scene: BattleScene): SessionSaveData {
|
||||||
return {
|
return {
|
||||||
seed: scene.seed,
|
seed: scene.seed,
|
||||||
playTime: scene.sessionPlayTime,
|
playTime: scene.sessionPlayTime,
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
import { Stat } from "#enums/stat";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import GameManager from "#test/utils/gameManager";
|
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
|
|
||||||
import { VictoryPhase } from "#app/phases/victory-phase";
|
|
||||||
import { TurnStartPhase } from "#app/phases/turn-start-phase";
|
|
||||||
import { BattlerIndex } from "#app/battle";
|
|
||||||
|
|
||||||
describe("Abilities - Beast Boost", () => {
|
describe("Abilities - Beast Boost", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
@ -37,49 +34,44 @@ describe("Abilities - Beast Boost", () => {
|
|||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(SPLASH_ONLY);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note that both MOXIE and BEAST_BOOST test for their current implementation and not their mainline behavior.
|
|
||||||
it("should prefer highest stat to boost its corresponding stat stage by 1 when winning a battle", async() => {
|
it("should prefer highest stat to boost its corresponding stat stage by 1 when winning a battle", async() => {
|
||||||
// SLOWBRO's highest stat is DEF, so it should be picked here
|
await game.classicMode.startBattle([Species.SLOWBRO]);
|
||||||
await game.startBattle([
|
|
||||||
Species.SLOWBRO
|
|
||||||
]);
|
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
// Set the pokemon's highest stat to DEF, so it should be picked by Beast Boost
|
||||||
|
vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([ 10000, 100, 1000, 200, 100, 100 ]);
|
||||||
|
console.log(playerPokemon.stats);
|
||||||
|
|
||||||
expect(playerPokemon.getStatStage(Stat.DEF)).toBe(0);
|
expect(playerPokemon.getStatStage(Stat.DEF)).toBe(0);
|
||||||
|
|
||||||
game.move.select(Moves.FLAMETHROWER);
|
game.move.select(Moves.FLAMETHROWER);
|
||||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(VictoryPhase);
|
await game.phaseInterceptor.to("VictoryPhase");
|
||||||
|
|
||||||
expect(playerPokemon.getStatStage(Stat.DEF)).toBe(1);
|
expect(playerPokemon.getStatStage(Stat.DEF)).toBe(1);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("should use in-battle overriden stats when determining the stat stage to raise by 1", async() => {
|
it("should use in-battle overriden stats when determining the stat stage to raise by 1", async() => {
|
||||||
// If the opponent can GUARD_SPLIT, SLOWBRO's second highest stat should be SPATK
|
|
||||||
game.override.enemyMoveset(new Array(4).fill(Moves.GUARD_SPLIT));
|
game.override.enemyMoveset(new Array(4).fill(Moves.GUARD_SPLIT));
|
||||||
|
|
||||||
await game.startBattle([
|
await game.classicMode.startBattle([Species.SLOWBRO]);
|
||||||
Species.SLOWBRO
|
|
||||||
]);
|
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
// If the opponent uses Guard Split, the pokemon's second highest stat (SPATK) should be chosen
|
||||||
|
vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([ 10000, 100, 201, 200, 100, 100 ]);
|
||||||
|
|
||||||
expect(playerPokemon.getStatStage(Stat.SPATK)).toBe(0);
|
expect(playerPokemon.getStatStage(Stat.SPATK)).toBe(0);
|
||||||
|
|
||||||
game.move.select(Moves.FLAMETHROWER);
|
game.move.select(Moves.FLAMETHROWER);
|
||||||
|
|
||||||
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
|
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
|
||||||
|
await game.phaseInterceptor.to("VictoryPhase");
|
||||||
await game.phaseInterceptor.runFrom(TurnStartPhase).to(VictoryPhase);
|
|
||||||
|
|
||||||
expect(playerPokemon.getStatStage(Stat.SPATK)).toBe(1);
|
expect(playerPokemon.getStatStage(Stat.SPATK)).toBe(1);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("should have order preference in case of stat ties", async() => {
|
it("should have order preference in case of stat ties", async() => {
|
||||||
// Order preference follows the order of EFFECTIVE_STAT
|
// Order preference follows the order of EFFECTIVE_STAT
|
||||||
await game.startBattle([
|
await game.classicMode.startBattle([Species.SLOWBRO]);
|
||||||
Species.SLOWBRO
|
|
||||||
]);
|
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
@ -90,7 +82,7 @@ describe("Abilities - Beast Boost", () => {
|
|||||||
|
|
||||||
game.move.select(Moves.FLAMETHROWER);
|
game.move.select(Moves.FLAMETHROWER);
|
||||||
|
|
||||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(VictoryPhase);
|
await game.phaseInterceptor.to("VictoryPhase");
|
||||||
|
|
||||||
expect(playerPokemon.getStatStage(Stat.SPATK)).toBe(1);
|
expect(playerPokemon.getStatStage(Stat.SPATK)).toBe(1);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
@ -10,7 +10,7 @@ import { EnemyPokemon } from "#app/field/pokemon";
|
|||||||
import { toDmgValue } from "#app/utils";
|
import { toDmgValue } from "#app/utils";
|
||||||
|
|
||||||
describe("Boss Pokemon / Shields", () => {
|
describe("Boss Pokemon / Shields", () => {
|
||||||
const TIMEOUT = 2500;
|
const TIMEOUT = 20 * 1000;
|
||||||
|
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
137
src/test/reload.test.ts
Normal file
137
src/test/reload.test.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import { Species } from "#app/enums/species";
|
||||||
|
import { GameModes } from "#app/game-mode";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
import { SPLASH_ONLY } from "./utils/testUtils";
|
||||||
|
import { Moves } from "#app/enums/moves";
|
||||||
|
import { Biome } from "#app/enums/biome";
|
||||||
|
|
||||||
|
describe("Reload", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not have RNG inconsistencies in a Classic run", async () => {
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
|
const preReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const postReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
expect(preReloadRngState).toBe(postReloadRngState);
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
|
it("should not have RNG inconsistencies after a biome switch", async () => {
|
||||||
|
game.override
|
||||||
|
.startingWave(10)
|
||||||
|
.startingBiome(Biome.CAVE) // Will lead to biomes with randomly generated weather
|
||||||
|
.battleType("single")
|
||||||
|
.startingLevel(100)
|
||||||
|
.enemyLevel(1000)
|
||||||
|
.disableTrainerWaves()
|
||||||
|
.moveset([Moves.KOWTOW_CLEAVE])
|
||||||
|
.enemyMoveset(SPLASH_ONLY);
|
||||||
|
await game.dailyMode.startBattle();
|
||||||
|
|
||||||
|
// Transition from Daily Run Wave 10 to Wave 11 in order to trigger biome switch
|
||||||
|
game.move.select(Moves.KOWTOW_CLEAVE);
|
||||||
|
await game.phaseInterceptor.to("DamagePhase");
|
||||||
|
await game.doKillOpponents();
|
||||||
|
await game.toNextWave();
|
||||||
|
expect(game.phaseInterceptor.log).toContain("NewBiomeEncounterPhase");
|
||||||
|
|
||||||
|
const preReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const postReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
expect(preReloadRngState).toBe(postReloadRngState);
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
|
it("should not have RNG inconsistencies at a Daily run wild Pokemon fight", async () => {
|
||||||
|
await game.dailyMode.startBattle();
|
||||||
|
|
||||||
|
const preReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const postReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
expect(preReloadRngState).toBe(postReloadRngState);
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
|
it("should not have RNG inconsistencies at a Daily run double battle", async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("double");
|
||||||
|
await game.dailyMode.startBattle();
|
||||||
|
|
||||||
|
const preReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const postReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
expect(preReloadRngState).toBe(postReloadRngState);
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
|
it("should not have RNG inconsistencies at a Daily run Gym Leader fight", async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.startingWave(40);
|
||||||
|
await game.dailyMode.startBattle();
|
||||||
|
|
||||||
|
const preReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const postReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
expect(preReloadRngState).toBe(postReloadRngState);
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
|
it("should not have RNG inconsistencies at a Daily run regular trainer fight", async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.startingWave(45);
|
||||||
|
await game.dailyMode.startBattle();
|
||||||
|
|
||||||
|
const preReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const postReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
expect(preReloadRngState).toBe(postReloadRngState);
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
|
it("should not have RNG inconsistencies at a Daily run wave 50 Boss fight", async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.startingWave(50);
|
||||||
|
await game.runToFinalBossEncounter([Species.BULBASAUR], GameModes.DAILY);
|
||||||
|
|
||||||
|
const preReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const postReloadRngState = Phaser.Math.RND.state();
|
||||||
|
|
||||||
|
expect(preReloadRngState).toBe(postReloadRngState);
|
||||||
|
}, 20000);
|
||||||
|
});
|
@ -45,6 +45,8 @@ import { ChallengeModeHelper } from "./helpers/challengeModeHelper";
|
|||||||
import { MoveHelper } from "./helpers/moveHelper";
|
import { MoveHelper } from "./helpers/moveHelper";
|
||||||
import { OverridesHelper } from "./helpers/overridesHelper";
|
import { OverridesHelper } from "./helpers/overridesHelper";
|
||||||
import { SettingsHelper } from "./helpers/settingsHelper";
|
import { SettingsHelper } from "./helpers/settingsHelper";
|
||||||
|
import { ReloadHelper } from "./helpers/reloadHelper";
|
||||||
|
import { CheckSwitchPhase } from "#app/phases/check-switch-phase";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to manage the game state and transitions between phases.
|
* Class to manage the game state and transitions between phases.
|
||||||
@ -61,6 +63,7 @@ export default class GameManager {
|
|||||||
public readonly dailyMode: DailyModeHelper;
|
public readonly dailyMode: DailyModeHelper;
|
||||||
public readonly challengeMode: ChallengeModeHelper;
|
public readonly challengeMode: ChallengeModeHelper;
|
||||||
public readonly settings: SettingsHelper;
|
public readonly settings: SettingsHelper;
|
||||||
|
public readonly reload: ReloadHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of GameManager.
|
* Creates an instance of GameManager.
|
||||||
@ -82,6 +85,7 @@ export default class GameManager {
|
|||||||
this.dailyMode = new DailyModeHelper(this);
|
this.dailyMode = new DailyModeHelper(this);
|
||||||
this.challengeMode = new ChallengeModeHelper(this);
|
this.challengeMode = new ChallengeModeHelper(this);
|
||||||
this.settings = new SettingsHelper(this);
|
this.settings = new SettingsHelper(this);
|
||||||
|
this.reload = new ReloadHelper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -231,12 +235,12 @@ export default class GameManager {
|
|||||||
this.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
|
this.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
|
||||||
const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler;
|
const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler;
|
||||||
handler.processInput(Button.CANCEL);
|
handler.processInput(Button.CANCEL);
|
||||||
}, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(NewBattlePhase), true);
|
}, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(NewBattlePhase) || this.isCurrentPhase(CheckSwitchPhase), true);
|
||||||
|
|
||||||
this.onNextPrompt("SelectModifierPhase", Mode.CONFIRM, () => {
|
this.onNextPrompt("SelectModifierPhase", Mode.CONFIRM, () => {
|
||||||
const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler;
|
const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler;
|
||||||
handler.processInput(Button.ACTION);
|
handler.processInput(Button.ACTION);
|
||||||
}, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(NewBattlePhase));
|
}, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(NewBattlePhase) || this.isCurrentPhase(CheckSwitchPhase));
|
||||||
}
|
}
|
||||||
|
|
||||||
forceOpponentToSwitch() {
|
forceOpponentToSwitch() {
|
||||||
|
53
src/test/utils/helpers/reloadHelper.ts
Normal file
53
src/test/utils/helpers/reloadHelper.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { GameManagerHelper } from "./gameManagerHelper";
|
||||||
|
import { TitlePhase } from "#app/phases/title-phase";
|
||||||
|
import { Mode } from "#app/ui/ui";
|
||||||
|
import { vi } from "vitest";
|
||||||
|
import { BattleStyle } from "#app/enums/battle-style";
|
||||||
|
import { CommandPhase } from "#app/phases/command-phase";
|
||||||
|
import { TurnInitPhase } from "#app/phases/turn-init-phase";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to allow reloading sessions in unit tests.
|
||||||
|
*/
|
||||||
|
export class ReloadHelper extends GameManagerHelper {
|
||||||
|
/**
|
||||||
|
* Simulate reloading the session from the title screen, until reaching the
|
||||||
|
* beginning of the first turn (equivalent to running `startBattle()`) for
|
||||||
|
* the reloaded session.
|
||||||
|
*/
|
||||||
|
async reloadSession() : Promise<void> {
|
||||||
|
const scene = this.game.scene;
|
||||||
|
const sessionData = scene.gameData.getSessionSaveData(scene);
|
||||||
|
const titlePhase = new TitlePhase(scene);
|
||||||
|
|
||||||
|
scene.clearPhaseQueue();
|
||||||
|
|
||||||
|
// Set the last saved session to the desired session data
|
||||||
|
vi.spyOn(scene.gameData, "getSession").mockReturnValue(
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
resolve(sessionData);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
scene.unshiftPhase(titlePhase);
|
||||||
|
this.game.endPhase(); // End the currently ongoing battle
|
||||||
|
|
||||||
|
titlePhase.loadSaveSlot(-1); // Load the desired session data
|
||||||
|
this.game.phaseInterceptor.shift(); // Loading the save slot also ended TitlePhase, clean it up
|
||||||
|
|
||||||
|
// Run through prompts for switching Pokemon, copied from classicModeHelper.ts
|
||||||
|
if (this.game.scene.battleStyle === BattleStyle.SWITCH) {
|
||||||
|
this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
||||||
|
this.game.setMode(Mode.MESSAGE);
|
||||||
|
this.game.endPhase();
|
||||||
|
}, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase));
|
||||||
|
|
||||||
|
this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
||||||
|
this.game.setMode(Mode.MESSAGE);
|
||||||
|
this.game.endPhase();
|
||||||
|
}, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase));
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.game.phaseInterceptor.to(CommandPhase);
|
||||||
|
console.log("==================[New Turn]==================");
|
||||||
|
}
|
||||||
|
}
|
@ -12,12 +12,14 @@ import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
|
|||||||
import { EvolutionPhase } from "#app/phases/evolution-phase";
|
import { EvolutionPhase } from "#app/phases/evolution-phase";
|
||||||
import { FaintPhase } from "#app/phases/faint-phase";
|
import { FaintPhase } from "#app/phases/faint-phase";
|
||||||
import { LearnMovePhase } from "#app/phases/learn-move-phase";
|
import { LearnMovePhase } from "#app/phases/learn-move-phase";
|
||||||
|
import { LevelCapPhase } from "#app/phases/level-cap-phase";
|
||||||
import { LoginPhase } from "#app/phases/login-phase";
|
import { LoginPhase } from "#app/phases/login-phase";
|
||||||
import { MessagePhase } from "#app/phases/message-phase";
|
import { MessagePhase } from "#app/phases/message-phase";
|
||||||
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
|
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
|
||||||
import { MoveEndPhase } from "#app/phases/move-end-phase";
|
import { MoveEndPhase } from "#app/phases/move-end-phase";
|
||||||
import { MovePhase } from "#app/phases/move-phase";
|
import { MovePhase } from "#app/phases/move-phase";
|
||||||
import { NewBattlePhase } from "#app/phases/new-battle-phase";
|
import { NewBattlePhase } from "#app/phases/new-battle-phase";
|
||||||
|
import { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase";
|
||||||
import { NextEncounterPhase } from "#app/phases/next-encounter-phase";
|
import { NextEncounterPhase } from "#app/phases/next-encounter-phase";
|
||||||
import { PostSummonPhase } from "#app/phases/post-summon-phase";
|
import { PostSummonPhase } from "#app/phases/post-summon-phase";
|
||||||
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
|
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
|
||||||
@ -63,6 +65,7 @@ export default class PhaseInterceptor {
|
|||||||
[TitlePhase, this.startPhase],
|
[TitlePhase, this.startPhase],
|
||||||
[SelectGenderPhase, this.startPhase],
|
[SelectGenderPhase, this.startPhase],
|
||||||
[EncounterPhase, this.startPhase],
|
[EncounterPhase, this.startPhase],
|
||||||
|
[NewBiomeEncounterPhase, this.startPhase],
|
||||||
[SelectStarterPhase, this.startPhase],
|
[SelectStarterPhase, this.startPhase],
|
||||||
[PostSummonPhase, this.startPhase],
|
[PostSummonPhase, this.startPhase],
|
||||||
[SummonPhase, this.startPhase],
|
[SummonPhase, this.startPhase],
|
||||||
@ -98,6 +101,7 @@ export default class PhaseInterceptor {
|
|||||||
[PartyHealPhase, this.startPhase],
|
[PartyHealPhase, this.startPhase],
|
||||||
[EvolutionPhase, this.startPhase],
|
[EvolutionPhase, this.startPhase],
|
||||||
[EndEvolutionPhase, this.startPhase],
|
[EndEvolutionPhase, this.startPhase],
|
||||||
|
[LevelCapPhase, this.startPhase],
|
||||||
];
|
];
|
||||||
|
|
||||||
private endBySetMode = [
|
private endBySetMode = [
|
||||||
@ -239,6 +243,22 @@ export default class PhaseInterceptor {
|
|||||||
this.scene.shiftPhase();
|
this.scene.shiftPhase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the current phase from the phase interceptor.
|
||||||
|
*
|
||||||
|
* Do not call this unless absolutely necessary. This function is intended
|
||||||
|
* for cleaning up the phase interceptor when, for whatever reason, a phase
|
||||||
|
* is manually ended without using the phase interceptor.
|
||||||
|
*
|
||||||
|
* @param shouldRun Whether or not the current scene should also be run.
|
||||||
|
*/
|
||||||
|
shift(shouldRun: boolean = false) : void {
|
||||||
|
this.onHold.shift();
|
||||||
|
if (shouldRun) {
|
||||||
|
this.scene.shiftPhase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to initialize phases and their corresponding methods.
|
* Method to initialize phases and their corresponding methods.
|
||||||
*/
|
*/
|
||||||
|
@ -33,7 +33,7 @@ const timedEvents: TimedEvent[] = [
|
|||||||
xPosition: 19,
|
xPosition: 19,
|
||||||
yPosition: 115,
|
yPosition: 115,
|
||||||
scale: 0.30,
|
scale: 0.30,
|
||||||
availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es", "pt_BR", "zh_CN"]
|
availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN"]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user