mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-09 00:49:27 +02:00
[WIP]
This commit is contained in:
parent
09bb498c7a
commit
10af69a777
@ -97,10 +97,10 @@ interface SerializedIllusionData extends Omit<IllusionData, "fusionSpecies"> {
|
||||
}
|
||||
|
||||
interface SerializedPokemonSummonData {
|
||||
statStages: number[];
|
||||
moveQueue: TurnMove[];
|
||||
tags: BattlerTag[];
|
||||
abilitySuppressed: boolean;
|
||||
statStages?: number[];
|
||||
moveQueue?: TurnMove[];
|
||||
tags?: BattlerTag[];
|
||||
abilitySuppressed?: boolean;
|
||||
speciesForm?: SerializedSpeciesForm;
|
||||
fusionSpeciesForm?: SerializedSpeciesForm;
|
||||
ability?: AbilityId;
|
||||
@ -109,12 +109,12 @@ interface SerializedPokemonSummonData {
|
||||
fusionGender?: Gender;
|
||||
stats: number[];
|
||||
moveset?: PokemonMove[];
|
||||
types: PokemonType[];
|
||||
types?: PokemonType[];
|
||||
addedType?: PokemonType;
|
||||
illusion?: SerializedIllusionData;
|
||||
illusionBroken: boolean;
|
||||
berriesEatenLast: BerryType[];
|
||||
moveHistory: TurnMove[];
|
||||
illusionBroken?: boolean;
|
||||
berriesEatenLast?: BerryType[];
|
||||
moveHistory?: TurnMove[];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -250,9 +250,12 @@ export class PokemonSummonData {
|
||||
},
|
||||
};
|
||||
// Replace `null` with `undefined`, as `undefined` never gets serialized
|
||||
// Replace empty arrays with `[]`
|
||||
for (const [key, value] of Object.entries(t)) {
|
||||
if (value === null) {
|
||||
t[key] = undefined;
|
||||
} else if (Array.isArray(value) && value.length === 0) {
|
||||
t[key] = [];
|
||||
}
|
||||
}
|
||||
return t;
|
||||
|
30
src/system/schema-migrators/custom-pokemon-data.ts
Normal file
30
src/system/schema-migrators/custom-pokemon-data.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import type { Z$PokemonData } from "#system/schemas/v1.10/pokemon-data";
|
||||
import { NatureSchema } from "#system/schemas/v1.10/pokemon-nature";
|
||||
import type z from "zod";
|
||||
|
||||
/**
|
||||
* Very early saves did not have `customPokemonData` and instead
|
||||
* stored things like nature overrides and abilities from MEs directly.
|
||||
* This migrator moves the properties into the `customPokemonData` field.
|
||||
*/
|
||||
export function PreCustomPokemonDataMigrator(
|
||||
data: z.output<typeof Z$PokemonData>,
|
||||
): asserts data is z.output<typeof Z$PokemonData> {
|
||||
// Value of `-1` indicated no override, so we can ignore it.
|
||||
const nature = NatureSchema.safeParse(data.natureOverride);
|
||||
if (nature.success) {
|
||||
const customPokemonData = data.customPokemonData;
|
||||
// If natureOverride is valid, use it
|
||||
if (
|
||||
customPokemonData &&
|
||||
typeof customPokemonData === "object" &&
|
||||
((customPokemonData as { nature?: number }).nature ?? -1) === -1
|
||||
) {
|
||||
customPokemonData;
|
||||
} else {
|
||||
data.customPokemonData = {
|
||||
nature: nature.data,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
69
src/system/schema-migrators/summon-data.ts
Normal file
69
src/system/schema-migrators/summon-data.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Z$PositiveInt } from "#system/schemas/common";
|
||||
import type { Z$IllusionData } from "#system/schemas/v1.10/illusion-data";
|
||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* In version 1.9, serialized illusion data looked like this, where `basePokemon` held
|
||||
* information about the pokemon that had the illusion ability, while the pokemon's own
|
||||
* properties were modified. (though were overwritten on save).
|
||||
*
|
||||
* ```ts
|
||||
* interface IllusionData {
|
||||
* basePokemon: {
|
||||
* name: string;
|
||||
* nickname: string;
|
||||
* shiny: boolean;
|
||||
* variant: Variant;
|
||||
* fusionShiny: boolean;
|
||||
* fusionVariant: Variant;
|
||||
* }
|
||||
* species: Species;
|
||||
* formIndex: number;
|
||||
* gender: Gender;
|
||||
* pokeball: PokeballType;
|
||||
* fusionSpecies?: PokemonSpecies;
|
||||
* fusionFormIndex?: number;
|
||||
* fusionGender?: Gender;
|
||||
* level?: number
|
||||
* ```
|
||||
*
|
||||
* As this version of the data is compatible with version 1.10, we only need to specify the new properties.
|
||||
*/
|
||||
export const Z$V1_9_IllusionData = z.looseObject({
|
||||
species: Z$PositiveInt,
|
||||
fusionSpecies: z
|
||||
.object({
|
||||
speciesId: Z$PositiveInt,
|
||||
})
|
||||
.optional()
|
||||
.catch(undefined),
|
||||
});
|
||||
type V1_9_IllusionData = z.input<typeof Z$V1_9_IllusionData>;
|
||||
|
||||
/**
|
||||
* Migrate illusion data from version 1.9 to 1.10
|
||||
*
|
||||
* @remarks
|
||||
* Extract `speciesId` from `fusionSpecies`, and use defaults for all fields from the illusioned pokemon.
|
||||
*
|
||||
*/
|
||||
export function V1_10_IllusionDataMigrator(arg: V1_9_IllusionData): Partial<z.input<typeof Z$IllusionData>> {
|
||||
return Z$V1_9_IllusionData.transform(data => {
|
||||
// Needed to fetch a default name.
|
||||
const pokemon = getPokemonSpecies(data.species);
|
||||
return {
|
||||
...(data as Omit<V1_9_IllusionData, "fusionSpecies">),
|
||||
// unwrap fusion species
|
||||
fusionSpecies: data.fusionSpecies?.speciesId,
|
||||
// and use defaults for all fields from the illusioned pokemon
|
||||
name: pokemon.name,
|
||||
nickname: pokemon.name,
|
||||
shiny: false,
|
||||
fusionShiny: false,
|
||||
variant: 0,
|
||||
fusionVariant: 0,
|
||||
fusionFormIndex: 0,
|
||||
};
|
||||
}).parse(arg);
|
||||
}
|
25
src/system/schemas/v1.10/illusion-data.ts
Normal file
25
src/system/schemas/v1.10/illusion-data.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Z$NonNegativeInt, Z$PositiveInt } from "#system/schemas/common";
|
||||
import { Z$PokeballType } from "#system/schemas/v1.10/pokeball-type";
|
||||
import { Z$Gender } from "#system/schemas/v1.10/pokemon-gender";
|
||||
import { z } from "zod";
|
||||
|
||||
|
||||
// TODO: Write migrator for illusion data's fusionSpecies field
|
||||
// that transforms incoming fusion species
|
||||
|
||||
export const Z$IllusionData = z.object({
|
||||
name: z.string(),
|
||||
nickname: z.string(),
|
||||
shiny: z.boolean(),
|
||||
variant: z.literal([0, 1, 2]).catch(0),
|
||||
species: Z$PositiveInt,
|
||||
formIndex: Z$NonNegativeInt.catch(0),
|
||||
gender: Z$Gender,
|
||||
pokeball: Z$PokeballType,
|
||||
fusionSpecies: Z$PositiveInt.optional().catch(undefined),
|
||||
fusionFormIndex: Z$NonNegativeInt.optional().catch(undefined),
|
||||
fusionShiny: z.boolean().optional().catch(false),
|
||||
fusionVariant: z.literal([0, 1, 2]).optional().catch(0),
|
||||
fusionGender: Z$Gender.optional().catch(undefined),
|
||||
level: Z$PositiveInt.optional().catch(undefined),
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
import { Z$BoolCatchToFalse, Z$NonNegativeInt, Z$PositiveInt } from "#schemas/common";
|
||||
import { Z$PokeballType } from "#schemas/pokeball-type";
|
||||
import { Z$PokemonMove } from "#schemas/pokemon-move";
|
||||
import { Z$PokemonBattleData } from "#system/schemas/v1.10/pokemon-battle-data";
|
||||
import { Z$Gender } from "#system/schemas/v1.10/pokemon-gender";
|
||||
import z from "zod";
|
||||
import { NatureSchema } from "./pokemon-nature";
|
||||
@ -14,7 +15,7 @@ import { StatusSchema } from "./status-effect";
|
||||
* `looseObject` used here to allow properties specific to player or enemy Pokémon
|
||||
* to be handled by their respective schemas.
|
||||
*/
|
||||
const Z$PokemonData = z.looseObject({
|
||||
export const Z$PokemonData = z.looseObject({
|
||||
// malformed pokemon ids are _not_ supported.
|
||||
id: z.uint32(),
|
||||
species: z.uint32(),
|
||||
@ -65,6 +66,9 @@ const Z$PokemonData = z.looseObject({
|
||||
//#endregion "fusion" information
|
||||
|
||||
pokerus: z.boolean().catch(false),
|
||||
summonData: Z$PokemonSummonData,
|
||||
battleData: Z$PokemonBattleData,
|
||||
summonDataSpeciesFormIndex: Z$NonNegativeInt,
|
||||
});
|
||||
|
||||
export const Z$PlayerPokemonData = z.object({
|
||||
@ -88,29 +92,6 @@ export const Z$EnemyPokemonData = z.object({
|
||||
bossSegments: z.int().nonnegative().default(0),
|
||||
});
|
||||
|
||||
// TODO: Replace output assertion type with the type of pokemon data that has CustomPokemonData.
|
||||
export function PreCustomPokemonDataMigrator(
|
||||
data: z.output<typeof Z$PokemonData>,
|
||||
): asserts data is z.output<typeof Z$PokemonData> {
|
||||
// Value of `-1` indicated no override, so we can ignore it.
|
||||
const nature = NatureSchema.safeParse(data.natureOverride);
|
||||
if (nature.success) {
|
||||
const customPokemonData = data.customPokemonData;
|
||||
// If natureOverride is valid, use it
|
||||
if (
|
||||
customPokemonData &&
|
||||
typeof customPokemonData === "object" &&
|
||||
((customPokemonData as { nature?: number }).nature ?? -1) === -1
|
||||
) {
|
||||
customPokemonData;
|
||||
} else {
|
||||
data.customPokemonData = {
|
||||
nature: nature.data,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type PreParsedPokemonData = z.input<typeof Z$PokemonData>;
|
||||
export type ParsedPokemonData = z.output<typeof Z$PokemonData>;
|
||||
|
||||
|
@ -1,47 +1,36 @@
|
||||
import { Z$NonNegativeInt } from "#system/schemas/common";
|
||||
import { Z$Gender } from "#system/schemas/v1.10/pokemon-gender";
|
||||
import { Z$PokemonSpeciesForm } from "#system/schemas/v1.10/pokemon-species-form";
|
||||
import { Z$PokemonMove } from "#system/schemas/v1.10/pokemon-move";
|
||||
import { Z$StatSet } from "#system/schemas/v1.10/pokemon-stats";
|
||||
import { Z$PokemonType } from "#system/schemas/v1.10/pokemon-type";
|
||||
import { Z$TurnMove } from "#system/schemas/v1.10/turn-move";
|
||||
import { z } from "zod";
|
||||
|
||||
const Z$StatStage = z.int().min(-6).max(6).catch(0);
|
||||
|
||||
const Z$StatStageSet = z.tuple([
|
||||
Z$StatStage,
|
||||
Z$StatStage,
|
||||
Z$StatStage,
|
||||
Z$StatStage,
|
||||
Z$StatStage,
|
||||
Z$StatStage,
|
||||
Z$StatStage,
|
||||
]);
|
||||
|
||||
// Pre version 1.10 pokemon summon data migration needs to rename
|
||||
// input fields
|
||||
export const Z$SerializedSpeciesForm = z.object({
|
||||
id: Z$NonNegativeInt,
|
||||
formIndex: Z$NonNegativeInt.catch(0),
|
||||
});
|
||||
|
||||
/**
|
||||
* Zod schema for Pokémon summon data as of version 1.10.
|
||||
*
|
||||
* @remarks
|
||||
* All fields other than `stats` are optional, and catch to `undefined` on parse error,
|
||||
* allowing {@linkcode PokemonSummonData} to fill in defaults.
|
||||
*
|
||||
*/
|
||||
export const Z$PokemonSummonData = z.object({
|
||||
statStages: Z$StatStageSet.optional().catch(undefined),
|
||||
statSages: z.array(z.int().min(-6).max(6).catch(0)).optional().catch(undefined),
|
||||
moveQueue: z.array(Z$TurnMove).optional().catch(undefined),
|
||||
// todo: tags
|
||||
abilitySuppressed: z.boolean().optional().catch(undefined),
|
||||
|
||||
//#region Overrides for transform
|
||||
speciesForm: Z$PokemonSpeciesForm.nullable().catch(null),
|
||||
fusionSpeciesForm: Z$PokemonSpeciesForm.nullable().catch(null),
|
||||
speciesForm: Z$SerializedSpeciesForm.optional().catch(undefined),
|
||||
ability: Z$NonNegativeInt.optional().catch(undefined),
|
||||
passiveAbility: Z$NonNegativeInt.optional().catch(undefined),
|
||||
gender: Z$Gender.optional().catch(undefined),
|
||||
fusionGender: Z$Gender.optional().catch(undefined),
|
||||
stats: Z$StatSet.optional().catch(undefined),
|
||||
moveset: z.array(Z$TurnMove).nullable().catch(null),
|
||||
//#endregion Overrides for transform
|
||||
|
||||
stats: Z$StatSet,
|
||||
moveset: z.array(Z$PokemonMove).optional().catch(undefined),
|
||||
types: z.array(Z$PokemonType).optional().catch(undefined),
|
||||
addedType: Z$PokemonType.nullable().catch(null),
|
||||
addedType: Z$PokemonType.optional().catch(undefined),
|
||||
illusion
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user