mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-04 23:42:18 +02:00
Fixed migrate script, re-added deprecated attributes out of necessity
This commit is contained in:
parent
9e65d0a07b
commit
68adbcbe83
@ -7,17 +7,21 @@ import type { Nature } from "#enums/nature";
|
|||||||
* Includes abilities, nature, changed types, etc.
|
* Includes abilities, nature, changed types, etc.
|
||||||
*/
|
*/
|
||||||
export class CustomPokemonData {
|
export class CustomPokemonData {
|
||||||
public spriteScale: number;
|
public spriteScale = 1;
|
||||||
public ability: Abilities | -1;
|
public ability: Abilities | -1;
|
||||||
public passive: Abilities | -1;
|
public passive: Abilities | -1;
|
||||||
public nature: Nature | -1;
|
public nature: Nature | -1;
|
||||||
public types: PokemonType[];
|
public types: PokemonType[];
|
||||||
|
/** Deprecated but needed for session save migration */
|
||||||
|
// TODO: Remove this once pre-session migration is implemented
|
||||||
|
public hitsRecCount: number | null = null;
|
||||||
|
|
||||||
constructor(data?: CustomPokemonData | Partial<CustomPokemonData>) {
|
constructor(data?: CustomPokemonData | Partial<CustomPokemonData>) {
|
||||||
this.spriteScale = data?.spriteScale ?? -1;
|
this.spriteScale = data?.spriteScale ?? 1;
|
||||||
this.ability = data?.ability ?? -1;
|
this.ability = data?.ability ?? -1;
|
||||||
this.passive = data?.passive ?? -1;
|
this.passive = data?.passive ?? -1;
|
||||||
this.nature = data?.nature ?? -1;
|
this.nature = data?.nature ?? -1;
|
||||||
this.types = data?.types ?? [];
|
this.types = data?.types ?? [];
|
||||||
|
this.hitsRecCount = data?.hitsRecCount ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1183,12 +1183,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
formKey === "ruchbah-starmobile" ||
|
formKey === "ruchbah-starmobile" ||
|
||||||
formKey === "caph-starmobile"
|
formKey === "caph-starmobile"
|
||||||
) {
|
) {
|
||||||
|
// G-Max and starmobiles have flat 1.5x scale
|
||||||
return 1.5;
|
return 1.5;
|
||||||
}
|
}
|
||||||
if (this.customPokemonData.spriteScale > 0) {
|
return this.customPokemonData.spriteScale;
|
||||||
return this.customPokemonData.spriteScale;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resets the pokemon's field sprite properties, including position, alpha, and scale */
|
/** Resets the pokemon's field sprite properties, including position, alpha, and scale */
|
||||||
|
@ -1194,13 +1194,18 @@ export class GameData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load modifier data
|
||||||
|
|
||||||
|
if (globalScene.modifiers.length) {
|
||||||
|
console.warn("Existing modifiers not cleared on session load, deleting...");
|
||||||
|
globalScene.modifiers = [];
|
||||||
|
}
|
||||||
for (const modifierData of sessionData.modifiers) {
|
for (const modifierData of sessionData.modifiers) {
|
||||||
const modifier = modifierData.toModifier(Modifier[modifierData.className]);
|
const modifier = modifierData.toModifier(Modifier[modifierData.className]);
|
||||||
if (modifier) {
|
if (modifier) {
|
||||||
globalScene.addModifier(modifier, true);
|
globalScene.addModifier(modifier, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
globalScene.updateModifiers(true);
|
globalScene.updateModifiers(true);
|
||||||
|
|
||||||
for (const enemyModifierData of sessionData.enemyModifiers) {
|
for (const enemyModifierData of sessionData.enemyModifiers) {
|
||||||
@ -1338,12 +1343,12 @@ export class GameData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseSessionData(dataStr: string): SessionSaveData {
|
parseSessionData(dataStr: string): SessionSaveData {
|
||||||
// TODO: Add add `null`/`undefined` to the corresponding type signatures for this
|
// TODO: Add `null`/`undefined` to the corresponding type signatures for this
|
||||||
// (or prevent them from being null)
|
// (or prevent them from being null)
|
||||||
// If the value is able to *not exist*, it should say so in the code
|
// If the value is able to *not exist*, it should say so in the code
|
||||||
|
|
||||||
const sessionData = JSON.parse(dataStr, (k: string, v: any) => {
|
const sessionData = JSON.parse(dataStr, (k: string, v: any) => {
|
||||||
// TODO: Move this into migrate script
|
// TODO: Add pre-parse migrate scripts
|
||||||
switch (k) {
|
switch (k) {
|
||||||
case "party":
|
case "party":
|
||||||
case "enemyParty": {
|
case "enemyParty": {
|
||||||
@ -1452,7 +1457,7 @@ export class GameData {
|
|||||||
encrypt(JSON.stringify(sessionData), bypassLogin),
|
encrypt(JSON.stringify(sessionData), bypassLogin),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.debug("Session data saved");
|
console.debug("Session data saved!");
|
||||||
|
|
||||||
if (!bypassLogin && sync) {
|
if (!bypassLogin && sync) {
|
||||||
pokerogueApi.savedata.updateAll(request).then(error => {
|
pokerogueApi.savedata.updateAll(request).then(error => {
|
||||||
|
@ -69,6 +69,12 @@ export default class PokemonData {
|
|||||||
public customPokemonData: CustomPokemonData;
|
public customPokemonData: CustomPokemonData;
|
||||||
public fusionCustomPokemonData: CustomPokemonData;
|
public fusionCustomPokemonData: CustomPokemonData;
|
||||||
|
|
||||||
|
// Deprecated attributes, needed for now to allow SessionData migration (see PR#4619 comments)
|
||||||
|
// TODO: Remove these once pre-session migration is implemented
|
||||||
|
public natureOverride: Nature | -1;
|
||||||
|
public mysteryEncounterPokemonData: CustomPokemonData | null;
|
||||||
|
public fusionMysteryEncounterPokemonData: CustomPokemonData | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new {@linkcode PokemonData} instance out of a {@linkcode Pokemon}
|
* Construct a new {@linkcode PokemonData} instance out of a {@linkcode Pokemon}
|
||||||
* or JSON representation thereof.
|
* or JSON representation thereof.
|
||||||
@ -114,6 +120,15 @@ export default class PokemonData {
|
|||||||
this.isTerastallized = !!source.isTerastallized;
|
this.isTerastallized = !!source.isTerastallized;
|
||||||
this.stellarTypesBoosted = source.stellarTypesBoosted ?? [];
|
this.stellarTypesBoosted = source.stellarTypesBoosted ?? [];
|
||||||
|
|
||||||
|
// Deprecated, but needed for session data migration
|
||||||
|
this.natureOverride = source.natureOverride;
|
||||||
|
this.mysteryEncounterPokemonData = source.mysteryEncounterPokemonData
|
||||||
|
? new CustomPokemonData(source.mysteryEncounterPokemonData)
|
||||||
|
: null;
|
||||||
|
this.fusionMysteryEncounterPokemonData = source.fusionMysteryEncounterPokemonData
|
||||||
|
? new CustomPokemonData(source.fusionMysteryEncounterPokemonData)
|
||||||
|
: null;
|
||||||
|
|
||||||
this.fusionSpecies = sourcePokemon?.fusionSpecies?.speciesId ?? source.fusionSpecies;
|
this.fusionSpecies = sourcePokemon?.fusionSpecies?.speciesId ?? source.fusionSpecies;
|
||||||
this.fusionFormIndex = source.fusionFormIndex;
|
this.fusionFormIndex = source.fusionFormIndex;
|
||||||
this.fusionAbilityIndex = source.fusionAbilityIndex;
|
this.fusionAbilityIndex = source.fusionAbilityIndex;
|
||||||
|
@ -27,14 +27,17 @@ const migratePartyData: SessionSaveMigrator = {
|
|||||||
// only edit summondata moveset if exists
|
// only edit summondata moveset if exists
|
||||||
pkmnData.summonData.moveset &&= pkmnData.summonData.moveset.filter(m => !!m);
|
pkmnData.summonData.moveset &&= pkmnData.summonData.moveset.filter(m => !!m);
|
||||||
|
|
||||||
if (
|
if (pkmnData.customPokemonData) {
|
||||||
pkmnData.customPokemonData &&
|
// revert all "-1" sprite scales to a minimum value of 1
|
||||||
"hitsRecCount" in pkmnData.customPokemonData &&
|
pkmnData.customPokemonData.spriteScale = Math.max(1, pkmnData.customPokemonData.spriteScale);
|
||||||
typeof pkmnData.customPokemonData["hitsRecCount"] === "number"
|
if (
|
||||||
) {
|
"hitsRecCount" in pkmnData.customPokemonData &&
|
||||||
// transfer old hit count stat to battleData.
|
typeof pkmnData.customPokemonData["hitsRecCount"] === "number"
|
||||||
// No need to reset it as new Pokemon
|
) {
|
||||||
pkmnData.battleData.hitCount = pkmnData.customPokemonData["hitsRecCount"];
|
// transfer old hit count stat to battleData.
|
||||||
|
pkmnData.battleData.hitCount = pkmnData.customPokemonData["hitsRecCount"];
|
||||||
|
pkmnData.customPokemonData["hitsRecCount"] = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return pkmnData;
|
return pkmnData;
|
||||||
};
|
};
|
||||||
|
@ -82,14 +82,15 @@ describe("Abilities - Harvest", () => {
|
|||||||
.weather(WeatherType.NONE); // clear weather so we can control when harvest rolls succeed
|
.weather(WeatherType.NONE); // clear weather so we can control when harvest rolls succeed
|
||||||
await game.classicMode.startBattle([Species.MILOTIC]);
|
await game.classicMode.startBattle([Species.MILOTIC]);
|
||||||
|
|
||||||
const player = game.scene.getPlayerPokemon();
|
const milotic = game.scene.getPlayerPokemon()!;
|
||||||
|
expect(milotic).toBeDefined();
|
||||||
|
|
||||||
// Chug a few berries without harvest (should get tracked)
|
// Chug a few berries without harvest (should get tracked)
|
||||||
game.move.select(Moves.SPLASH);
|
game.move.select(Moves.SPLASH);
|
||||||
await game.forceEnemyMove(Moves.NUZZLE);
|
await game.forceEnemyMove(Moves.NUZZLE);
|
||||||
await game.toNextTurn();
|
await game.toNextTurn();
|
||||||
|
|
||||||
expect(player?.battleData.berriesEaten).toEqual(expect.arrayContaining([BerryType.ENIGMA, BerryType.LUM]));
|
expect(milotic.battleData.berriesEaten).toEqual(expect.arrayContaining([BerryType.ENIGMA, BerryType.LUM]));
|
||||||
expect(getPlayerBerries()).toHaveLength(2);
|
expect(getPlayerBerries()).toHaveLength(2);
|
||||||
|
|
||||||
// Give ourselves harvest and disable enemy neut gas,
|
// Give ourselves harvest and disable enemy neut gas,
|
||||||
@ -97,10 +98,12 @@ describe("Abilities - Harvest", () => {
|
|||||||
game.override.ability(Abilities.HARVEST);
|
game.override.ability(Abilities.HARVEST);
|
||||||
game.move.select(Moves.GASTRO_ACID);
|
game.move.select(Moves.GASTRO_ACID);
|
||||||
await game.forceEnemyMove(Moves.NUZZLE);
|
await game.forceEnemyMove(Moves.NUZZLE);
|
||||||
|
|
||||||
await game.phaseInterceptor.to("TurnEndPhase", false);
|
await game.phaseInterceptor.to("TurnEndPhase", false);
|
||||||
vi.spyOn(Phaser.Math.RND, "realInRange").mockReturnValue(0);
|
vi.spyOn(Phaser.Math.RND, "realInRange").mockReturnValue(0);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
expect(player?.battleData.berriesEaten).toEqual(
|
expect(milotic.battleData.berriesEaten).toEqual(
|
||||||
expect.arrayContaining([BerryType.ENIGMA, BerryType.LUM, BerryType.ENIGMA, BerryType.LUM]),
|
expect.arrayContaining([BerryType.ENIGMA, BerryType.LUM, BerryType.ENIGMA, BerryType.LUM]),
|
||||||
);
|
);
|
||||||
expect(getPlayerBerries()).toHaveLength(0);
|
expect(getPlayerBerries()).toHaveLength(0);
|
||||||
@ -112,11 +115,11 @@ describe("Abilities - Harvest", () => {
|
|||||||
vi.spyOn(Phaser.Math.RND, "realInRange").mockReturnValue(1);
|
vi.spyOn(Phaser.Math.RND, "realInRange").mockReturnValue(1);
|
||||||
await game.toNextTurn();
|
await game.toNextTurn();
|
||||||
|
|
||||||
expect(player?.battleData.berriesEaten).toHaveLength(3);
|
expect(milotic?.battleData.berriesEaten).toHaveLength(3);
|
||||||
expect(getPlayerBerries()).toHaveLength(1);
|
expect(getPlayerBerries()).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("remembers berries eaten array across waves and save/reload", async () => {
|
it("remembers berries eaten array across waves", async () => {
|
||||||
game.override
|
game.override
|
||||||
.startingHeldItems([{ name: "BERRY", type: BerryType.PETAYA, count: 2 }])
|
.startingHeldItems([{ name: "BERRY", type: BerryType.PETAYA, count: 2 }])
|
||||||
.ability(Abilities.BALL_FETCH); // don't actually need harvest for this test
|
.ability(Abilities.BALL_FETCH); // don't actually need harvest for this test
|
||||||
@ -132,20 +135,17 @@ describe("Abilities - Harvest", () => {
|
|||||||
|
|
||||||
// ate 1 berry without recovering (no harvest)
|
// ate 1 berry without recovering (no harvest)
|
||||||
expect(regieleki.battleData.berriesEaten).toEqual([BerryType.PETAYA]);
|
expect(regieleki.battleData.berriesEaten).toEqual([BerryType.PETAYA]);
|
||||||
expect(getPlayerBerries()).toEqual([expect.objectContaining({ berryType: BerryType.PETAYA, stackCount: 1 })]);
|
expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA });
|
||||||
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1);
|
expect(regieleki.getStatStage(Stat.SPATK)).toBe(1);
|
||||||
|
|
||||||
await game.toNextWave();
|
await game.toNextWave();
|
||||||
|
|
||||||
expect(regieleki.battleData.berriesEaten).toEqual([BerryType.PETAYA]);
|
expect(regieleki.battleData.berriesEaten).toEqual([BerryType.PETAYA]);
|
||||||
|
expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA });
|
||||||
await game.reload.reloadSession();
|
expect(regieleki.getStatStage(Stat.SPATK)).toBe(1);
|
||||||
|
|
||||||
const regielekiReloaded = game.scene.getPlayerPokemon()!;
|
|
||||||
expect(regielekiReloaded.battleData.berriesEaten).toEqual([BerryType.PETAYA]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps berries eaten across reloads", async () => {
|
it("keeps harvested berries across reloads", async () => {
|
||||||
game.override
|
game.override
|
||||||
.startingHeldItems([{ name: "BERRY", type: BerryType.PETAYA, count: 1 }])
|
.startingHeldItems([{ name: "BERRY", type: BerryType.PETAYA, count: 1 }])
|
||||||
.moveset([Moves.SPLASH, Moves.EARTHQUAKE])
|
.moveset([Moves.SPLASH, Moves.EARTHQUAKE])
|
||||||
@ -172,12 +172,13 @@ describe("Abilities - Harvest", () => {
|
|||||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||||
await game.toNextWave();
|
await game.toNextWave();
|
||||||
|
|
||||||
expect(getPlayerBerries()).toEqual([expect.objectContaining({ berryType: BerryType.PETAYA, stackCount: 1 })]);
|
expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA });
|
||||||
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1);
|
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1);
|
||||||
|
|
||||||
await game.reload.reloadSession();
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
expect(getPlayerBerries()).toEqual([expect.objectContaining({ berryType: BerryType.PETAYA, stackCount: 1 })]);
|
expect(regieleki.battleData.berriesEaten).toEqual([]);
|
||||||
|
expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA });
|
||||||
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1);
|
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -46,6 +46,16 @@ export class ReloadHelper extends GameManagerHelper {
|
|||||||
scene.unshiftPhase(titlePhase);
|
scene.unshiftPhase(titlePhase);
|
||||||
this.game.endPhase(); // End the currently ongoing battle
|
this.game.endPhase(); // End the currently ongoing battle
|
||||||
|
|
||||||
|
// remove all persistent mods before loading
|
||||||
|
// TODO: Look into why these aren't removed before load
|
||||||
|
if (this.game.scene.modifiers.length) {
|
||||||
|
console.log(
|
||||||
|
"Removing %d modifiers from scene on load...",
|
||||||
|
this.game.scene.modifiers.length,
|
||||||
|
this.game.scene.modifiers,
|
||||||
|
);
|
||||||
|
this.game.scene.modifiers = [];
|
||||||
|
}
|
||||||
titlePhase.loadSaveSlot(-1); // Load the desired session data
|
titlePhase.loadSaveSlot(-1); // Load the desired session data
|
||||||
this.game.phaseInterceptor.shift(); // Loading the save slot also ended TitlePhase, clean it up
|
this.game.phaseInterceptor.shift(); // Loading the save slot also ended TitlePhase, clean it up
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user