diff --git a/src/system/version_migration/v1_0_4/session_migrators.ts b/src/system/version_migration/v1_0_4/session_migrators.ts deleted file mode 100644 index 766df68d2fe..00000000000 --- a/src/system/version_migration/v1_0_4/session_migrators.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { SessionSaveData } from "../../game-data"; - -/** - * Converts old lapsing modifiers (battle items, lures, and Dire Hit) and - * other miscellaneous modifiers (vitamins, White Herb) to any new class - * names and/or change in reload arguments. - * @param data {@linkcode SessionSaveData} - */ -export function migrateModifiers(data: SessionSaveData) { - data.modifiers.forEach((m) => { - if (m.className === "PokemonBaseStatModifier") { - m.className = "BaseStatModifier"; - } else if (m.className === "PokemonResetNegativeStatStageModifier") { - m.className = "ResetNegativeStatStageModifier"; - } else if (m.className === "TempBattleStatBoosterModifier") { - const maxBattles = 5; - // Dire Hit no longer a part of the TempBattleStatBoosterModifierTypeGenerator - if (m.typeId !== "DIRE_HIT") { - m.className = "TempStatStageBoosterModifier"; - m.typeId = "TEMP_STAT_STAGE_BOOSTER"; - - // Migration from TempBattleStat to Stat - const newStat = m.typePregenArgs[0] + 1; - m.typePregenArgs[0] = newStat; - - // From [ stat, battlesLeft ] to [ stat, maxBattles, battleCount ] - m.args = [ newStat, maxBattles, Math.min(m.args[1], maxBattles) ]; - } else { - m.className = "TempCritBoosterModifier"; - m.typePregenArgs = []; - - // From [ stat, battlesLeft ] to [ maxBattles, battleCount ] - m.args = [ maxBattles, Math.min(m.args[1], maxBattles) ]; - } - } else if (m.className === "DoubleBattleChanceBoosterModifier" && m.args.length === 1) { - let maxBattles: number; - switch (m.typeId) { - case "MAX_LURE": - maxBattles = 30; - break; - case "SUPER_LURE": - maxBattles = 15; - break; - default: - maxBattles = 10; - break; - } - - // From [ battlesLeft ] to [ maxBattles, battleCount ] - m.args = [ maxBattles, Math.min(m.args[0], maxBattles) ]; - } - }); - - data.enemyModifiers.forEach((m) => { - if (m.className === "PokemonBaseStatModifier") { - m.className = "BaseStatModifier"; - } else if (m.className === "PokemonResetNegativeStatStageModifier") { - m.className = "ResetNegativeStatStageModifier"; - } - }); -} diff --git a/src/system/version_migration/v1_0_4/settings_migrators.ts b/src/system/version_migration/v1_0_4/settings_migrators.ts deleted file mode 100644 index 59955d53352..00000000000 --- a/src/system/version_migration/v1_0_4/settings_migrators.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { SettingKeys } from "../../settings/settings"; - -/** - * Migrate from "REROLL_TARGET" property to {@linkcode - * SettingKeys.Shop_Cursor_Target}. - * @param data the `settings` object - */ -export function fixRerollTarget(data: Object) { - if (data.hasOwnProperty("REROLL_TARGET") && !data.hasOwnProperty(SettingKeys.Shop_Cursor_Target)) { - data[SettingKeys.Shop_Cursor_Target] = data["REROLL_TARGET"]; - delete data["REROLL_TARGET"]; - localStorage.setItem("settings", JSON.stringify(data)); - } -} diff --git a/src/system/version_migration/v1_0_4/system_migrators.ts b/src/system/version_migration/v1_0_4/system_migrators.ts deleted file mode 100644 index 8d40c0985b9..00000000000 --- a/src/system/version_migration/v1_0_4/system_migrators.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { AbilityAttr, defaultStarterSpecies, DexAttr, SystemSaveData } from "../../game-data"; -import { allSpecies } from "../../../data/pokemon-species"; - -/** - * Migrate ability starter data if empty for caught species - * @param data {@linkcode SystemSaveData} - */ -export function migrateAbilityData(data: SystemSaveData) { - if (data.starterData && data.dexData) { - // Migrate ability starter data if empty for caught species - Object.keys(data.starterData).forEach(sd => { - if (data.dexData[sd]?.caughtAttr && (data.starterData[sd] && !data.starterData[sd].abilityAttr)) { - data.starterData[sd].abilityAttr = 1; - } - }); - } -} - -/** - * Populate legendary Pokémon statistics if they are missing - * @param data {@linkcode SystemSaveData} - */ -export function fixLegendaryStats(data: SystemSaveData) { - if (data.gameStats && (data.gameStats.legendaryPokemonCaught !== undefined && data.gameStats.subLegendaryPokemonCaught === undefined)) { - data.gameStats.subLegendaryPokemonSeen = 0; - data.gameStats.subLegendaryPokemonCaught = 0; - data.gameStats.subLegendaryPokemonHatched = 0; - allSpecies.filter(s => s.subLegendary).forEach(s => { - const dexEntry = data.dexData[s.speciesId]; - data.gameStats.subLegendaryPokemonSeen += dexEntry.seenCount; - data.gameStats.legendaryPokemonSeen = Math.max(data.gameStats.legendaryPokemonSeen - dexEntry.seenCount, 0); - data.gameStats.subLegendaryPokemonCaught += dexEntry.caughtCount; - data.gameStats.legendaryPokemonCaught = Math.max(data.gameStats.legendaryPokemonCaught - dexEntry.caughtCount, 0); - data.gameStats.subLegendaryPokemonHatched += dexEntry.hatchedCount; - data.gameStats.legendaryPokemonHatched = Math.max(data.gameStats.legendaryPokemonHatched - dexEntry.hatchedCount, 0); - }); - data.gameStats.subLegendaryPokemonSeen = Math.max(data.gameStats.subLegendaryPokemonSeen, data.gameStats.subLegendaryPokemonCaught); - data.gameStats.legendaryPokemonSeen = Math.max(data.gameStats.legendaryPokemonSeen, data.gameStats.legendaryPokemonCaught); - data.gameStats.mythicalPokemonSeen = Math.max(data.gameStats.mythicalPokemonSeen, data.gameStats.mythicalPokemonCaught); - } -} - -/** - * Unlock all starters' first ability and female gender option - * @param data {@linkcode SystemSaveData} - */ -export function fixStarterData(data: SystemSaveData) { - for (const starterId of defaultStarterSpecies) { - if (data.starterData[starterId]?.abilityAttr) { - data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1; - } - if (data.dexData[starterId]?.caughtAttr) { - data.dexData[starterId].caughtAttr |= DexAttr.FEMALE; - } - } -} diff --git a/src/system/version_migration/version_converter.ts b/src/system/version_migration/version_converter.ts index 10aa11f7b25..0fcfa9f9fdc 100644 --- a/src/system/version_migration/version_converter.ts +++ b/src/system/version_migration/version_converter.ts @@ -2,9 +2,7 @@ import { SessionSaveData, SystemSaveData } from "../game-data"; import { version } from "../../../package.json"; // --- v1.0.4 (and below) PATCHES --- // -import * as v1_0_4SessionData from "./v1_0_4/session_migrators"; -import * as v1_0_4SystemData from "./v1_0_4/system_migrators"; -import * as v1_0_4SettingsData from "./v1_0_4/settings_migrators"; +import * as v1_0_4 from "./versions/v1_0_4"; const LATEST_VERSION = version.split(".").map(value => parseInt(value)); @@ -16,9 +14,8 @@ export abstract class VersionConverter { } } - callMigrators(data: any, migrationObject: Object) { - const migrators = Object.values(migrationObject); - for (const migrate of migrators) { + callMigrators(data: any, migrationArr: readonly any[]) { + for (const migrate of migrationArr) { migrate(data); } } @@ -40,7 +37,7 @@ export class SessionVersionConverter extends VersionConverter { case 0: if (curPatch <= 4) { console.log("Applying v1.0.4 session data migration!"); - this.callMigrators(data, v1_0_4SessionData); + this.callMigrators(data, v1_0_4.sessionMigrators); } default: } @@ -64,7 +61,7 @@ export class SystemVersionConverter extends VersionConverter { case 0: if (curPatch <= 4) { console.log("Applying v1.0.4 system data migraton!"); - this.callMigrators(data, v1_0_4SystemData); + this.callMigrators(data, v1_0_4.systemMigrators); } default: } @@ -89,7 +86,7 @@ export class SettingsVersionConverter extends VersionConverter { case 0: if (curPatch <= 4) { console.log("Applying v1.0.4 settings data migraton!"); - this.callMigrators(data, v1_0_4SettingsData); + this.callMigrators(data, v1_0_4.sessionMigrators); } default: } diff --git a/src/system/version_migration/versions/v1_0_4.ts b/src/system/version_migration/versions/v1_0_4.ts new file mode 100644 index 00000000000..4131ee4236d --- /dev/null +++ b/src/system/version_migration/versions/v1_0_4.ts @@ -0,0 +1,137 @@ +import { SettingKeys } from "../../settings/settings"; +import { AbilityAttr, defaultStarterSpecies, DexAttr, SystemSaveData, SessionSaveData } from "../../game-data"; +import { allSpecies } from "../../../data/pokemon-species"; + + +export const systemMigrators = [ + /** + * Migrate ability starter data if empty for caught species + * @param data {@linkcode SystemSaveData} + */ + function migrateAbilityData(data: SystemSaveData) { + if (data.starterData && data.dexData) { + // Migrate ability starter data if empty for caught species + Object.keys(data.starterData).forEach(sd => { + if (data.dexData[sd]?.caughtAttr && (data.starterData[sd] && !data.starterData[sd].abilityAttr)) { + data.starterData[sd].abilityAttr = 1; + } + }); + } + }, + + /** + * Populate legendary Pokémon statistics if they are missing + * @param data {@linkcode SystemSaveData} + */ + function fixLegendaryStats(data: SystemSaveData) { + if (data.gameStats && (data.gameStats.legendaryPokemonCaught !== undefined && data.gameStats.subLegendaryPokemonCaught === undefined)) { + data.gameStats.subLegendaryPokemonSeen = 0; + data.gameStats.subLegendaryPokemonCaught = 0; + data.gameStats.subLegendaryPokemonHatched = 0; + allSpecies.filter(s => s.subLegendary).forEach(s => { + const dexEntry = data.dexData[s.speciesId]; + data.gameStats.subLegendaryPokemonSeen += dexEntry.seenCount; + data.gameStats.legendaryPokemonSeen = Math.max(data.gameStats.legendaryPokemonSeen - dexEntry.seenCount, 0); + data.gameStats.subLegendaryPokemonCaught += dexEntry.caughtCount; + data.gameStats.legendaryPokemonCaught = Math.max(data.gameStats.legendaryPokemonCaught - dexEntry.caughtCount, 0); + data.gameStats.subLegendaryPokemonHatched += dexEntry.hatchedCount; + data.gameStats.legendaryPokemonHatched = Math.max(data.gameStats.legendaryPokemonHatched - dexEntry.hatchedCount, 0); + }); + data.gameStats.subLegendaryPokemonSeen = Math.max(data.gameStats.subLegendaryPokemonSeen, data.gameStats.subLegendaryPokemonCaught); + data.gameStats.legendaryPokemonSeen = Math.max(data.gameStats.legendaryPokemonSeen, data.gameStats.legendaryPokemonCaught); + data.gameStats.mythicalPokemonSeen = Math.max(data.gameStats.mythicalPokemonSeen, data.gameStats.mythicalPokemonCaught); + } + }, + + /** + * Unlock all starters' first ability and female gender option + * @param data {@linkcode SystemSaveData} + */ + function fixStarterData(data: SystemSaveData) { + for (const starterId of defaultStarterSpecies) { + if (data.starterData[starterId]?.abilityAttr) { + data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1; + } + if (data.dexData[starterId]?.caughtAttr) { + data.dexData[starterId].caughtAttr |= DexAttr.FEMALE; + } + } + } +] as const; + +export const settingsMigrators = [ + /** + * Migrate from "REROLL_TARGET" property to {@linkcode + * SettingKeys.Shop_Cursor_Target}. + * @param data the `settings` object + */ + function fixRerollTarget(data: Object) { + if (data.hasOwnProperty("REROLL_TARGET") && !data.hasOwnProperty(SettingKeys.Shop_Cursor_Target)) { + data[SettingKeys.Shop_Cursor_Target] = data["REROLL_TARGET"]; + delete data["REROLL_TARGET"]; + localStorage.setItem("settings", JSON.stringify(data)); + } + } +] as const; + +export const sessionMigrators = [ + /** + * Converts old lapsing modifiers (battle items, lures, and Dire Hit) and + * other miscellaneous modifiers (vitamins, White Herb) to any new class + * names and/or change in reload arguments. + * @param data {@linkcode SessionSaveData} + */ + function migrateModifiers(data: SessionSaveData) { + data.modifiers.forEach((m) => { + if (m.className === "PokemonBaseStatModifier") { + m.className = "BaseStatModifier"; + } else if (m.className === "PokemonResetNegativeStatStageModifier") { + m.className = "ResetNegativeStatStageModifier"; + } else if (m.className === "TempBattleStatBoosterModifier") { + const maxBattles = 5; + // Dire Hit no longer a part of the TempBattleStatBoosterModifierTypeGenerator + if (m.typeId !== "DIRE_HIT") { + m.className = "TempStatStageBoosterModifier"; + m.typeId = "TEMP_STAT_STAGE_BOOSTER"; + + // Migration from TempBattleStat to Stat + const newStat = m.typePregenArgs[0] + 1; + m.typePregenArgs[0] = newStat; + + // From [ stat, battlesLeft ] to [ stat, maxBattles, battleCount ] + m.args = [ newStat, maxBattles, Math.min(m.args[1], maxBattles) ]; + } else { + m.className = "TempCritBoosterModifier"; + m.typePregenArgs = []; + + // From [ stat, battlesLeft ] to [ maxBattles, battleCount ] + m.args = [ maxBattles, Math.min(m.args[1], maxBattles) ]; + } + } else if (m.className === "DoubleBattleChanceBoosterModifier" && m.args.length === 1) { + let maxBattles: number; + switch (m.typeId) { + case "MAX_LURE": + maxBattles = 30; + break; + case "SUPER_LURE": + maxBattles = 15; + break; + default: + maxBattles = 10; + break; + } + + // From [ battlesLeft ] to [ maxBattles, battleCount ] + m.args = [ maxBattles, Math.min(m.args[0], maxBattles) ]; + } + }); + + data.enemyModifiers.forEach((m) => { + if (m.className === "PokemonBaseStatModifier") { + m.className = "BaseStatModifier"; + } else if (m.className === "PokemonResetNegativeStatStageModifier") { + m.className = "ResetNegativeStatStageModifier"; + } + }); + } +] as const;