Compare commits
14 Commits
32f1254709
...
ba0a3f8395
Author | SHA1 | Date |
---|---|---|
Philippe | ba0a3f8395 | |
NightKev | 10e0f9f0de | |
AJ Fontaine | 8457fb96fe | |
damocleas | f95a5d41cb | |
Tempoanon | 6d903440b4 | |
NightKev | 7c57ccf42e | |
prateau | 02ad35a15e | |
Adrian T. | f88aaadbe7 | |
prateau | 7625093ed9 | |
prateau | 9312545deb | |
prateau | 6a0605c781 | |
prateau | 6d49080ca5 | |
prateau | 02940aa516 | |
prateau | 9f04d7d423 |
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "pokemon-rogue-battle",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pokemon-rogue-battle",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.1",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@material/material-color-utilities": "^0.2.7",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "pokemon-rogue-battle",
|
||||
"private": true,
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
|
|
|
@ -31,7 +31,7 @@ import { BerryType } from "#enums/berry-type";
|
|||
import { PERMANENT_STATS, Stat } from "#enums/stat";
|
||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import PokemonSpecies, { allSpecies } from "#app/data/pokemon-species";
|
||||
import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/berriesAbound";
|
||||
|
@ -62,8 +62,8 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
|||
let bossSpecies: PokemonSpecies;
|
||||
if (scene.eventManager.isEventActive() && scene.eventManager.activeEvent()?.uncommonBreedEncounters && randSeedInt(2) === 1) {
|
||||
const eventEncounter = randSeedItem(scene.eventManager.activeEvent()!.uncommonBreedEncounters!);
|
||||
bossSpecies = allSpecies[eventEncounter.species];
|
||||
bossSpecies.speciesId = bossSpecies.getSpeciesForLevel(level, eventEncounter.allowEvolution);
|
||||
const levelSpecies = getPokemonSpecies(eventEncounter.species).getWildSpeciesForLevel(level, eventEncounter.allowEvolution ?? false, true, scene.gameMode);
|
||||
bossSpecies = getPokemonSpecies( levelSpecies );
|
||||
} else {
|
||||
bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, level, 0, getPartyLuckValue(scene.getPlayerParty()), true);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encoun
|
|||
import { randSeedInt, randSeedItem } from "#app/utils";
|
||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import PokemonSpecies, { allSpecies } from "#app/data/pokemon-species";
|
||||
import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/fightOrFlight";
|
||||
|
@ -60,8 +60,8 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
|||
let bossSpecies: PokemonSpecies;
|
||||
if (scene.eventManager.isEventActive() && scene.eventManager.activeEvent()?.uncommonBreedEncounters && randSeedInt(2) === 1) {
|
||||
const eventEncounter = randSeedItem(scene.eventManager.activeEvent()!.uncommonBreedEncounters!);
|
||||
bossSpecies = allSpecies[eventEncounter.species];
|
||||
bossSpecies.speciesId = bossSpecies.getSpeciesForLevel(level, eventEncounter.allowEvolution);
|
||||
const levelSpecies = getPokemonSpecies(eventEncounter.species).getWildSpeciesForLevel(level, eventEncounter.allowEvolution ?? false, true, scene.gameMode);
|
||||
bossSpecies = getPokemonSpecies( levelSpecies );
|
||||
} else {
|
||||
bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, level, 0, getPartyLuckValue(scene.getPlayerParty()), true);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import { BerryModifier } from "#app/modifier/modifier";
|
|||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import { Stat } from "#enums/stat";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
import PokemonSpecies, { allSpecies } from "#app/data/pokemon-species";
|
||||
import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounters/uncommonBreed";
|
||||
|
@ -55,8 +55,8 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
|||
let species: PokemonSpecies;
|
||||
if (scene.eventManager.isEventActive() && scene.eventManager.activeEvent()?.uncommonBreedEncounters && randSeedInt(2) === 1) {
|
||||
const eventEncounter = randSeedItem(scene.eventManager.activeEvent()!.uncommonBreedEncounters!);
|
||||
species = allSpecies[eventEncounter.species];
|
||||
species.speciesId = species.getSpeciesForLevel(level, eventEncounter.allowEvolution);
|
||||
const levelSpecies = getPokemonSpecies(eventEncounter.species).getWildSpeciesForLevel(level, eventEncounter.allowEvolution ?? false, true, scene.gameMode);
|
||||
species = getPokemonSpecies( levelSpecies );
|
||||
} else {
|
||||
species = scene.arena.randomSpecies(scene.currentBattle.waveIndex, level, 0, getPartyLuckValue(scene.getPlayerParty()), true);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import { GameModes, getGameMode } from "#app/game-mode";
|
|||
import { BattleType } from "#app/battle";
|
||||
import TrainerData from "#app/system/trainer-data";
|
||||
import { trainerConfigs } from "#app/data/trainer-config";
|
||||
import { resetSettings, setSetting, SettingKeys } from "#app/system/settings/settings";
|
||||
import { resetSettings, setSetting, Setting, settingIndex, SettingKeys } from "#app/system/settings/settings";
|
||||
import { achvs } from "#app/system/achv";
|
||||
import EggData from "#app/system/egg-data";
|
||||
import { Egg } from "#app/data/egg";
|
||||
|
@ -65,16 +65,12 @@ export const defaultStarterSpecies: Species[] = [
|
|||
|
||||
const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary
|
||||
|
||||
export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0): string {
|
||||
export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0, username?: string): string {
|
||||
switch (dataType) {
|
||||
case GameDataType.SYSTEM:
|
||||
return "data";
|
||||
return `data_${username}`;
|
||||
case GameDataType.SESSION:
|
||||
let ret = "sessionData";
|
||||
if (slotId) {
|
||||
ret += slotId;
|
||||
}
|
||||
return ret;
|
||||
return `sessionData${slotId || ""}_${username}`;
|
||||
case GameDataType.SETTINGS:
|
||||
return "settings";
|
||||
case GameDataType.TUTORIALS:
|
||||
|
@ -82,7 +78,7 @@ export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0): str
|
|||
case GameDataType.SEEN_DIALOGUES:
|
||||
return "seenDialogues";
|
||||
case GameDataType.RUN_HISTORY:
|
||||
return "runHistoryData";
|
||||
return `runHistoryData_${username}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1364,9 +1360,35 @@ export class GameData {
|
|||
});
|
||||
}
|
||||
|
||||
public getDataToExport(dataType: GameDataType, slotId: integer = 0): Promise<string | null> {
|
||||
return new Promise<string | null>(resolve => {
|
||||
if (!bypassLogin && dataType < GameDataType.SETTINGS) {
|
||||
let promise: Promise<string | null> = Promise.resolve(null);
|
||||
|
||||
if (dataType === GameDataType.SYSTEM) {
|
||||
promise = pokerogueApi.savedata.system.get({ clientSessionId });
|
||||
} else if (dataType === GameDataType.SESSION) {
|
||||
promise = pokerogueApi.savedata.session.get({ slot: slotId, clientSessionId });
|
||||
}
|
||||
|
||||
promise.then(response => {
|
||||
if (!response?.length || response[0] !== "{") {
|
||||
console.error(response);
|
||||
resolve(null);
|
||||
}
|
||||
resolve(response);
|
||||
});
|
||||
} else {
|
||||
const dataKey: string = getDataTypeKey(dataType, slotId, loggedInUser?.username);
|
||||
const data = localStorage.getItem(dataKey);
|
||||
resolve((!data || dataType === GameDataType.SETTINGS) ? data : decrypt(data, bypassLogin));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public tryExportData(dataType: GameDataType, slotId: integer = 0): Promise<boolean> {
|
||||
return new Promise<boolean>(resolve => {
|
||||
const dataKey: string = `${getDataTypeKey(dataType, slotId)}_${loggedInUser?.username}`;
|
||||
const dataKey: string = getDataTypeKey(dataType, slotId, loggedInUser?.username);
|
||||
const handleData = (dataStr: string) => {
|
||||
switch (dataType) {
|
||||
case GameDataType.SYSTEM:
|
||||
|
@ -1381,38 +1403,56 @@ export class GameData {
|
|||
link.click();
|
||||
link.remove();
|
||||
};
|
||||
if (!bypassLogin && dataType < GameDataType.SETTINGS) {
|
||||
let promise: Promise<string | null> = Promise.resolve(null);
|
||||
|
||||
if (dataType === GameDataType.SYSTEM) {
|
||||
promise = pokerogueApi.savedata.system.get({ clientSessionId });
|
||||
} else if (dataType === GameDataType.SESSION) {
|
||||
promise = pokerogueApi.savedata.session.get({ slot: slotId, clientSessionId });
|
||||
}
|
||||
|
||||
promise.then(response => {
|
||||
if (!response?.length || response[0] !== "{") {
|
||||
console.error(response);
|
||||
resolve(false);
|
||||
return;
|
||||
this.getDataToExport(dataType, slotId)
|
||||
.then(data => {
|
||||
if (data) {
|
||||
handleData(data);
|
||||
}
|
||||
|
||||
handleData(response);
|
||||
resolve(true);
|
||||
resolve(!!data);
|
||||
});
|
||||
} else {
|
||||
const data = localStorage.getItem(dataKey);
|
||||
if (data) {
|
||||
handleData(decrypt(data, bypassLogin));
|
||||
}
|
||||
resolve(!!data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public importData(dataType: GameDataType, slotId: integer = 0): void {
|
||||
const dataKey = `${getDataTypeKey(dataType, slotId)}_${loggedInUser?.username}`;
|
||||
public validateDataToImport(dataStr: string, dataType: GameDataType): boolean {
|
||||
try {
|
||||
switch (dataType) {
|
||||
case GameDataType.SYSTEM:
|
||||
dataStr = this.convertSystemDataStr(dataStr);
|
||||
const systemData = this.parseSystemData(dataStr);
|
||||
return !!systemData.dexData && !!systemData.timestamp;
|
||||
case GameDataType.SESSION:
|
||||
const sessionData = this.parseSessionData(dataStr);
|
||||
return !!sessionData.party && !!sessionData.enemyParty && !!sessionData.timestamp;
|
||||
case GameDataType.RUN_HISTORY:
|
||||
const data = JSON.parse(dataStr);
|
||||
const keys = Object.keys(data);
|
||||
return keys.every((key) => {
|
||||
const entryKeys = Object.keys(data[key]);
|
||||
return [ "isFavorite", "isVictory", "entry" ].every(v => entryKeys.includes(v)) && entryKeys.length === 3;
|
||||
});
|
||||
case GameDataType.SETTINGS:
|
||||
return Object.entries(JSON.parse(dataStr))
|
||||
.every(([ k, v ]: [string, number]) => {
|
||||
const index: number = settingIndex(k);
|
||||
return index === -1 || Setting[index].options.length > v;
|
||||
});
|
||||
case GameDataType.TUTORIALS:
|
||||
case GameDataType.SEEN_DIALOGUES:
|
||||
return true;
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public setImportedData(dataStr: string, dataType: GameDataType, slotId: integer = 0) {
|
||||
const dataKey = getDataTypeKey(dataType, slotId, loggedInUser?.username);
|
||||
const encryptedData = (dataType === GameDataType.SETTINGS) ? dataStr : encrypt(dataStr, bypassLogin);
|
||||
localStorage.setItem(dataKey, encryptedData);
|
||||
}
|
||||
|
||||
public importData(dataType: GameDataType, slotId: integer = 0): void {
|
||||
let saveFile: any = document.getElementById("saveFile");
|
||||
if (saveFile) {
|
||||
saveFile.remove();
|
||||
|
@ -1429,41 +1469,13 @@ export class GameData {
|
|||
|
||||
reader.onload = (_ => {
|
||||
return e => {
|
||||
let dataName: string;
|
||||
let dataStr = AES.decrypt(e.target?.result?.toString()!, saveKey).toString(enc.Utf8); // TODO: is this bang correct?
|
||||
let valid = false;
|
||||
try {
|
||||
dataName = GameDataType[dataType].toLowerCase();
|
||||
switch (dataType) {
|
||||
case GameDataType.SYSTEM:
|
||||
dataStr = this.convertSystemDataStr(dataStr);
|
||||
const systemData = this.parseSystemData(dataStr);
|
||||
valid = !!systemData.dexData && !!systemData.timestamp;
|
||||
break;
|
||||
case GameDataType.SESSION:
|
||||
const sessionData = this.parseSessionData(dataStr);
|
||||
valid = !!sessionData.party && !!sessionData.enemyParty && !!sessionData.timestamp;
|
||||
break;
|
||||
case GameDataType.RUN_HISTORY:
|
||||
const data = JSON.parse(dataStr);
|
||||
const keys = Object.keys(data);
|
||||
dataName = i18next.t("menuUiHandler:RUN_HISTORY").toLowerCase();
|
||||
keys.forEach((key) => {
|
||||
const entryKeys = Object.keys(data[key]);
|
||||
valid = [ "isFavorite", "isVictory", "entry" ].every(v => entryKeys.includes(v)) && entryKeys.length === 3;
|
||||
});
|
||||
break;
|
||||
case GameDataType.SETTINGS:
|
||||
case GameDataType.TUTORIALS:
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
}
|
||||
const dataName = (dataType === GameDataType.RUN_HISTORY)
|
||||
? i18next.t("menuUiHandler:RUN_HISTORY").toLowerCase()
|
||||
: GameDataType[dataType].toLowerCase();
|
||||
const dataStr = AES.decrypt(e.target?.result?.toString()!, saveKey).toString(enc.Utf8); // TODO: is this bang correct?
|
||||
const valid = this.validateDataToImport(dataStr, dataType);
|
||||
|
||||
const displayError = (error: string) => this.scene.ui.showText(error, null, () => this.scene.ui.showText("", 0), Utils.fixedInt(1500));
|
||||
dataName = dataName!; // tell TS compiler that dataName is defined!
|
||||
|
||||
if (!valid) {
|
||||
return this.scene.ui.showText(`Your ${dataName} data could not be loaded. It may be corrupted.`, null, () => this.scene.ui.showText("", 0), Utils.fixedInt(1500));
|
||||
|
@ -1471,7 +1483,7 @@ export class GameData {
|
|||
|
||||
this.scene.ui.showText(`Your ${dataName} data will be overridden and the page will reload. Proceed?`, null, () => {
|
||||
this.scene.ui.setOverlayMode(Mode.CONFIRM, () => {
|
||||
localStorage.setItem(dataKey, encrypt(dataStr, bypassLogin));
|
||||
this.setImportedData(dataStr, dataType, slotId);
|
||||
|
||||
if (!bypassLogin && dataType < GameDataType.SETTINGS) {
|
||||
updateUserInfo().then(success => {
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as BattleScene from "#app/battle-scene";
|
|||
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
||||
import { SessionSaveData } from "#app/system/game-data";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { GameDataType } from "#enums/game-data-type";
|
||||
import { Moves } from "#enums/moves";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
|
@ -73,4 +74,63 @@ describe("System - Game Data", () => {
|
|||
expect(account.updateUserInfo).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getDataToExport", () => {
|
||||
it("should get default settings", async () => {
|
||||
const defaultSettings = "{\"PLAYER_GENDER\":0,\"gameVersion\":\"1.0.4\"}";
|
||||
localStorage.setItem("settings", defaultSettings);
|
||||
|
||||
const result = await game.scene.gameData.getDataToExport(GameDataType.SETTINGS);
|
||||
|
||||
expect(result).toEqual(defaultSettings);
|
||||
});
|
||||
|
||||
it("should get undefined when there is no settings", async () => {
|
||||
const result = await game.scene.gameData.getDataToExport(GameDataType.SETTINGS);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("setImportedData", () => {
|
||||
it("should set settings in local storage", () => {
|
||||
const settings = "{\"PLAYER_GENDER\":0,\"gameVersion\":\"1.0.4\"}";
|
||||
game.scene.gameData.setImportedData(settings, GameDataType.SETTINGS);
|
||||
|
||||
expect(localStorage.getItem("settings")).toEqual(settings);
|
||||
});
|
||||
|
||||
it("should override default settings", () => {
|
||||
const defaultSettings = "{\"PLAYER_GENDER\":0,\"gameVersion\":\"1.0.4\"}";
|
||||
localStorage.setItem("settings", defaultSettings);
|
||||
|
||||
const newSettings = "{\"PLAYER_GENDER\":1,\"gameVersion\":\"1.0.7\",\"GAME_SPEED\":7}";
|
||||
game.scene.gameData.setImportedData(newSettings, GameDataType.SETTINGS);
|
||||
|
||||
expect(localStorage.getItem("settings")).toEqual(newSettings);
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateDataToImport", () => {
|
||||
it("should be true when the setting data is valid", async () => {
|
||||
const settings = "{\"PLAYER_GENDER\":0,\"gameVersion\":\"1.0.4\"}";
|
||||
const result = await game.scene.gameData.validateDataToImport(settings, GameDataType.SETTINGS);
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should be false when the setting data is an invalid JSON", async () => {
|
||||
const settings = "";
|
||||
const result = await game.scene.gameData.validateDataToImport(settings, GameDataType.SETTINGS);
|
||||
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should be false when the setting data contains an unknow value", async () => {
|
||||
const settings = "{\"PLAYER_GENDER\":0,\"gameVersion\":\"1.0.4\",\"GAME_SPEED\":999}";
|
||||
const result = await game.scene.gameData.validateDataToImport(settings, GameDataType.SETTINGS);
|
||||
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -246,6 +246,22 @@ export default class MenuUiHandler extends MessageUiHandler {
|
|||
},
|
||||
keepOpen: true
|
||||
});
|
||||
manageDataOptions.push({
|
||||
label: i18next.t("menuUiHandler:importSettings"),
|
||||
handler: () => {
|
||||
this.scene.gameData.importData(GameDataType.SETTINGS);
|
||||
return true;
|
||||
},
|
||||
keepOpen: true
|
||||
});
|
||||
manageDataOptions.push({
|
||||
label: i18next.t("menuUiHandler:exportSettings"),
|
||||
handler: () => {
|
||||
this.scene.gameData.tryExportData(GameDataType.SETTINGS);
|
||||
return true;
|
||||
},
|
||||
keepOpen: true
|
||||
});
|
||||
if (Utils.isLocal || Utils.isBeta) {
|
||||
manageDataOptions.push({
|
||||
label: i18next.t("menuUiHandler:importData"),
|
||||
|
|
Loading…
Reference in New Issue