mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-14 03:19:28 +02:00
Merge branch 'beta' into CosmogEvoChange
This commit is contained in:
commit
750323bc6e
@ -380,9 +380,21 @@ export class BattleScene extends SceneBase {
|
||||
};
|
||||
}
|
||||
|
||||
populateAnims();
|
||||
/**
|
||||
* These moves serve as fallback animations for other moves without loaded animations, and
|
||||
* must be loaded prior to game start.
|
||||
*/
|
||||
const defaultMoves = [MoveId.TACKLE, MoveId.TAIL_WHIP, MoveId.FOCUS_ENERGY, MoveId.STRUGGLE];
|
||||
|
||||
await this.initVariantData();
|
||||
await Promise.all([
|
||||
populateAnims(),
|
||||
this.initVariantData(),
|
||||
initCommonAnims().then(() => loadCommonAnimAssets(true)),
|
||||
Promise.all(defaultMoves.map(m => initMoveAnim(m))).then(() => loadMoveAnimAssets(defaultMoves, true)),
|
||||
this.initStarterColors(),
|
||||
]).catch(reason => {
|
||||
throw new Error(`Unexpected error during BattleScene preLoad!\nReason: ${reason}`);
|
||||
});
|
||||
}
|
||||
|
||||
create() {
|
||||
@ -584,8 +596,6 @@ export class BattleScene extends SceneBase {
|
||||
|
||||
this.party = [];
|
||||
|
||||
const loadPokemonAssets = [];
|
||||
|
||||
this.arenaPlayer = new ArenaBase(true);
|
||||
this.arenaPlayer.setName("arena-player");
|
||||
this.arenaPlayerTransition = new ArenaBase(true);
|
||||
@ -640,26 +650,14 @@ export class BattleScene extends SceneBase {
|
||||
|
||||
this.reset(false, false, true);
|
||||
|
||||
// Initialize UI-related aspects and then start the login phase.
|
||||
const ui = new UI();
|
||||
this.uiContainer.add(ui);
|
||||
|
||||
this.ui = ui;
|
||||
|
||||
ui.setup();
|
||||
|
||||
const defaultMoves = [MoveId.TACKLE, MoveId.TAIL_WHIP, MoveId.FOCUS_ENERGY, MoveId.STRUGGLE];
|
||||
|
||||
Promise.all([
|
||||
Promise.all(loadPokemonAssets),
|
||||
initCommonAnims().then(() => loadCommonAnimAssets(true)),
|
||||
Promise.all(
|
||||
[MoveId.TACKLE, MoveId.TAIL_WHIP, MoveId.FOCUS_ENERGY, MoveId.STRUGGLE].map(m => initMoveAnim(m)),
|
||||
).then(() => loadMoveAnimAssets(defaultMoves, true)),
|
||||
this.initStarterColors(),
|
||||
]).then(() => {
|
||||
this.phaseManager.toTitleScreen(true);
|
||||
this.phaseManager.shiftPhase();
|
||||
});
|
||||
this.phaseManager.toTitleScreen(true);
|
||||
this.phaseManager.shiftPhase();
|
||||
}
|
||||
|
||||
initSession(): void {
|
||||
|
@ -4,7 +4,6 @@ import { defaultStarterSpecies } from "#app/constants";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
|
||||
import { speciesStarterCosts } from "#balance/starters";
|
||||
import { getEggTierForSpecies } from "#data/egg";
|
||||
import { pokemonFormChanges } from "#data/pokemon-forms";
|
||||
import type { PokemonSpecies } from "#data/pokemon-species";
|
||||
import { getPokemonSpeciesForm } from "#data/pokemon-species";
|
||||
@ -12,7 +11,6 @@ import { BattleType } from "#enums/battle-type";
|
||||
import { ChallengeType } from "#enums/challenge-type";
|
||||
import { Challenges } from "#enums/challenges";
|
||||
import { TypeColor, TypeShadow } from "#enums/color";
|
||||
import { EggTier } from "#enums/egg-type";
|
||||
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
||||
import { ModifierTier } from "#enums/modifier-tier";
|
||||
import type { MoveId } from "#enums/move-id";
|
||||
@ -26,7 +24,7 @@ import type { Pokemon } from "#field/pokemon";
|
||||
import { Trainer } from "#field/trainer";
|
||||
import { PokemonMove } from "#moves/pokemon-move";
|
||||
import type { DexAttrProps, GameData } from "#system/game-data";
|
||||
import { BooleanHolder, type NumberHolder, randSeedItem } from "#utils/common";
|
||||
import { BooleanHolder, isBetween, type NumberHolder, randSeedItem } from "#utils/common";
|
||||
import { deepCopy } from "#utils/data";
|
||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||
import { toCamelCase, toSnakeCase } from "#utils/strings";
|
||||
@ -685,14 +683,11 @@ export class SingleTypeChallenge extends Challenge {
|
||||
*/
|
||||
export class FreshStartChallenge extends Challenge {
|
||||
constructor() {
|
||||
super(Challenges.FRESH_START, 3);
|
||||
super(Challenges.FRESH_START, 2);
|
||||
}
|
||||
|
||||
applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean {
|
||||
if (
|
||||
(this.value === 1 && !defaultStarterSpecies.includes(pokemon.speciesId)) ||
|
||||
(this.value === 2 && getEggTierForSpecies(pokemon) >= EggTier.EPIC)
|
||||
) {
|
||||
if (this.value === 1 && !defaultStarterSpecies.includes(pokemon.speciesId)) {
|
||||
valid.value = false;
|
||||
return true;
|
||||
}
|
||||
@ -708,12 +703,18 @@ export class FreshStartChallenge extends Challenge {
|
||||
pokemon.abilityIndex = pokemon.abilityIndex % 2; // Always base ability, if you set it to hidden it wraps to first ability
|
||||
pokemon.passive = false; // Passive isn't unlocked
|
||||
pokemon.nature = Nature.HARDY; // Neutral nature
|
||||
pokemon.moveset = pokemon.species
|
||||
let validMoves = pokemon.species
|
||||
.getLevelMoves()
|
||||
.filter(m => m[0] <= 5)
|
||||
.map(lm => lm[1])
|
||||
.slice(0, 4)
|
||||
.map(m => new PokemonMove(m)); // No egg moves
|
||||
.filter(m => isBetween(m[0], 1, 5))
|
||||
.map(lm => lm[1]);
|
||||
// Filter egg moves out of the moveset
|
||||
pokemon.moveset = pokemon.moveset.filter(pm => validMoves.includes(pm.moveId));
|
||||
if (pokemon.moveset.length < 4) {
|
||||
// If there's empty slots fill with remaining valid moves
|
||||
const existingMoveIds = pokemon.moveset.map(pm => pm.moveId);
|
||||
validMoves = validMoves.filter(m => !existingMoveIds.includes(m));
|
||||
pokemon.moveset = pokemon.moveset.concat(validMoves.map(m => new PokemonMove(m))).slice(0, 4);
|
||||
}
|
||||
pokemon.luck = 0; // No luck
|
||||
pokemon.shiny = false; // Not shiny
|
||||
pokemon.variant = 0; // Not shiny
|
||||
|
@ -99,8 +99,12 @@ export class SelectStarterPhase extends Phase {
|
||||
starterPokemon.generateFusionSpecies(true);
|
||||
}
|
||||
starterPokemon.setVisible(false);
|
||||
applyChallenges(ChallengeType.STARTER_MODIFY, starterPokemon);
|
||||
const chalApplied = applyChallenges(ChallengeType.STARTER_MODIFY, starterPokemon);
|
||||
party.push(starterPokemon);
|
||||
if (chalApplied) {
|
||||
// If any challenges modified the starter, it should update
|
||||
loadPokemonAssets.push(starterPokemon.updateInfo());
|
||||
}
|
||||
loadPokemonAssets.push(starterPokemon.loadAssets());
|
||||
});
|
||||
overrideModifiers();
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import { waitUntil } from "#test/test-utils/game-manager-utils";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
@ -36,19 +35,6 @@ describe("Test misc", () => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// it.skip("test apifetch mock async", async () => {
|
||||
// const spy = vi.fn();
|
||||
// await apiFetch("https://localhost:8080/account/info").then(response => {
|
||||
// expect(response.status).toBe(200);
|
||||
// expect(response.ok).toBe(true);
|
||||
// return response.json();
|
||||
// }).then(data => {
|
||||
// spy(); // Call the spy function
|
||||
// expect(data).toEqual({ "username": "greenlamp", "lastSessionSlot": 0 });
|
||||
// });
|
||||
// expect(spy).toHaveBeenCalled();
|
||||
// });
|
||||
|
||||
it("test fetch mock sync", async () => {
|
||||
const response = await fetch("https://localhost:8080/account/info");
|
||||
const data = await response.json();
|
||||
@ -62,19 +48,4 @@ describe("Test misc", () => {
|
||||
const data = await game.scene.cachedFetch("./battle-anims/splishy-splash.json");
|
||||
expect(data).toBeDefined();
|
||||
});
|
||||
|
||||
it("testing wait phase queue", async () => {
|
||||
const fakeScene = {
|
||||
phaseQueue: [1, 2, 3], // Initially not empty
|
||||
};
|
||||
setTimeout(() => {
|
||||
fakeScene.phaseQueue = [];
|
||||
}, 500);
|
||||
const spy = vi.fn();
|
||||
await waitUntil(() => fakeScene.phaseQueue.length === 0).then(result => {
|
||||
expect(result).toBe(true);
|
||||
spy(); // Call the spy function
|
||||
});
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -87,17 +87,6 @@ function getTestRunStarters(seed: string, species?: SpeciesId[]): Starter[] {
|
||||
return starters;
|
||||
}
|
||||
|
||||
export function waitUntil(truth): Promise<unknown> {
|
||||
return new Promise(resolve => {
|
||||
const interval = setInterval(() => {
|
||||
if (truth()) {
|
||||
clearInterval(interval);
|
||||
resolve(true);
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for populating party, wave index, etc. without having to spin up and run through an entire EncounterPhase
|
||||
*/
|
||||
|
@ -31,7 +31,7 @@ import { TurnEndPhase } from "#phases/turn-end-phase";
|
||||
import { TurnInitPhase } from "#phases/turn-init-phase";
|
||||
import { TurnStartPhase } from "#phases/turn-start-phase";
|
||||
import { ErrorInterceptor } from "#test/test-utils/error-interceptor";
|
||||
import { generateStarter, waitUntil } from "#test/test-utils/game-manager-utils";
|
||||
import { generateStarter } from "#test/test-utils/game-manager-utils";
|
||||
import { GameWrapper } from "#test/test-utils/game-wrapper";
|
||||
import { ChallengeModeHelper } from "#test/test-utils/helpers/challenge-mode-helper";
|
||||
import { ClassicModeHelper } from "#test/test-utils/helpers/classic-mode-helper";
|
||||
@ -85,30 +85,22 @@ export class GameManager {
|
||||
constructor(phaserGame: Phaser.Game, bypassLogin = true) {
|
||||
localStorage.clear();
|
||||
ErrorInterceptor.getInstance().clear();
|
||||
BattleScene.prototype.randBattleSeedInt = (range, min = 0) => min + range - 1; // This simulates a max roll
|
||||
// Simulate max rolls on RNG functions
|
||||
// TODO: Create helpers for disabling/enabling battle RNG
|
||||
BattleScene.prototype.randBattleSeedInt = (range, min = 0) => min + range - 1;
|
||||
this.gameWrapper = new GameWrapper(phaserGame, bypassLogin);
|
||||
|
||||
let firstTimeScene = false;
|
||||
// TODO: Figure out a way to optimize and re-use the same game manager for each test
|
||||
|
||||
// Re-use an existing `globalScene` if present, or else create a new scene from scratch.
|
||||
if (globalScene) {
|
||||
this.scene = globalScene;
|
||||
this.phaseInterceptor = new PhaseInterceptor(this.scene);
|
||||
this.resetScene();
|
||||
} else {
|
||||
this.scene = new BattleScene();
|
||||
this.phaseInterceptor = new PhaseInterceptor(this.scene);
|
||||
this.gameWrapper.setScene(this.scene);
|
||||
firstTimeScene = true;
|
||||
}
|
||||
|
||||
this.phaseInterceptor = new PhaseInterceptor(this.scene);
|
||||
|
||||
if (!firstTimeScene) {
|
||||
this.scene.reset(false, true);
|
||||
(this.scene.ui.handlers[UiMode.STARTER_SELECT] as StarterSelectUiHandler).clearStarterPreferences();
|
||||
|
||||
// Must be run after phase interceptor has been initialized.
|
||||
this.scene.phaseManager.toTitleScreen(true);
|
||||
this.scene.phaseManager.shiftPhase();
|
||||
|
||||
this.gameWrapper.scene = this.scene;
|
||||
}
|
||||
|
||||
this.textInterceptor = new TextInterceptor(this.scene);
|
||||
@ -122,10 +114,30 @@ export class GameManager {
|
||||
this.modifiers = new ModifierHelper(this);
|
||||
this.field = new FieldHelper(this);
|
||||
|
||||
this.initDefaultOverrides();
|
||||
|
||||
// TODO: remove `any` assertion
|
||||
global.fetch = vi.fn(MockFetch) as any;
|
||||
}
|
||||
|
||||
/** Reset a prior `BattleScene` instance to the proper initial state. */
|
||||
private resetScene(): void {
|
||||
this.scene.reset(false, true);
|
||||
(this.scene.ui.handlers[UiMode.STARTER_SELECT] as StarterSelectUiHandler).clearStarterPreferences();
|
||||
|
||||
this.gameWrapper.scene = this.scene;
|
||||
|
||||
this.scene.phaseManager.toTitleScreen(true);
|
||||
this.scene.phaseManager.shiftPhase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize various default overrides for starting tests, typically to alleviate randomness.
|
||||
*/
|
||||
// TODO: This should not be here
|
||||
private initDefaultOverrides(): void {
|
||||
// Disables Mystery Encounters on all tests (can be overridden at test level)
|
||||
this.override.mysteryEncounterChance(0);
|
||||
|
||||
global.fetch = vi.fn(MockFetch) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,15 +153,13 @@ export class GameManager {
|
||||
* @param mode - The mode to wait for.
|
||||
* @returns A promise that resolves when the mode is set.
|
||||
*/
|
||||
waitMode(mode: UiMode): Promise<void> {
|
||||
return new Promise(async resolve => {
|
||||
await waitUntil(() => this.scene.ui?.getMode() === mode);
|
||||
return resolve();
|
||||
});
|
||||
// TODO: This is unused
|
||||
async waitMode(mode: UiMode): Promise<void> {
|
||||
await vi.waitUntil(() => this.scene.ui?.getMode() === mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the current phase.
|
||||
* End the currently running phase immediately.
|
||||
*/
|
||||
endPhase() {
|
||||
this.scene.phaseManager.getCurrentPhase()?.end();
|
||||
@ -283,11 +293,14 @@ export class GameManager {
|
||||
.getPokemon()
|
||||
.getMoveset()
|
||||
[movePosition].getMove();
|
||||
if (!move.isMultiTarget()) {
|
||||
handler.setCursor(targetIndex !== undefined ? targetIndex : BattlerIndex.ENEMY);
|
||||
}
|
||||
if (move.isMultiTarget() && targetIndex !== undefined) {
|
||||
expect.fail(`targetIndex was passed to selectMove() but move ("${move.name}") is not targetted`);
|
||||
|
||||
// Multi target attacks do not select a target
|
||||
if (move.isMultiTarget()) {
|
||||
if (targetIndex !== undefined) {
|
||||
expect.fail(`targetIndex was passed to selectMove() but move ("${move.name}") is not targeted`);
|
||||
}
|
||||
} else {
|
||||
handler.setCursor(targetIndex ?? BattlerIndex.ENEMY);
|
||||
}
|
||||
handler.processInput(Button.ACTION);
|
||||
},
|
||||
|
@ -143,7 +143,7 @@ export class MoveHelper extends GameManagerHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper function to get the index of the selected move in the selected part member's moveset. */
|
||||
/** Helper function to get the index of the selected move in the selected party member's moveset. */
|
||||
private getMovePosition(pokemonIndex: BattlerIndex.PLAYER | BattlerIndex.PLAYER_2, move: MoveId): number {
|
||||
const playerPokemon = this.game.scene.getPlayerField()[pokemonIndex];
|
||||
const moveset = playerPokemon.getMoveset();
|
||||
@ -153,17 +153,18 @@ export class MoveHelper extends GameManagerHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies a player pokemon's moveset to contain only the selected move and then
|
||||
* Modifies a player pokemon's moveset to contain only the selected move, and then
|
||||
* selects it to be used during the next {@linkcode CommandPhase}.
|
||||
*
|
||||
* Warning: Will disable the player moveset override if it is enabled!
|
||||
* **Warning**: Will disable the player moveset override if it is enabled, as well as any mid-battle moveset changes!
|
||||
*
|
||||
* Note: If you need to check for changes in the player's moveset as part of the test, it may be
|
||||
* best to use {@linkcode changeMoveset} and {@linkcode select} instead.
|
||||
* @param moveId - the move to use
|
||||
* @param pkmIndex - The {@linkcode BattlerIndex} of the player Pokemon using the move. Relevant for double battles only and defaults to {@linkcode BattlerIndex.PLAYER} if not specified.
|
||||
* @param targetIndex - The {@linkcode BattlerIndex} of the Pokemon to target for single-target moves; should be omitted for multi-target moves.
|
||||
* @param useTera - If `true`, the Pokemon will attempt to Terastallize even without a Tera Orb; default `false`.
|
||||
* @param moveId - The {@linkcode MoveId} to use
|
||||
* @param pkmIndex - The {@linkcode BattlerIndex} of the player Pokemon using the move. Relevant for double battles only and defaults to {@linkcode BattlerIndex.PLAYER} if not specified
|
||||
* @param targetIndex - The {@linkcode BattlerIndex} of the Pokemon to target for single-target moves; should be omitted for multi-target moves
|
||||
* @param useTera - If `true`, the Pokemon will attempt to Terastallize even without a Tera Orb; default `false`
|
||||
* @remarks
|
||||
* If you need to check for changes in the player's moveset as part of the test, it may be
|
||||
* better to use {@linkcode changeMoveset} and {@linkcode select} instead.
|
||||
*/
|
||||
public use(
|
||||
moveId: MoveId,
|
||||
@ -176,8 +177,11 @@ export class MoveHelper extends GameManagerHelper {
|
||||
console.warn("Warning: `MoveHelper.use` overwriting player pokemon moveset and disabling moveset override!");
|
||||
}
|
||||
|
||||
// Clear out both the normal and temporary movesets before setting the move.
|
||||
const pokemon = this.game.scene.getPlayerField()[pkmIndex];
|
||||
pokemon.moveset = [new PokemonMove(moveId)];
|
||||
pokemon.moveset.splice(0);
|
||||
pokemon.summonData.moveset?.splice(0);
|
||||
pokemon.setMove(0, moveId);
|
||||
|
||||
if (useTera) {
|
||||
this.selectWithTera(moveId, pkmIndex, targetIndex);
|
||||
@ -211,7 +215,7 @@ export class MoveHelper extends GameManagerHelper {
|
||||
/**
|
||||
* Changes a pokemon's moveset to the given move(s).
|
||||
*
|
||||
* Used when the normal moveset override can't be used (such as when it's necessary to check or update properties of the moveset).
|
||||
* Useful when normal moveset overrides can't be used (such as when it's necessary to check or update properties of the moveset).
|
||||
*
|
||||
* **Note**: Will disable the moveset override matching the pokemon's party.
|
||||
* @param pokemon - The {@linkcode Pokemon} being modified
|
||||
@ -232,8 +236,8 @@ export class MoveHelper extends GameManagerHelper {
|
||||
moveset = coerceArray(moveset);
|
||||
expect(moveset.length, "Cannot assign more than 4 moves to a moveset!").toBeLessThanOrEqual(4);
|
||||
pokemon.moveset = [];
|
||||
moveset.forEach(move => {
|
||||
pokemon.moveset.push(new PokemonMove(move));
|
||||
moveset.forEach((move, i) => {
|
||||
pokemon.setMove(i, move);
|
||||
});
|
||||
const movesetStr = moveset.map(moveId => MoveId[moveId]).join(", ");
|
||||
console.log(`Pokemon ${pokemon.species.name}'s moveset manually set to ${movesetStr} (=[${moveset.join(", ")}])!`);
|
||||
|
Loading…
Reference in New Issue
Block a user