[Bug] Fix reloads erasing weather on first wave of biome (#4078)
* [Bug] Fix reloads erasing weather on first wave of biome * Minor revisions * Minor revisions 2 * Update test --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
parent
128df1b6d2
commit
009fd3fc5c
|
@ -216,8 +216,8 @@ export class EncounterPhase extends BattlePhase {
|
|||
|
||||
this.scene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||
if (!this.loaded) {
|
||||
//@ts-ignore
|
||||
this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || this.scene.lastSavePlayTime >= 300).then(success => { // TODO: get rid of ts-ignore
|
||||
this.trySetWeatherIfNewBiome(); // Set weather before session gets saved
|
||||
this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || (this.scene.lastSavePlayTime ?? 0) >= 300).then(success => {
|
||||
this.scene.disableMenu = false;
|
||||
if (!success) {
|
||||
return this.scene.reset(true);
|
||||
|
@ -250,10 +250,6 @@ export class EncounterPhase extends BattlePhase {
|
|||
}
|
||||
}
|
||||
|
||||
if (!this.loaded) {
|
||||
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
|
||||
}
|
||||
|
||||
const enemyField = this.scene.getEnemyField();
|
||||
this.scene.tweens.add({
|
||||
targets: [this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.arenaPlayer, this.scene.trainer].flat(),
|
||||
|
@ -519,4 +515,18 @@ export class EncounterPhase extends BattlePhase {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set biome weather if and only if this encounter is the start of a new biome.
|
||||
*
|
||||
* By using function overrides, this should happen if and only if this phase
|
||||
* is exactly a NewBiomeEncounterPhase or an EncounterPhase (to account for
|
||||
* Wave 1 of a Daily Run), but NOT NextEncounterPhase (which starts the next
|
||||
* wave in the same biome).
|
||||
*/
|
||||
trySetWeatherIfNewBiome(): void {
|
||||
if (!this.loaded) {
|
||||
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase {
|
|||
}
|
||||
}
|
||||
|
||||
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
|
||||
|
||||
for (const pokemon of this.scene.getParty().filter(p => p.isOnField())) {
|
||||
applyAbAttrs(PostBiomeChangeAbAttr, pokemon, null);
|
||||
}
|
||||
|
@ -41,4 +39,11 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set biome weather.
|
||||
*/
|
||||
trySetWeatherIfNewBiome(): void {
|
||||
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,4 +67,10 @@ export class NextEncounterPhase extends EncounterPhase {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing (since this is simply the next wave in the same biome).
|
||||
*/
|
||||
trySetWeatherIfNewBiome(): void {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@ import { Moves } from "#enums/moves";
|
|||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { Species } from "#enums/species";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { Biome } from "#app/enums/biome";
|
||||
|
||||
describe("Test Battle Phase", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
|
@ -290,22 +291,27 @@ describe("Test Battle Phase", () => {
|
|||
expect(game.scene.currentBattle.turn).toBeGreaterThan(turn);
|
||||
}, 20000);
|
||||
|
||||
it("to next wave with pokemon killed, single", async () => {
|
||||
it("does not set new weather if staying in same biome", async () => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
game.override.battleType("single");
|
||||
game.override.starterSpecies(Species.MEWTWO);
|
||||
game.override.enemySpecies(Species.RATTATA);
|
||||
game.override.enemyAbility(Abilities.HYDRATION);
|
||||
game.override.ability(Abilities.ZEN_MODE);
|
||||
game.override.startingLevel(2000);
|
||||
game.override.startingWave(3);
|
||||
game.override.moveset([moveToUse]);
|
||||
game.override
|
||||
.battleType("single")
|
||||
.starterSpecies(Species.MEWTWO)
|
||||
.enemySpecies(Species.RATTATA)
|
||||
.enemyAbility(Abilities.HYDRATION)
|
||||
.ability(Abilities.ZEN_MODE)
|
||||
.startingLevel(2000)
|
||||
.startingWave(3)
|
||||
.startingBiome(Biome.LAKE)
|
||||
.moveset([moveToUse]);
|
||||
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
await game.startBattle();
|
||||
await game.classicMode.startBattle();
|
||||
const waveIndex = game.scene.currentBattle.waveIndex;
|
||||
game.move.select(moveToUse);
|
||||
|
||||
vi.spyOn(game.scene.arena, "trySetWeather");
|
||||
await game.doKillOpponents();
|
||||
await game.toNextWave();
|
||||
expect(game.scene.arena.trySetWeather).not.toHaveBeenCalled();
|
||||
expect(game.scene.currentBattle.waveIndex).toBeGreaterThan(waveIndex);
|
||||
}, 20000);
|
||||
|
||||
|
|
|
@ -38,16 +38,15 @@ describe("Reload", () => {
|
|||
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)
|
||||
.startingLevel(100) // Avoid levelling up
|
||||
.enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents()
|
||||
.disableTrainerWaves()
|
||||
.moveset([Moves.KOWTOW_CLEAVE])
|
||||
.enemyMoveset(Moves.SPLASH);
|
||||
await game.dailyMode.startBattle();
|
||||
|
||||
// Transition from Daily Run Wave 10 to Wave 11 in order to trigger biome switch
|
||||
// Transition from 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();
|
||||
|
@ -63,6 +62,34 @@ describe("Reload", () => {
|
|||
expect(preReloadRngState).toBe(postReloadRngState);
|
||||
}, 20000);
|
||||
|
||||
it("should not have weather inconsistencies after a biome switch", async () => {
|
||||
game.override
|
||||
.startingWave(10)
|
||||
.startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather
|
||||
.battleType("single")
|
||||
.startingLevel(100) // Avoid levelling up
|
||||
.enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents()
|
||||
.disableTrainerWaves()
|
||||
.moveset([Moves.KOWTOW_CLEAVE])
|
||||
.enemyMoveset(Moves.SPLASH);
|
||||
await game.classicMode.startBattle(); // Apparently daily mode would override the biome
|
||||
|
||||
// Transition from 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 preReloadWeather = game.scene.arena.weather;
|
||||
|
||||
await game.reload.reloadSession();
|
||||
|
||||
const postReloadWeather = game.scene.arena.weather;
|
||||
|
||||
expect(postReloadWeather).toStrictEqual(preReloadWeather);
|
||||
}, 20000);
|
||||
|
||||
it("should not have RNG inconsistencies at a Daily run wild Pokemon fight", async () => {
|
||||
await game.dailyMode.startBattle();
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ import TargetSelectUiHandler from "#app/ui/target-select-ui-handler";
|
|||
import { Mode } from "#app/ui/ui";
|
||||
import { Button } from "#enums/buttons";
|
||||
import { ExpNotification } from "#enums/exp-notification";
|
||||
import { GameDataType } from "#enums/game-data-type";
|
||||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { Species } from "#enums/species";
|
||||
import { generateStarter, waitUntil } from "#test/utils/gameManagerUtils";
|
||||
|
@ -371,13 +370,11 @@ export default class GameManager {
|
|||
* @returns A promise that resolves with the exported save data.
|
||||
*/
|
||||
exportSaveToTest(): Promise<string> {
|
||||
const saveKey = "x0i2O7WRiANTqPmZ";
|
||||
return new Promise(async (resolve) => {
|
||||
await this.scene.gameData.saveAll(this.scene, true, true, true, true);
|
||||
this.scene.reset(true);
|
||||
await waitUntil(() => this.scene.ui?.getMode() === Mode.TITLE);
|
||||
await this.scene.gameData.tryExportData(GameDataType.SESSION, 0);
|
||||
await waitUntil(() => localStorage.hasOwnProperty("toExport"));
|
||||
return resolve(localStorage.getItem("toExport")!); // TODO: is this bang correct?;
|
||||
const sessionSaveData = this.scene.gameData.getSessionSaveData(this.scene);
|
||||
const encryptedSaveData = AES.encrypt(JSON.stringify(sessionSaveData), saveKey).toString();
|
||||
resolve(encryptedSaveData);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,27 @@ 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";
|
||||
import { SessionSaveData } from "#app/system/game-data";
|
||||
import GameManager from "../gameManager";
|
||||
|
||||
/**
|
||||
* Helper to allow reloading sessions in unit tests.
|
||||
*/
|
||||
export class ReloadHelper extends GameManagerHelper {
|
||||
sessionData: SessionSaveData;
|
||||
|
||||
constructor(game: GameManager) {
|
||||
super(game);
|
||||
|
||||
// Whenever the game saves the session, save it to the reloadHelper instead
|
||||
vi.spyOn(game.scene.gameData, "saveAll").mockImplementation((scene) => {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
this.sessionData = scene.gameData.getSessionSaveData(scene);
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate reloading the session from the title screen, until reaching the
|
||||
* beginning of the first turn (equivalent to running `startBattle()`) for
|
||||
|
@ -17,7 +33,6 @@ export class ReloadHelper extends GameManagerHelper {
|
|||
*/
|
||||
async reloadSession() : Promise<void> {
|
||||
const scene = this.game.scene;
|
||||
const sessionData = scene.gameData.getSessionSaveData(scene);
|
||||
const titlePhase = new TitlePhase(scene);
|
||||
|
||||
scene.clearPhaseQueue();
|
||||
|
@ -25,7 +40,7 @@ export class ReloadHelper extends GameManagerHelper {
|
|||
// Set the last saved session to the desired session data
|
||||
vi.spyOn(scene.gameData, "getSession").mockReturnValue(
|
||||
new Promise((resolve, reject) => {
|
||||
resolve(sessionData);
|
||||
resolve(this.sessionData);
|
||||
})
|
||||
);
|
||||
scene.unshiftPhase(titlePhase);
|
||||
|
|
Loading…
Reference in New Issue