diff --git a/src/data/nature.ts b/src/data/nature.ts index 86da8bc66a4..724314390af 100644 --- a/src/data/nature.ts +++ b/src/data/nature.ts @@ -61,7 +61,7 @@ export function getNatureName(nature: Nature, includeStatEffects: boolean = fals return ret; } -export function getNatureIncrease(nature: Nature): string { +export function getNatureIncrease(nature: Nature) { switch (nature) { case Nature.LONELY: case Nature.BRAVE: @@ -102,7 +102,7 @@ export function getNatureIncrease(nature: Nature): string { return "" } } -export function getNatureDecrease(nature: Nature): string { +export function getNatureDecrease(nature: Nature) { switch (nature) { case Nature.BOLD: case Nature.TIMID: diff --git a/src/logger.ts b/src/logger.ts index 5546970f08b..9d6a03bc1bb 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,3 +1,4 @@ +//#region Imports import i18next from "i18next"; import * as Utils from "./utils"; import Pokemon from "./field/pokemon"; @@ -5,52 +6,111 @@ import { PlayerPokemon, EnemyPokemon } from "./field/pokemon"; import { Nature, getNatureDecrease, getNatureIncrease, getNatureName } from "./data/nature"; import BattleScene from "./battle-scene"; import { OptionSelectItem } from "./ui/abstact-option-select-ui-handler"; -import { TrainerType } from "#enums/trainer-type"; -import { Modifier, PokemonHeldItemModifier } from "./modifier/modifier"; -import Battle from "./battle"; +import { PokemonHeldItemModifier } from "./modifier/modifier"; import { getBiomeName, PokemonPools, SpeciesTree } from "./data/biomes"; -import { trainerConfigs } from "./data/trainer-config"; import { Mode } from "./ui/ui"; -import { LoginPhase, TitlePhase } from "./phases"; -import { Item } from "pokenode-ts"; +import { TitlePhase } from "./phases"; import Trainer from "./field/trainer"; import { Species } from "./enums/species"; -import { junit } from "node:test/reporters"; -import { i } from "vitest/dist/reporters-xEmem8D4.js"; import { GameMode, GameModes } from "./game-mode"; +import { randomUUID, UUID } from "node:crypto"; +//#endregion + + + + +// #region Variables + +// Value holders +export const rarities = [] +export const rarityslot = [0, ""] +export const Actions = [] + +// Booleans +export const isPreSwitch: Utils.BooleanHolder = new Utils.BooleanHolder(false); +export const isFaintSwitch: Utils.BooleanHolder = new Utils.BooleanHolder(false); +export const SheetsMode = new Utils.BooleanHolder(false) + +// (unused) Stores the current DRPD +/** @deprecated */ +export var StoredLog: DRPD = undefined; + +/** The current DRPD version. */ +export const DRPD_Version = "1.1.0" +/** (Unused / reference only) All the log versions that this mod can keep updated. + * @see updateLog +*/ +export const acceptedVersions = [ + "1.0.0", + "1.0.0a", + "1.1.0", +] + +// #endregion + + + + + +//#region Downloading /** - * All logs. + * Saves a log to your device. + * @param i The index of the log you want to save. + */ +export function downloadLogByID(i: integer) { + console.log(i) + var d = JSON.parse(localStorage.getItem(logs[i][1])) + const blob = new Blob([ printDRPD("", "", d as DRPD) ], {type: "text/json"}); + const link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + var date: string = (d as DRPD).date + var filename: string = date[5] + date[6] + "_" + date[8] + date[9] + "_" + date[0] + date[1] + date[2] + date[3] + "_" + (d as DRPD).label + ".json" + link.download = `${filename}`; + link.click(); + link.remove(); +} +/** + * Saves a log to your device in an alternate format. + * @param i The index of the log you want to save. + */ +export function downloadLogByIDToSheet(i: integer) { + console.log(i) + var d = JSON.parse(localStorage.getItem(logs[i][1])) + SheetsMode.value = true; + const blob = new Blob([ printDRPD("", "", d as DRPD) ], {type: "text/json"}); + SheetsMode.value = false; + const link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + var date: string = (d as DRPD).date + var filename: string = date[5] + date[6] + "_" + date[8] + date[9] + "_" + date[0] + date[1] + date[2] + date[3] + "_" + (d as DRPD).label + "_sheetexport" + ".json" + link.download = `${filename}`; + link.click(); + link.remove(); +} +//#endregion + + + + + +// #region Log Handler +/** + * Stores logs. + * Generate a new list with `getLogs()`. * - * Format: [filename, localStorage key, name, header, item sprite, header suffix] + * @see getLogs */ export const logs: string[][] = [ - //["instructions.txt", "path_log", "Steps", "Run Steps", "blunder_policy", ""], - //["encounters.csv", "enc_log", "Encounters", "Encounter Data", "ub", ",,,,,,,,,,,,,,,,"], ["drpd.json", "drpd", "DRPD", "", "wide_lens", ""], - //["drpd1.json", "drpd1", "DRPD 1", "", "wide_lens", ""], - //["drpd2.json", "drpd2", "DRPD 2", "", "wide_lens", ""], - //["drpd3.json", "drpd3", "DRPD 3", "", "wide_lens", ""], - //["drpd4.json", "drpd4", "DRPD 4", "", "wide_lens", ""], - //["drpd5.json", "drpd5", "DRPD 5", "", "wide_lens", ""], ] +/** @deprecated */ export const logKeys: string[] = [ "i", // Instructions/steps "e", // Encounters "d", // Debug ]; -export const RNGState: number[] = [] - -export const autoCheckpoints: integer[] = [ - 1, - 11, - 21, - 31, - 41, - 50 -] - /** * Uses the save's RNG seed to create a log ID. Used to assign each save its own log. * @param scene The BattleScene. @@ -71,6 +131,8 @@ export function getItemsID(scene: BattleScene) { } /** * Resets the `logs` array, and creates a list of all game logs in LocalStorage. + * + * @see logs */ export function getLogs() { while(logs.length > 0) @@ -103,6 +165,103 @@ export function getMode(scene: BattleScene) { } } +// #endregion + + + + + +// #region Utilities + +/** + * Pulls the current run's DRPD from LocalStorage using the run's RNG seed. + * @param scene The BattleScene. Used to get the wave number, which is what determines the name of the log we need. + * @returns The DRPD file, or `null` if there is no file for this run. + */ +export function getDRPD(scene: BattleScene): DRPD { + var drpd: DRPD = JSON.parse(localStorage.getItem(getLogID(scene))) as DRPD; + if (drpd == undefined || drpd == null) + return null; + drpd = updateLog(drpd); + //scene.arenaFlyout.updateFieldText() + return drpd; +} + +/** + * Testing purposes only. + */ +export const RNGState: number[] = [] + +/** + * The waves that autosaves are created at. + */ +export const autoCheckpoints: integer[] = [ + 1, + 11, + 21, + 31, + 41, + 50 +] + +/** + * Used to get the filesize of a string. + */ +export const byteSize = str => new Blob([str]).size +/** + * Contains names for different file size units. + * + * B: 1 byte + * + * KB: 1,000 bytes + * + * MB: 1,000,000 bytes + * + * GB: 1,000,000,000 bytes + * + * TB: 1,000,000,000,000 bytes + */ +const filesizes = ["b", "kb", "mb", "gb", "tb"] +/** + * Returns the size of a file, in bytes, KB, MB, GB, or (hopefully not) TB. + * @param str The data to get the size of. + * @returns The file size. Every thousand units is moved up to the next unit and rounded to the nearest tenth (i.e. 1,330,000 bytes will return "1.3mb" - 1,330,000b --> 1,330kb --> 1.3mb) + * @see filesizes + */ +export function getSize(str: string) { + var d = byteSize(str) + var unit = 0 + while (d > 1000 && unit < filesizes.length - 1) { + d = Math.round(d/100)/10 + unit++ + } + return d.toString() + filesizes[unit] +} + +/** + * Compares a Species to a biome's tier pool. + * @param species The species to search for. + * @param pool The SpeciesPool tier to compare. + * @returns whether or not `species` was found in the `pool`. + */ +function checkForPokeInBiome(species: Species, pool: (Species | SpeciesTree)[]): boolean { + //console.log(species, pool) + for (var i = 0; i < pool.length; i++) { + if (typeof pool[i] === "number") { + //console.log(pool[i] + " == " + species + "? " + (pool[i] == species)) + if (pool[i] == species) return true; + } else { + var k = Object.keys(pool[i]) + //console.log(pool[i], k) + for (var j = 0; j < k.length; j++) { + //console.log(pool[i][k[j]] + " == " + species + "? " + (pool[i][k[j]] == species)) + if (pool[i][k[j]] == species) return true; + } + } + } + return false; +} + /** * Formats a Pokemon in the player's party. * @param scene The BattleScene, for getting the player's party. @@ -129,95 +288,80 @@ export function enemyPokeName(scene: BattleScene, index: integer | Pokemon | Ene } // LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, "") -export const rarities = [] -export const rarityslot = [0, ""] +// #endregion -export const isPreSwitch: Utils.BooleanHolder = new Utils.BooleanHolder(false); -export const isFaintSwitch: Utils.BooleanHolder = new Utils.BooleanHolder(false); -export var StoredLog: DRPD = undefined; -export const DRPD_Version = "1.0.0a" -export const acceptedVersions = [ - "1.0.0", - "1.0.0a", -] -export interface DRPD { - version: string, - title?: string, - authors: string[], - date: string, - waves: Wave[], - starters?: PokeData[] -} -export interface Wave { - id: integer, - reload: boolean, - type: string, - double: boolean, - actions: string[], - shop: string, - biome: string, - clearActionsFlag: boolean, - trainer?: TrainerData, - pokemon?: PokeData[] -} -export interface PokeData { - id: integer, - name: string, - ability: string, - isHiddenAbility: boolean, - passiveAbility: string, - nature: NatureData, - gender: string, - rarity: string, - captured: boolean, - level: integer, - items: ItemData[], - ivs: IVData, - source?: Pokemon -} -export interface NatureData { - name: string, - increased: string, - decreased: string -} -export interface IVData { - hp: integer, - atk: integer, - def: integer, - spatk: integer, - spdef: integer, - speed: integer -} -export interface TrainerData { - id: integer, - name: string, - type: string, -} -export interface ItemData { - id: string, - name: string, - quantity: integer, + + +// #region DRPD +/** + * Updates a DRPD, checkings its version and making any necessary changes to it in order to keep it up to date. + * + * @param drpd The DRPD document to update. Its version will be read automatically. + * @see DRPD + */ +function updateLog(drpd: DRPD): DRPD { + if (drpd.version == "1.0.0") { + drpd.version = "1.0.0a" + console.log("Updated to 1.0.0a - changed item IDs to strings") + for (var i = 0; i < drpd.waves.length; i++) { + if (drpd.waves[i] != undefined) { + if (drpd.waves[i].pokemon != undefined) { + for (var j = 0; j < drpd.waves[i].pokemon.length; j++) { + for (var k = 0; k < drpd.waves[i].pokemon[j].items.length; k++) { + drpd.waves[i].pokemon[j].items[k].id = drpd.waves[i].pokemon[j].items[k].id.toString() + } + } + } + } + } + for (var j = 0; j < drpd.starters.length; j++) { + for (var k = 0; k < drpd.starters[j].items.length; k++) { + drpd.starters[j].items[k].id = drpd.starters[j].items[k].id.toString() + } + } + } // 1.0.0 → 1.0.0a + if (drpd.version == "1.0.0a") { + drpd.version = "1.1.0" + drpd.uuid = randomUUID() + drpd.label = "route" + } // 1.0.0a → 1.1.0 + return drpd; } -export const Actions = [] + + + /** - * Creates a new document in the DRPD format - * @param name (Optional) The name for the file. Defaults to "Untitled Run". - * @param authorName (Optional) The author(s) of the file. Defaults to "Write your name here". - * @returns The fresh DRPD document. + * The Daily Run Pathing Description (DRPD) Specification is a JSON standard for organizing the information about a daily run. */ -export function newDocument(name: string = "Untitled Run", authorName: string | string[] = "Write your name here"): DRPD { - return { - version: DRPD_Version, - title: name, - authors: (Array.isArray(authorName) ? authorName : [authorName]), - date: (new Date().getUTCMonth() + 1 < 10 ? "0" : "") + (new Date().getUTCMonth() + 1) + "-" + (new Date().getUTCDate() < 10 ? "0" : "") + new Date().getUTCDate() + "-" + new Date().getUTCFullYear(), - waves: new Array(50), - starters: new Array(3), - } +export interface DRPD { + /** The version of this run. @see DRPD_Version */ + version: string, + /** The display name of this run. Not to be confused with `label`. Entered by the user. */ + title?: string, + /** The webpage path and internal name of this run. Entered by the user. Not to be confused with `title`, which is only a cosmetic identifier. */ + label: string, + /** A unique ID for this run. Currently unused, but may be used in the future. */ + uuid: UUID, + /** The name(s) of the users that worked on this run. Entered by the user. */ + authors: string[], + /** The date that this document was created on. Does NOT automatically detect the date of daily runs (It can't) */ + date: string, + /** + * A list of all the waves in this Daily Run. + * + * A completed Daily Run will have 50 waves. + * + * This array automatically sorts by wave number, with blank slots being pushed to the bottom. + * + * @see Wave + */ + waves: Wave[], + /** The Pokemon that the player started with. Daily runs will have 3. @see PokeData */ + starters?: PokeData[] } /** * Imports a string as a DRPD. @@ -228,65 +372,120 @@ export function importDocument(drpd: string): DRPD { return JSON.parse(drpd) as DRPD; } /** - * Exports a Pokemon's data as `PokeData`. - * @param pokemon The Pokemon to store. - * @param encounterRarity The rarity tier of the Pokemon for this biome. - * @returns The Pokemon data. + * Creates a new document in the DRPD format + * @param name (Optional) The name for the file. Defaults to "Untitled Run". + * @param authorName (Optional) The author(s) of the file. Defaults to "Write your name here". + * @returns The fresh DRPD document. */ -export function exportPokemon(pokemon: Pokemon, encounterRarity?: string): PokeData { +export function newDocument(name: string = "Untitled Run", authorName: string | string[] = "Write your name here"): DRPD { return { - id: pokemon.species.speciesId, - name: pokemon.species.getName(), - ability: pokemon.getAbility().name, - isHiddenAbility: pokemon.hasAbility(pokemon.species.abilityHidden), - passiveAbility: pokemon.getPassiveAbility().name, - nature: exportNature(pokemon.nature), - gender: pokemon.gender == 0 ? "Male" : (pokemon.gender == 1 ? "Female" : "Genderless"), - rarity: encounterRarity, - captured: false, - level: pokemon.level, - items: pokemon.getHeldItems().map((item, idx) => exportItem(item)), - ivs: exportIVs(pokemon.ivs) + version: DRPD_Version, + title: name, + label: "", + uuid: randomUUID(), + authors: (Array.isArray(authorName) ? authorName : [authorName]), + date: new Date().getUTCFullYear() + "-" + (new Date().getUTCMonth() + 1 < 10 ? "0" : "") + (new Date().getUTCMonth() + 1) + "-" + (new Date().getUTCDate() < 10 ? "0" : "") + new Date().getUTCDate(), + waves: new Array(50), + starters: new Array(3), } } /** - * Exports a Pokemon's nature as `NatureData`. - * @param nature The nature to store. - * @returns The nature data. + * Prints a DRPD as a string, for saving it to your device. + * @param inData The data to add on to. + * @param indent The indent string (just a bunch of spaces). + * @param drpd The `DRPD` to export. + * @returns `inData`, with all the DRPD's data appended to it. + * + * @see downloadLogByID */ -export function exportNature(nature: Nature): NatureData { - return { - name: getNatureName(nature), - increased: getNatureIncrease(nature), - decreased: getNatureDecrease(nature), +export function printDRPD(inData: string, indent: string, drpd: DRPD): string { + console.log("Printing for sheet?: " + SheetsMode.value) + inData += indent + "{" + inData += "\n" + indent + " \"version\": \"" + drpd.version + "\"" + inData += ",\n" + indent + " \"title\": \"" + drpd.title + "\"" + inData += ",\n" + indent + " \"authors\": [\"" + drpd.authors.join("\", \"") + "\"]" + inData += ",\n" + indent + " \"date\": \"" + drpd.date + "\"" + if (drpd.waves) { + inData += ",\n" + indent + " \"waves\": [\n" + var isFirst = true + for (var i = 0; i < drpd.waves.length; i++) { + if (drpd.waves[i] != undefined && drpd.waves[i] != null) { + if (isFirst) { + isFirst = false; + } else { + inData += ",\n" + } + inData = printWave(inData, indent + " ", drpd.waves[i]) + } + } + } else { + inData += ",\n" + indent + " \"waves\": []" } + inData += ",\n" + indent + " \"starters\": [\n" + var isFirst = true + for (var i = 0; i < drpd.starters.length; i++) { + if (drpd.starters[i] != undefined && drpd.starters[i] != null) { + if (isFirst) { + isFirst = false; + } else { + inData += ",\n" + } + inData = printPoke(inData, indent + " ", drpd.starters[i]) + } + } + inData += "\n" + indent + " ]\n" + indent + "}" + return inData; } +// #endregion + + + + + +// #region Wave /** - * Exports a Held Item as `ItemData`. - * @param item The item to store. - * @returns The item data. + * A Wave is one individual battle in the run. Each group of ten waves has the same biome. */ -export function exportItem(item: PokemonHeldItemModifier): ItemData { - return { - id: item.type.identifier, - name: item.type.name, - quantity: item.getStackCount() - } -} -/** - * Exports a Pokemon's IVs as `IVData`. - * @param ivs The IV array to store. - * @returns The IV data. - */ -export function exportIVs(ivs: integer[]): IVData { - return { - hp: ivs[0], - atk: ivs[1], - def: ivs[2], - spatk: ivs[3], - spdef: ivs[4], - speed: ivs[5] - } +export interface Wave { + /** The wave number. Used to label the wave, detect and delete duplicates, and automatically sort `DRPD.waves[]`. */ + id: integer, + /** Set to `true` if a reload is required to play this wave properly. Setting this value is the PITA I have ever dealt with. */ + reload: boolean, + /** + * The specific type of wave. + * + * `wild`: This is a wild encounter. + * + * `trainer`: This is a trainer battle. + * + * `boss`: This is a boss floor (floors 10, 20, 30, etc). Overrides the two values above. + */ + type: "wild" | "trainer" | "boss", + /** Set to `true` if this is a double battle. */ + double: boolean, + /** The list of actions that the player took during this wave. */ + actions: string[], + /** The item that the player took in the shop. A blank string (`""`) if there is no shop (wave 10, 20, 30, etc.) or the player fled from battle. */ + shop: string, + /** The biome that this battle takes place in. */ + biome: string, + /** If true, the next time an action is logged, all previous actions will be deleted. + * @see Wave.actions + * @see logActions + * @see resetWaveActions + */ + clearActionsFlag: boolean, + /** The trainer that you fight in this floor, if any. + * @see TrainerData + * @see Wave.type + */ + trainer?: TrainerData, + /** The Pokémon that you have to battle against. + * Not included if this is a trainer battle. + * @see PokeData + * @see Wave.type + */ + pokemon?: PokeData[] } /** * Exports the current battle as a `Wave`. @@ -328,322 +527,87 @@ export function exportWave(scene: BattleScene): Wave { return ret; } /** - * Exports the opposing trainer as `TrainerData`. - * @param trainer The Trainer to store. - * @returns The Trainer data. + * Prints a wave as a string, for saving a DRPD to your device. + * @param inData The data to add on to. + * @param indent The indent string (just a bunch of spaces). + * @param wave The `Wave` to export. + * @returns `inData`, with all the wave's data appended to it. + * + * @see printDRPD */ -export function exportTrainer(trainer: Trainer): TrainerData { - if (trainer.config.getTitle(0, trainer.variant) == "Finn") { - return { - id: trainer.config.trainerType, - name: "Finn", - type: "Rival" - } - } - if (trainer.config.getTitle(0, trainer.variant) == "Ivy") { - return { - id: trainer.config.trainerType, - name: "Ivy", - type: "Rival" - } - } - return { - id: trainer.config.trainerType, - name: trainer.name, - type: trainer.config.getTitle(0, trainer.variant) - } -} - -export const byteSize = str => new Blob([str]).size -const filesizes = ["b", "kb", "mb", "gb", "tb"] -export function getSize(str: string) { - var d = byteSize(str) - var unit = 0 - while (d > 1000 && unit < filesizes.length - 1) { - d = Math.round(d/100)/10 - unit++ - } - return d.toString() + filesizes[unit] -} - -export function getDRPD(scene: BattleScene): DRPD { - var drpd: DRPD = JSON.parse(localStorage.getItem(getLogID(scene))) as DRPD; - drpd = updateLog(drpd); - //scene.arenaFlyout.updateFieldText() - return drpd; -} - -/** - * Generates a UI option to save a log to your device. - * @param i The slot number. Corresponds to an index in `logs`. - * @param saves Your session data. Used to label logs if they match one of your save slots. - * @returns A UI option. - */ -export function generateOption(i: integer, saves: any): OptionSelectItem { - var filename: string = (JSON.parse(localStorage.getItem(logs[i][1])) as DRPD).title - var op: OptionSelectItem = { - label: `Export ${filename} (${getSize(printDRPD("", "", JSON.parse(localStorage.getItem(logs[i][1])) as DRPD))})`, - handler: () => { - downloadLogByID(i) - return false; - } - } - for (var j = 0; j < saves.length; j++) { - console.log(saves[j].seed, logs[i][2], saves[j].seed == logs[i][2]) - if (saves[j].seed == logs[i][2]) { - op.label = "[Slot " + (saves[j].slot + 1) + "]" + op.label.substring(6) - } - } - if (logs[i][4] != "") { - op.label = " " + op.label - op.item = logs[i][4] - } - return op; -} -/** - * Generates a UI option to save a log to your device. - * @param i The slot number. Corresponds to an index in `logs`. - * @param saves Your session data. Used to label logs if they match one of your save slots. - * @returns A UI option. - */ -export function generateEditOption(scene: BattleScene, i: integer, saves: any, phase: TitlePhase): OptionSelectItem { - var filename: string = (JSON.parse(localStorage.getItem(logs[i][1])) as DRPD).title - var op: OptionSelectItem = { - label: `Export ${filename} (${getSize(printDRPD("", "", JSON.parse(localStorage.getItem(logs[i][1])) as DRPD))})`, - handler: () => { - rarityslot[1] = logs[i][1] - //scene.phaseQueue[0].end() - scene.ui.setMode(Mode.NAME_LOG, { - autofillfields: [ - (JSON.parse(localStorage.getItem(logs[i][1])) as DRPD).title, - (JSON.parse(localStorage.getItem(logs[i][1])) as DRPD).authors.join(", ") - ], - buttonActions: [ - () => { - console.log("Rename") - scene.ui.playSelect(); - phase.callEnd() - }, - () => { - console.log("Export") - scene.ui.playSelect(); - downloadLogByID(i) - phase.callEnd() - }, - () => { - console.log("Export to Sheets") - scene.ui.playSelect(); - downloadLogByIDToSheet(i) - phase.callEnd() - }, - () => { - console.log("Delete") - scene.ui.playSelect(); - localStorage.removeItem(logs[i][1]) - phase.callEnd() +function printWave(inData: string, indent: string, wave: Wave): string { + inData += indent + "{" + inData += "\n" + indent + " \"id\": " + wave.id + "" + inData += ",\n" + indent + " \"reload\": " + wave.reload + "" + inData += ",\n" + indent + " \"type\": \"" + wave.type + "\"" + inData += ",\n" + indent + " \"double\": " + wave.double + "" + var isFirst = true + if (wave.actions.length > 0) { + if (SheetsMode.value) { + inData += ",\n" + indent + " \"actions\": \"" + var isFirst = true + for (var i = 0; i < wave.actions.length; i++) { + if (wave.actions[i] != undefined) { + if (isFirst) { + isFirst = false; + } else { + inData += "CHAR(10)" + } + inData += wave.actions[i] } - ] - }); - return false; + } + inData += "\"" + } else { + inData += ",\n" + indent + " \"actions\": [" + for (var i = 0; i < wave.actions.length; i++) { + if (wave.actions[i] != undefined) { + if (isFirst) { + isFirst = false; + } else { + inData += "," + } + inData += "\n " + indent + "\"" + wave.actions[i] + "\"" + } + } + if (!isFirst) inData += "\n" + inData += indent + " ]" } + } else { + inData += ",\n" + indent + " \"actions\": [\"[No actions?]\"]" } - for (var j = 0; j < saves.length; j++) { - //console.log(saves[j].seed, logs[i][2], saves[j].seed == logs[i][2]) - if (saves[j].seed == logs[i][2]) { - op.label = "[Slot " + (saves[j].slot + 1) + "]" + op.label.substring(6) + inData += ",\n " + indent + "\"shop\": \"" + wave.shop + "\"" + inData += ",\n " + indent + "\"biome\": \"" + wave.biome + "\"" + if (wave.trainer) { + inData += ",\n " + indent + "\"trainer\": " + inData = printTrainer(inData, indent + " ", wave.trainer) + } + if (wave.pokemon) + if (wave.pokemon.length > 0) { + inData += ",\n " + indent + "\"pokemon\": [\n" + isFirst = true + for (var i = 0; i < wave.pokemon.length; i++) { + if (wave.pokemon[i] != undefined) { + if (isFirst) { + isFirst = false; + } else { + inData += ",\n" + } + inData = printPoke(inData, indent + " ", wave.pokemon[i]) + } + } + if (SheetsMode.value && wave.pokemon.length == 1) { + inData += "," + indent + " \n{" + indent + " \n}" + } + inData += "\n" + indent + " ]" } - } - if (logs[i][4] != "") { - op.label = " " + op.label - op.item = logs[i][4] - } - return op; -} -/** - * Generates an option to create a new log. - * - * Not used. - * @param i The slot number. Corresponds to an index in `logs`. - * @param scene The current scene. Not used. - * @param o The current game phase. Used to return to the previous menu. Not necessary anymore lol - * @returns A UI option. - * - * wow this function sucks - * @deprecated - */ -export function generateAddOption(i: integer, scene: BattleScene, o: TitlePhase) { - var op: OptionSelectItem = { - label: "Generate log " + logs[i][0], - handler: () => { - localStorage.setItem(logs[i][1], JSON.stringify(newDocument())) - o.callEnd(); - return true; - } - } - return op; + inData += "\n" + indent + "}" + return inData; } -/** - * Writes data to a new line. - * @param keyword The identifier key for the log you're writing to - * @param data The string you're writing to the given log - */ -export function toLog(keyword: string, data: string) { - localStorage.setItem(logs[logKeys.indexOf(keyword)][1], localStorage.getItem(logs[logKeys.indexOf(keyword)][1] + "\n" + data)) -} -/** - * Writes data on the same line you were on. - * @param keyword The identifier key for the log you're writing to - * @param data The string you're writing to the given log - */ -export function appendLog(keyword: string, data: string) { - localStorage.setItem(logs[logKeys.indexOf(keyword)][1], localStorage.getItem(logs[logKeys.indexOf(keyword)][1] + data)) -} -/** - * - * Clears all data from a log. - * @param keyword The identifier key for the log you want to reste - */ -export function clearLog(keyword: string) { - localStorage.setItem(logs[logKeys.indexOf(keyword)][1], "---- " + logs[logKeys.indexOf(keyword)][3] + " ----" + logs[logKeys.indexOf(keyword)][5]) -} -export function setFileInfo(title: string, authors: string[]) { - console.log("Setting file " + rarityslot[1] + " to " + title + " / [" + authors.join(", ") + "]") - var fileID = rarityslot[1] as string - var drpd = JSON.parse(localStorage.getItem(fileID)) as DRPD; - drpd.title = title; - for (var i = 0; i < authors.length; i++) { - while (authors[i][0] == " ") { - authors[i] = authors[i].substring(1) - } - while (authors[i][authors[i].length - 1] == " ") { - authors[i] = authors[i].substring(0, authors[i].length - 1) - } - } - for (var i = 0; i < authors.length; i++) { - if (authors[i] == "") { - authors.splice(i, 1) - i--; - } - } - drpd.authors = authors; - localStorage.setItem(fileID, JSON.stringify(drpd)) -} -/** - * Saves a log to your device. - * @param keyword The identifier key for the log you want to save. - */ -export function downloadLog(keyword: string) { - var d = JSON.parse(localStorage.getItem(logs[logKeys.indexOf(keyword)][1])) - const blob = new Blob([ printDRPD("", "", d as DRPD) ], {type: "text/json"}); - const link = document.createElement("a"); - link.href = window.URL.createObjectURL(blob); - var date: string = (d as DRPD).date - var filename: string = date[0] + date[1] + "_" + date[3] + date[4] + "_" + date[6] + date[7] + date[8] + date[9] + "_route.json" - link.download = `${filename}`; - link.click(); - link.remove(); -} -/** - * Saves a log to your device. - * @param i The index of the log you want to save. - */ -export const SheetsMode = new Utils.BooleanHolder(false) -export function downloadLogByID(i: integer) { - console.log(i) - var d = JSON.parse(localStorage.getItem(logs[i][1])) - const blob = new Blob([ printDRPD("", "", d as DRPD) ], {type: "text/json"}); - const link = document.createElement("a"); - link.href = window.URL.createObjectURL(blob); - var date: string = (d as DRPD).date - var filename: string = date[0] + date[1] + "_" + date[3] + date[4] + "_" + date[6] + date[7] + date[8] + date[9] + "_route.json" - link.download = `${filename}`; - link.click(); - link.remove(); -} -export function downloadLogByIDToSheet(i: integer) { - console.log(i) - var d = JSON.parse(localStorage.getItem(logs[i][1])) - SheetsMode.value = true; - const blob = new Blob([ printDRPD("", "", d as DRPD) ], {type: "text/json"}); - SheetsMode.value = false; - const link = document.createElement("a"); - link.href = window.URL.createObjectURL(blob); - var date: string = (d as DRPD).date - var filename: string = date[0] + date[1] + "_" + date[3] + date[4] + "_" + date[6] + date[7] + date[8] + date[9] + "_route.json" - link.download = `${filename}`; - link.click(); - link.remove(); -} -/** - * Calls `logPokemon` once for each opponent or, if it's a trainer battle, logs the trainer's data. - * @param scene The BattleScene. Used to get the enemy team and whether it's a trainer battle or not. - * @param floor The wave index to write to. Defaults to the current wave. - */ -export function logTeam(scene: BattleScene, floor: integer = undefined) { - if (floor == undefined) floor = scene.currentBattle.waveIndex - var team = scene.getEnemyParty() - console.log("Log Enemy Team") - if (team[0].hasTrainer()) { - //var sprite = scene.currentBattle.trainer.config.getSpriteKey() - //var trainerCat = Utils.getEnumKeys(TrainerType)[Utils.getEnumValues(TrainerType).indexOf(scene.currentBattle.trainer.config.trainerType)] - //setRow("e", floor + ",0," + sprite + ",trainer," + trainerCat + ",,,,,,,,,,,,", floor, 0) - } else { - for (var i = 0; i < team.length; i++) { - logPokemon(scene, floor, i, team[i], rarities[i]) - } - if (team.length == 1) { - //setRow("e", ",,,,,,,,,,,,,,,,", floor, 1) - } - } -} -/** - * Logs the actions that the player took. - * - * This includes attacks you perform, items you transfer during the shop, Poke Balls you throw, running from battl, (or attempting to), and switching (including pre-switches). - * @param scene The BattleScene. Used to get the log ID. - * @param floor The wave index to write to. - * @param action The text you want to add to the actions list. - */ -export function logActions(scene: BattleScene, floor: integer, action: string) { - if (localStorage.getItem(getLogID(scene)) == null) localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) - var drpd = getDRPD(scene) - console.log("Log Action", drpd) - var wv: Wave = getWave(drpd, floor, scene) - if (wv.clearActionsFlag) { - console.log("Triggered clearActionsFlag") - wv.clearActionsFlag = false - wv.actions = [] - } - wv.actions.push(action) - console.log(drpd) - localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) -} -/** - * Logs what the player took from the rewards pool and, if applicable, who they used it on. - * @param scene The BattleScene. Used to get the log ID. - * @param floor The wave index to write to. - * @param action The shop action. Left blank if there was no shop this floor or if you ran away. Logged as "Skip taking items" if you didn't take anything for some reason. - */ -export function logShop(scene: BattleScene, floor: integer, action: string) { - if (localStorage.getItem(getLogID(scene)) == null) localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) - var drpd = getDRPD(scene) - console.log("Log Shop Item", drpd) - var wv: Wave = getWave(drpd, floor, scene) - wv.shop = action - console.log(drpd) - localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) -} -export function logCapture(scene: BattleScene, floor: integer, target: EnemyPokemon) { - //if (localStorage.getItem(getLogID(scene)) == null) localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) - var drpd = getDRPD(scene) - console.log("Log Capture", drpd) - var wv: Wave = getWave(drpd, floor, scene) - var pkslot = target.partyslot - wv.pokemon[pkslot].captured = true; - console.log(drpd) - localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) -} + + + + /** * Retrieves a wave from the DRPD. If the wave doesn't exist, it creates a new one. * @param drpd The document to read from. @@ -788,28 +752,571 @@ export function getWave(drpd: DRPD, floor: integer, scene: BattleScene): Wave { } return wv; } +// #endregion + + + + + +// #region Pokémon /** - * Compares a Species to a biome's tier pool. - * @param species The species to search for. - * @param pool The SpeciesPool tier to compare. - * @returns whether or not `species` was found in the `pool`. + * A Pokémon. + * + * This data type is used in `DRPD.starters` to list the player's starting Pokémon, or in `Wave.pokemon` to list the opponent(s) in a wild encounter. */ -function checkForPokeInBiome(species: Species, pool: (Species | SpeciesTree)[]): boolean { - //console.log(species, pool) - for (var i = 0; i < pool.length; i++) { - if (typeof pool[i] === "number") { - //console.log(pool[i] + " == " + species + "? " + (pool[i] == species)) - if (pool[i] == species) return true; - } else { - var k = Object.keys(pool[i]) - //console.log(pool[i], k) - for (var j = 0; j < k.length; j++) { - //console.log(pool[i][k[j]] + " == " + species + "? " + (pool[i][k[j]] == species)) - if (pool[i][k[j]] == species) return true; +export interface PokeData { + /** The party position of this Pokémon, as of the beginning of the battle. */ + id: integer, + /** The name of this Pokémon as it would appear in the party list or in battle. */ + name: string, + /** The Pokémon's primary ability. */ + ability: string, + /** Set to `true` if this Pokémon's ability is its Hidden Ability. + * @see PokeData.ability + */ + isHiddenAbility: boolean, + /** The Pokémon's passive / secondary ability. */ + passiveAbility: string, + /** The Pokémon's nature. Influences its stats. + * @see NatureData + */ + nature: NatureData, + /** The Pokémon's gender. */ + gender: "Male" | "Female" | "Genderless", + /** The Pokémon's encounter rarity within the current biome. */ + rarity: string, + /** Whether or not the Pokémon was captured. */ + captured: boolean, + /** The Pokémon's level. */ + level: integer, + /** The Pokémon's Held Items, if any. + * @see ItemData + */ + items: ItemData[], + /** The Pokémon's IVs. Influences its base stats. + * @see IVData + */ + ivs: IVData, + /** The Pokémon that was used to generate this `PokeData`. Not exported. + * @see Pokemon + */ + source?: Pokemon +} +/** + * Exports a Pokemon's data as `PokeData`. + * @param pokemon The Pokemon to store. + * @param encounterRarity The rarity tier of the Pokemon for this biome. + * @returns The Pokemon data. + */ +export function exportPokemon(pokemon: Pokemon, encounterRarity?: string): PokeData { + return { + id: pokemon.species.speciesId, + name: pokemon.species.getName(), + ability: pokemon.getAbility().name, + isHiddenAbility: pokemon.hasAbility(pokemon.species.abilityHidden), + passiveAbility: pokemon.getPassiveAbility().name, + nature: exportNature(pokemon.nature), + gender: pokemon.gender == 0 ? "Male" : (pokemon.gender == 1 ? "Female" : "Genderless"), + rarity: encounterRarity, + captured: false, + level: pokemon.level, + items: pokemon.getHeldItems().map((item, idx) => exportItem(item)), + ivs: exportIVs(pokemon.ivs) + } +} +/** + * Prints a Pokemon as a string, for saving a DRPD to your device. + * @param inData The data to add on to. + * @param indent The indent string (just a bunch of spaces). + * @param wave The `PokeData` to export. + * @returns `inData`, with all the Pokemon's data appended to it. + * + * @see printDRPD + */ +function printPoke(inData: string, indent: string, pokemon: PokeData) { + inData += indent + "{" + inData += "\n" + indent + " \"id\": " + pokemon.id + inData += ",\n" + indent + " \"name\": \"" + pokemon.name + "\"" + inData += ",\n" + indent + " \"ability\": \"" + pokemon.ability + "\"" + inData += ",\n" + indent + " \"isHiddenAbility\": " + pokemon.isHiddenAbility + inData += ",\n" + indent + " \"passiveAbility\": \"" + pokemon.passiveAbility + "\"" + inData += ",\n" + indent + " \"nature\": \n" + inData = printNature(inData, indent + " ", pokemon.nature) + inData += ",\n" + indent + " \"gender\": \"" + pokemon.gender + "\"" + inData += ",\n" + indent + " \"rarity\": \"" + pokemon.rarity + "\"" + inData += ",\n" + indent + " \"captured\": " + pokemon.captured + inData += ",\n" + indent + " \"level\": " + pokemon.level + if (SheetsMode.value) { + inData += ",\n" + indent + " \"items\": \"" + var isFirst = true + for (var i = 0; i < pokemon.items.length; i++) { + if (pokemon.items[i] != undefined) { + if (isFirst) { + isFirst = false; + } else { + inData += "CHAR(10)" + } + inData += printItemNoNewline(inData, "", pokemon.items[i]) + } } + inData += "\"" + } else { + if (pokemon.items.length > 0) { + inData += ",\n" + indent + " \"items\": [\n" + var isFirst = true + for (var i = 0; i < pokemon.items.length; i++) { + if (pokemon.items[i] != undefined) { + if (isFirst) { + isFirst = false; + } else { + inData += "," + } + inData = printItem(inData, indent + " ", pokemon.items[i]) + } + } + if (!isFirst) inData += "\n" + inData += indent + " ]" + } else { + inData += ",\n" + indent + " \"items\": []" } } - return false; + inData += ",\n" + indent + " \"ivs\": " + inData = printIV(inData, indent + " ", pokemon.ivs) + //inData += ",\n" + indent + " \"rarity\": " + pokemon.rarity + inData += "\n" + indent + "}" + return inData; +} + + + + + +/** + * Calls `logPokemon` once for each opponent or, if it's a trainer battle, logs the trainer's data. + * @param scene The BattleScene. Used to get the enemy team and whether it's a trainer battle or not. + * @param floor The wave index to write to. Defaults to the current wave. + */ +export function logTeam(scene: BattleScene, floor: integer = undefined) { + if (floor == undefined) floor = scene.currentBattle.waveIndex + var team = scene.getEnemyParty() + console.log("Log Enemy Team") + if (team[0].hasTrainer()) { + //var sprite = scene.currentBattle.trainer.config.getSpriteKey() + //var trainerCat = Utils.getEnumKeys(TrainerType)[Utils.getEnumValues(TrainerType).indexOf(scene.currentBattle.trainer.config.trainerType)] + //setRow("e", floor + ",0," + sprite + ",trainer," + trainerCat + ",,,,,,,,,,,,", floor, 0) + } else { + for (var i = 0; i < team.length; i++) { + logPokemon(scene, floor, i, team[i], rarities[i]) + } + if (team.length == 1) { + //setRow("e", ",,,,,,,,,,,,,,,,", floor, 1) + } + } +} +// #endregion + + + + + +// #region Nature +export interface NatureData { + /** The display name of this nature. */ + name: string, + /** The stat that gets a 10% increase from this nature, if any. */ + increased: "" | "atk" | "def" | "spatk" | "spdef" | "spe", + /** The stat that gets a 10% decrease from this nature, if any. */ + decreased: "" | "atk" | "def" | "spatk" | "spdef" | "spe" +} +/** + * Exports a Pokemon's nature as `NatureData`. + * @param nature The nature to store. + * @returns The nature data. + */ +export function exportNature(nature: Nature): NatureData { + return { + name: getNatureName(nature), + increased: getNatureIncrease(nature), + decreased: getNatureDecrease(nature), + } +} +/** + * Prints a Nature as a string, for saving a DRPD to your device. + * @param inData The data to add on to. + * @param indent The indent string (just a bunch of spaces). + * @param wave The `NatureData` to export. + * @returns `inData`, with all the nature data appended to it. + * + * @see printDRPD + */ +function printNature(inData: string, indent: string, nature: NatureData) { + inData += indent + "{" + inData += "\n" + indent + " \"name\": \"" + nature.name + "\"" + inData += ",\n" + indent + " \"increased\": \"" + nature.increased + "\"" + inData += ",\n" + indent + " \"decreased\": \"" + nature.decreased + "\"" + inData += "\n" + indent + "}" + return inData; +} +// #endregion + + + + + +// #region IVs +export interface IVData { + /** Influences a Pokémon's maximum health. */ + hp: integer, + /** Influences a Pokémon's physical strength. */ + atk: integer, + /** Influences a Pokémon's resistance to physical attacks. */ + def: integer, + /** Influences the power of a Pokémon's ranged attacks */ + spatk: integer, + /** Influences a Pokémon's resistance to ranged attacks. */ + spdef: integer, + /** Influences a Pokémon's action speed. */ + speed: integer +} +/** + * Exports a Pokémon's IVs as `IVData`. + * @param ivs The IV array to store. + * @returns The IV data. + */ +export function exportIVs(ivs: integer[]): IVData { + return { + hp: ivs[0], + atk: ivs[1], + def: ivs[2], + spatk: ivs[3], + spdef: ivs[4], + speed: ivs[5] + } +} +/** + * Prints a Pokemon's IV data as a string, for saving a DRPD to your device. + * @param inData The data to add on to. + * @param indent The indent string (just a bunch of spaces). + * @param wave The `IVData` to export. + * @returns `inData`, with the IV data appended to it. + * + * @see printDRPD + */ +function printIV(inData: string, indent: string, iv: IVData) { + inData += "{" + inData += "\n" + indent + " \"hp\": " + iv.hp + inData += ",\n" + indent + " \"atk\": " + iv.atk + inData += ",\n" + indent + " \"def\": " + iv.def + inData += ",\n" + indent + " \"spatk\": " + iv.spatk + inData += ",\n" + indent + " \"spdef\": " + iv.spdef + inData += ",\n" + indent + " \"spe\": " + iv.speed + inData += "\n" + indent + "}" + return inData; +} +// #endregion + + + + + +// #region Trainer +export interface TrainerData { + /** The trainer type's position in the Trainers enum. + * @see Trainer + */ + id: integer, + /** The Trainer's ingame name. */ + name: string, + /** The Trainer's ingame title. */ + type: string, +} +/** + * Exports the opposing trainer as `TrainerData`. + * @param trainer The Trainer to store. + * @returns The Trainer data. + */ +export function exportTrainer(trainer: Trainer): TrainerData { + if (trainer.config.getTitle(0, trainer.variant) == "Finn") { + return { + id: trainer.config.trainerType, + name: "Finn", + type: "Rival" + } + } + if (trainer.config.getTitle(0, trainer.variant) == "Ivy") { + return { + id: trainer.config.trainerType, + name: "Ivy", + type: "Rival" + } + } + return { + id: trainer.config.trainerType, + name: trainer.name, + type: trainer.config.getTitle(0, trainer.variant) + } +} +/** + * Prints a Trainer as a string, for saving a DRPD to your device. + * @param inData The data to add on to. + * @param indent The indent string (just a bunch of spaces). + * @param wave The `TrainerData` to export. + * @returns `inData`, with all the Trainer's data appended to it. + * + * @see printDRPD + */ +function printTrainer(inData: string, indent: string, trainer: TrainerData) { + inData += "{" + inData += "\n" + indent + " \"id\": \"" + trainer.id + "\"" + inData += ",\n" + indent + " \"name\": \"" + trainer.name + "\"" + inData += ",\n" + indent + " \"type\": \"" + trainer.type + "\"" + inData += "\n" + indent + "}" + return inData; +} +// #endregion + + + + + +// #region Item +/** An item held by a Pokémon. Quantities and ownership are recorded at the start of the battle, and do not reflect items being used up or stolen. */ +export interface ItemData { + /** A type:key pair identifying the specific item. + * + * Example: `FormChange:TOXIC_PLATE` + */ + id: string, + /** The item's ingame name. */ + name: string, + /** This item's stack size. */ + quantity: integer, +} +/** + * Exports a Held Item as `ItemData`. + * @param item The item to store. + * @returns The item data. + */ +export function exportItem(item: PokemonHeldItemModifier): ItemData { + return { + id: item.type.identifier, + name: item.type.name, + quantity: item.getStackCount() + } +} +/** + * Prints an item as a string, for saving a DRPD to your device. + * @param inData The data to add on to. + * @param indent The indent string (just a bunch of spaces). + * @param wave The `ItemData` to export. + * @returns `inData`, with all the Item's data appended to it. + * + * @see printDRPD + */ +function printItem(inData: string, indent: string, item: ItemData) { + inData += indent + "{" + inData += "\n" + indent + " \"id\": \"" + item.id + "\"" + inData += ",\n" + indent + " \"name\": \"" + item.name + "\"" + inData += ",\n" + indent + " \"quantity\": " + item.quantity + inData += "\n" + indent + "}" + return inData; +} +/** + * Prints an item as a string, for saving a DRPD to your device. + * @param inData The data to add on to. + * @param indent The indent string (just a bunch of spaces). + * @param wave The `ItemData` to export. + * @returns `inData`, with all the Item's data appended to it. + * + * @see `downloadLogByIDToSheet` + */ +function printItemNoNewline(inData: string, indent: string, item: ItemData) { + inData = "{\\\"id\\\": \\\"" + item.id + "\\\", \\\"name\\\": \\\"" + item.name + "\\\", \\\"quantity\\\": " + item.quantity + "}" + return inData; +} +// #endregion + + + + + +//#region Manage Logs menu + +/** + * Sets the name, author, and [todo] label for a file. + * @param title The display name of the file. + * @param authors The author(s) of the file. + * @todo Add label field. + */ +export function setFileInfo(title: string, authors: string[]) { + console.log("Setting file " + rarityslot[1] + " to " + title + " / [" + authors.join(", ") + "]") + var fileID = rarityslot[1] as string + var drpd = JSON.parse(localStorage.getItem(fileID)) as DRPD; + drpd.title = title; + for (var i = 0; i < authors.length; i++) { + while (authors[i][0] == " ") { + authors[i] = authors[i].substring(1) + } + while (authors[i][authors[i].length - 1] == " ") { + authors[i] = authors[i].substring(0, authors[i].length - 1) + } + } + for (var i = 0; i < authors.length; i++) { + if (authors[i] == "") { + authors.splice(i, 1) + i--; + } + } + drpd.authors = authors; + localStorage.setItem(fileID, JSON.stringify(drpd)) +} + +/** + * Generates a UI option to save a log to your device. + * @param i The slot number. Corresponds to an index in `logs`. + * @param saves Your session data. Used to label logs if they match one of your save slots. + * @returns A UI option. + */ +export function generateOption(i: integer, saves: any): OptionSelectItem { + var filename: string = (JSON.parse(localStorage.getItem(logs[i][1])) as DRPD).title + var op: OptionSelectItem = { + label: `Export ${filename} (${getSize(printDRPD("", "", JSON.parse(localStorage.getItem(logs[i][1])) as DRPD))})`, + handler: () => { + downloadLogByID(i) + return false; + } + } + for (var j = 0; j < saves.length; j++) { + console.log(saves[j].seed, logs[i][2], saves[j].seed == logs[i][2]) + if (saves[j].seed == logs[i][2]) { + op.label = "[Slot " + (saves[j].slot + 1) + "]" + op.label.substring(6) + } + } + if (logs[i][4] != "") { + op.label = " " + op.label + op.item = logs[i][4] + } + return op; +} +/** + * Generates a UI option to save a log to your device. + * @param i The slot number. Corresponds to an index in `logs`. + * @param saves Your session data. Used to label logs if they match one of your save slots. + * @returns A UI option. + */ +export function generateEditOption(scene: BattleScene, i: integer, saves: any, phase: TitlePhase): OptionSelectItem { + var filename: string = (JSON.parse(localStorage.getItem(logs[i][1])) as DRPD).title + var op: OptionSelectItem = { + label: `Export ${filename} (${getSize(printDRPD("", "", JSON.parse(localStorage.getItem(logs[i][1])) as DRPD))})`, + handler: () => { + rarityslot[1] = logs[i][1] + //scene.phaseQueue[0].end() + scene.ui.setMode(Mode.NAME_LOG, { + autofillfields: [ + (JSON.parse(localStorage.getItem(logs[i][1])) as DRPD).title, + (JSON.parse(localStorage.getItem(logs[i][1])) as DRPD).authors.join(", ") + ], + buttonActions: [ + () => { + console.log("Rename") + scene.ui.playSelect(); + phase.callEnd() + }, + () => { + console.log("Export") + scene.ui.playSelect(); + downloadLogByID(i) + phase.callEnd() + }, + () => { + console.log("Export to Sheets") + scene.ui.playSelect(); + downloadLogByIDToSheet(i) + phase.callEnd() + }, + () => { + console.log("Delete") + scene.ui.playSelect(); + localStorage.removeItem(logs[i][1]) + phase.callEnd() + } + ] + }); + return false; + } + } + for (var j = 0; j < saves.length; j++) { + //console.log(saves[j].seed, logs[i][2], saves[j].seed == logs[i][2]) + if (saves[j].seed == logs[i][2]) { + op.label = "[Slot " + (saves[j].slot + 1) + "]" + op.label.substring(6) + } + } + if (logs[i][4] != "") { + op.label = " " + op.label + op.item = logs[i][4] + } + return op; +} + +//#endregion + + + + + +//#region Logging Events +/** + * Logs the actions that the player took. + * + * This includes attacks you perform, items you transfer during the shop, Poke Balls you throw, running from battl, (or attempting to), and switching (including pre-switches). + * @param scene The BattleScene. Used to get the log ID. + * @param floor The wave index to write to. + * @param action The text you want to add to the actions list. + * + * @see resetWaveActions + */ +export function logActions(scene: BattleScene, floor: integer, action: string) { + if (localStorage.getItem(getLogID(scene)) == null) localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) + var drpd = getDRPD(scene) + console.log("Log Action", drpd) + var wv: Wave = getWave(drpd, floor, scene) + if (wv.double == undefined) + wv.double = false + if (wv.clearActionsFlag) { + console.log("Triggered clearActionsFlag") + wv.clearActionsFlag = false + wv.actions = [] + } + wv.actions.push(action) + console.log(drpd) + localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) +} +export function logCapture(scene: BattleScene, floor: integer, target: EnemyPokemon) { + //if (localStorage.getItem(getLogID(scene)) == null) localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) + var drpd = getDRPD(scene) + console.log("Log Capture", drpd) + var wv: Wave = getWave(drpd, floor, scene) + var pkslot = target.partyslot + wv.pokemon[pkslot].captured = true; + console.log(drpd) + localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) +} +/** + * Logs the player's current party. + * + * Called on Floor 1 to store the starters list. + * @param scene The BattleScene. Used to get the log ID and the player's party. + */ +export function logPlayerTeam(scene: BattleScene) { + if (localStorage.getItem(getLogID(scene)) == null) localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) + var drpd = getDRPD(scene) + console.log("Log Player Starters", drpd) + var P = scene.getParty() + for (var i = 0; i < P.length; i++) { + drpd.starters[i] = exportPokemon(P[i]) + } + console.log(drpd) + localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) } /** * Logs a wild Pokemon to a wave's data. @@ -894,22 +1401,18 @@ export function logPokemon(scene: BattleScene, floor: integer = undefined, slot: localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) } /** - * Clears the action list for a wave. - * @param scene The BattleScene. Used to get the log ID and trainer data. - * @param floor The wave index to write to. Defaults to the current floor. + * Logs what the player took from the rewards pool and, if applicable, who they used it on. + * @param scene The BattleScene. Used to get the log ID. + * @param floor The wave index to write to. + * @param action The shop action. Left blank if there was no shop this floor or if you ran away. Logged as "Skip taking items" if you didn't take anything for some reason. */ -export function resetWaveActions(scene: BattleScene, floor: integer = undefined, softflag: boolean) { - if (floor == undefined) floor = scene.currentBattle.waveIndex +export function logShop(scene: BattleScene, floor: integer, action: string) { if (localStorage.getItem(getLogID(scene)) == null) localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) var drpd = getDRPD(scene) - console.log("Clear Actions", drpd) + console.log("Log Shop Item", drpd) var wv: Wave = getWave(drpd, floor, scene) - if (softflag) { - wv.clearActionsFlag = true; - } else { - wv.actions = [] - } - console.log(drpd, wv) + wv.shop = action + console.log(drpd) localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) } /** @@ -930,23 +1433,141 @@ export function logTrainer(scene: BattleScene, floor: integer = undefined) { console.log(drpd) localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) } -/** - * Logs the player's current party. - * - * Called on Floor 1 to store the starters list. - * @param scene The BattleScene. Used to get the log ID and the player's party. - */ -export function logPlayerTeam(scene: BattleScene) { - if (localStorage.getItem(getLogID(scene)) == null) localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) + + + + + +export function flagReset(scene: BattleScene, floor: integer = undefined) { + if (floor == undefined) + floor = scene.currentBattle.waveIndex; + if (localStorage.getItem(getLogID(scene)) == null) + localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) var drpd = getDRPD(scene) - console.log("Log Player Starters", drpd) - var P = scene.getParty() - for (var i = 0; i < P.length; i++) { - drpd.starters[i] = exportPokemon(P[i]) - } + var wv = getWave(drpd, floor, scene) + wv.reload = true; console.log(drpd) localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) } +export function flagResetIfExists(scene: BattleScene, floor: integer = undefined) { + if (floor == undefined) + floor = scene.currentBattle.waveIndex; + if (localStorage.getItem(getLogID(scene)) == null) + localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) + var drpd = getDRPD(scene) + var waveExists = false + for (var i = 0; i < drpd.waves.length; i++) { + if (drpd.waves[i] != undefined) { + if (drpd.waves[i].id == floor) { + waveExists = true; + } + } + } + if (!waveExists) return; + var wv = getWave(drpd, floor, scene) + wv.reload = true; + console.log(drpd) + localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) +} + + + +/** + * Clears the action list for a wave. + * @param scene The BattleScene. Used to get the log ID and trainer data. + * @param floor The wave index to write to. Defaults to the current floor. + * + * @see logActions + */ +export function resetWaveActions(scene: BattleScene, floor: integer = undefined, softflag: boolean) { + if (floor == undefined) floor = scene.currentBattle.waveIndex + if (localStorage.getItem(getLogID(scene)) == null) localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) + var drpd = getDRPD(scene) + console.log("Clear Actions", drpd) + var wv: Wave = getWave(drpd, floor, scene) + if (softflag) { + wv.clearActionsFlag = true; + } else { + wv.actions = [] + } + console.log(drpd, wv) + localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) +} +//#endregion + + + + + +//#region Deprecated + +/** + * Writes data to a new line. + * @param keyword The identifier key for the log you're writing to + * @param data The string you're writing to the given log + * @deprecated + */ +export function toLog(keyword: string, data: string) { + localStorage.setItem(logs[logKeys.indexOf(keyword)][1], localStorage.getItem(logs[logKeys.indexOf(keyword)][1] + "\n" + data)) +} +/** + * Writes data on the same line you were on. + * @param keyword The identifier key for the log you're writing to + * @param data The string you're writing to the given log + * @deprecated + */ +export function appendLog(keyword: string, data: string) { + localStorage.setItem(logs[logKeys.indexOf(keyword)][1], localStorage.getItem(logs[logKeys.indexOf(keyword)][1] + data)) +} +/** + * Saves a log to your device. + * @param keyword The identifier key for the log you want to save. + * @deprecated + */ +export function downloadLog(keyword: string) { + var d = JSON.parse(localStorage.getItem(logs[logKeys.indexOf(keyword)][1])) + const blob = new Blob([ printDRPD("", "", d as DRPD) ], {type: "text/json"}); + const link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + var date: string = (d as DRPD).date + var filename: string = date[0] + date[1] + "_" + date[3] + date[4] + "_" + date[6] + date[7] + date[8] + date[9] + "_route.json" + link.download = `${filename}`; + link.click(); + link.remove(); +} +/** + * + * Clears all data from a log. + * @param keyword The identifier key for the log you want to reste + * @deprecated + */ +export function clearLog(keyword: string) { + localStorage.setItem(logs[logKeys.indexOf(keyword)][1], "---- " + logs[logKeys.indexOf(keyword)][3] + " ----" + logs[logKeys.indexOf(keyword)][5]) +} + +/** + * Generates an option to create a new log. + * + * Not used. + * @param i The slot number. Corresponds to an index in `logs`. + * @param scene The current scene. Not used. + * @param o The current game phase. Used to return to the previous menu. Not necessary anymore lol + * @returns A UI option. + * + * wow this function sucks + * @deprecated + */ +export function generateAddOption(i: integer, scene: BattleScene, o: TitlePhase) { + var op: OptionSelectItem = { + label: "Generate log " + logs[i][0], + handler: () => { + localStorage.setItem(logs[i][1], JSON.stringify(newDocument())) + o.callEnd(); + return true; + } + } + return op; +} /** * A sort function, used to sort csv columns. * @@ -1042,317 +1663,4 @@ export function setRow(keyword: string, newLine: string, floor: integer, slot: i } localStorage.setItem(logs[logKeys.indexOf(keyword)][1], data.slice(0, idx).join("\n") + "\n" + newLine + (data.slice(idx).length == 0 ? "" : "\n") + data.slice(idx).join("\n")); } -export function flagReset(scene: BattleScene, floor: integer = undefined) { - if (floor == undefined) - floor = scene.currentBattle.waveIndex; - if (localStorage.getItem(getLogID(scene)) == null) - localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) - var drpd = getDRPD(scene) - var wv = getWave(drpd, floor, scene) - wv.reload = true; - console.log(drpd) - localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) -} -export function flagResetIfExists(scene: BattleScene, floor: integer = undefined) { - if (floor == undefined) - floor = scene.currentBattle.waveIndex; - if (localStorage.getItem(getLogID(scene)) == null) - localStorage.setItem(getLogID(scene), JSON.stringify(newDocument(getMode(scene) + " Run"))) - var drpd = getDRPD(scene) - var waveExists = false - for (var i = 0; i < drpd.waves.length; i++) { - if (drpd.waves[i] != undefined) { - if (drpd.waves[i].id == floor) { - waveExists = true; - } - } - } - if (!waveExists) return; - var wv = getWave(drpd, floor, scene) - wv.reload = true; - console.log(drpd) - localStorage.setItem(getLogID(scene), JSON.stringify(drpd)) -} -/** - * Prints a DRPD as a string, for saving it to your device. - * @param inData The data to add on to. - * @param indent The indent string (just a bunch of spaces). - * @param drpd The `DRPD` to export. - * @returns `inData`, with all the DRPD's data appended to it. - * - * @see printWave - */ -export function printDRPD(inData: string, indent: string, drpd: DRPD): string { - console.log("Printing for sheet?: " + SheetsMode.value) - inData += indent + "{" - inData += "\n" + indent + " \"version\": \"" + drpd.version + "\"" - inData += ",\n" + indent + " \"title\": \"" + drpd.title + "\"" - inData += ",\n" + indent + " \"authors\": [\"" + drpd.authors.join("\", \"") + "\"]" - inData += ",\n" + indent + " \"date\": \"" + drpd.date + "\"" - if (drpd.waves) { - inData += ",\n" + indent + " \"waves\": [\n" - var isFirst = true - for (var i = 0; i < drpd.waves.length; i++) { - if (drpd.waves[i] != undefined && drpd.waves[i] != null) { - if (isFirst) { - isFirst = false; - } else { - inData += ",\n" - } - inData = printWave(inData, indent + " ", drpd.waves[i]) - } - } - } else { - inData += ",\n" + indent + " \"waves\": []" - } - inData += "\n" + indent + " ]\n" + indent + "}" - return inData; -} -/** - * Prints a wave as a string, for saving a DRPD to your device. - * @param inData The data to add on to. - * @param indent The indent string (just a bunch of spaces). - * @param wave The `Wave` to export. - * @returns `inData`, with all the wave's data appended to it. - * - * @see printDRPD - */ -function printWave(inData: string, indent: string, wave: Wave): string { - inData += indent + "{" - inData += "\n" + indent + " \"id\": " + wave.id + "" - inData += ",\n" + indent + " \"reload\": " + wave.reload + "" - inData += ",\n" + indent + " \"type\": \"" + wave.type + "\"" - inData += ",\n" + indent + " \"double\": " + wave.double + "" - var isFirst = true - if (wave.actions.length > 0) { - if (SheetsMode.value) { - inData += ",\n" + indent + " \"actions\": \"" - var isFirst = true - for (var i = 0; i < wave.actions.length; i++) { - if (wave.actions[i] != undefined) { - if (isFirst) { - isFirst = false; - } else { - inData += "CHAR(10)" - } - inData += wave.actions[i] - } - } - inData += "\"" - } else { - inData += ",\n" + indent + " \"actions\": [" - for (var i = 0; i < wave.actions.length; i++) { - if (wave.actions[i] != undefined) { - if (isFirst) { - isFirst = false; - } else { - inData += "," - } - inData += "\n " + indent + "\"" + wave.actions[i] + "\"" - } - } - if (!isFirst) inData += "\n" - inData += indent + " ]" - } - } else { - inData += ",\n" + indent + " \"actions\": [\"[No actions?]\"]" - } - inData += ",\n " + indent + "\"shop\": \"" + wave.shop + "\"" - inData += ",\n " + indent + "\"biome\": \"" + wave.biome + "\"" - if (wave.trainer) { - inData += ",\n " + indent + "\"trainer\": " - inData = printTrainer(inData, indent + " ", wave.trainer) - } - if (wave.pokemon) - if (wave.pokemon.length > 0) { - inData += ",\n " + indent + "\"pokemon\": [\n" - isFirst = true - for (var i = 0; i < wave.pokemon.length; i++) { - if (wave.pokemon[i] != undefined) { - if (isFirst) { - isFirst = false; - } else { - inData += ",\n" - } - inData = printPoke(inData, indent + " ", wave.pokemon[i]) - } - } - if (SheetsMode.value && wave.pokemon.length == 1) { - inData += "," + indent + " \n{" + indent + " \n}" - } - inData += "\n" + indent + " ]" - } - inData += "\n" + indent + "}" - return inData; -} -/** - * Prints a Pokemon as a string, for saving a DRPD to your device. - * @param inData The data to add on to. - * @param indent The indent string (just a bunch of spaces). - * @param wave The `PokeData` to export. - * @returns `inData`, with all the Pokemon's data appended to it. - * - * @see printDRPD - */ -function printPoke(inData: string, indent: string, pokemon: PokeData) { - inData += indent + "{" - inData += "\n" + indent + " \"id\": " + pokemon.id - inData += ",\n" + indent + " \"name\": \"" + pokemon.name + "\"" - inData += ",\n" + indent + " \"ability\": \"" + pokemon.ability + "\"" - inData += ",\n" + indent + " \"isHiddenAbility\": " + pokemon.isHiddenAbility - inData += ",\n" + indent + " \"passiveAbility\": \"" + pokemon.passiveAbility + "\"" - inData += ",\n" + indent + " \"nature\": \n" - inData = printNature(inData, indent + " ", pokemon.nature) - inData += ",\n" + indent + " \"gender\": \"" + pokemon.gender + "\"" - inData += ",\n" + indent + " \"rarity\": \"" + pokemon.rarity + "\"" - inData += ",\n" + indent + " \"captured\": " + pokemon.captured - inData += ",\n" + indent + " \"level\": " + pokemon.level - if (SheetsMode.value) { - inData += ",\n" + indent + " \"items\": \"" - var isFirst = true - for (var i = 0; i < pokemon.items.length; i++) { - if (pokemon.items[i] != undefined) { - if (isFirst) { - isFirst = false; - } else { - inData += "CHAR(10)" - } - inData += printItemNoNewline(inData, "", pokemon.items[i]) - } - } - inData += "\"" - } else { - if (pokemon.items.length > 0) { - inData += ",\n" + indent + " \"items\": [\n" - var isFirst = true - for (var i = 0; i < pokemon.items.length; i++) { - if (pokemon.items[i] != undefined) { - if (isFirst) { - isFirst = false; - } else { - inData += "," - } - inData = printItem(inData, indent + " ", pokemon.items[i]) - } - } - if (!isFirst) inData += "\n" - inData += indent + " ]" - } else { - inData += ",\n" + indent + " \"items\": []" - } - } - inData += ",\n" + indent + " \"ivs\": " - inData = printIV(inData, indent + " ", pokemon.ivs) - //inData += ",\n" + indent + " \"rarity\": " + pokemon.rarity - inData += "\n" + indent + "}" - return inData; -} -/** - * Prints a Nature as a string, for saving a DRPD to your device. - * @param inData The data to add on to. - * @param indent The indent string (just a bunch of spaces). - * @param wave The `NatureData` to export. - * @returns `inData`, with all the nature data appended to it. - * - * @see printDRPD - */ -function printNature(inData: string, indent: string, nature: NatureData) { - inData += indent + "{" - inData += "\n" + indent + " \"name\": \"" + nature.name + "\"" - inData += ",\n" + indent + " \"increased\": \"" + nature.increased + "\"" - inData += ",\n" + indent + " \"decreased\": \"" + nature.decreased + "\"" - inData += "\n" + indent + "}" - return inData; -} -/** - * Prints a Pokemon's IV data as a string, for saving a DRPD to your device. - * @param inData The data to add on to. - * @param indent The indent string (just a bunch of spaces). - * @param wave The `IVData` to export. - * @returns `inData`, with the IV data appended to it. - * - * @see printDRPD - */ -function printIV(inData: string, indent: string, iv: IVData) { - inData += "{" - inData += "\n" + indent + " \"hp\": " + iv.hp - inData += ",\n" + indent + " \"atk\": " + iv.atk - inData += ",\n" + indent + " \"def\": " + iv.def - inData += ",\n" + indent + " \"spatk\": " + iv.spatk - inData += ",\n" + indent + " \"spdef\": " + iv.spdef - inData += ",\n" + indent + " \"spe\": " + iv.speed - inData += "\n" + indent + "}" - return inData; -} -/** - * Prints a Trainer as a string, for saving a DRPD to your device. - * @param inData The data to add on to. - * @param indent The indent string (just a bunch of spaces). - * @param wave The `TrainerData` to export. - * @returns `inData`, with all the Trainer's data appended to it. - * - * @see printDRPD - */ -function printTrainer(inData: string, indent: string, trainer: TrainerData) { - inData += "{" - inData += "\n" + indent + " \"id\": \"" + trainer.id + "\"" - inData += ",\n" + indent + " \"name\": \"" + trainer.name + "\"" - inData += ",\n" + indent + " \"type\": \"" + trainer.type + "\"" - inData += "\n" + indent + "}" - return inData; -} -/** - * Prints an item as a string, for saving a DRPD to your device. - * @param inData The data to add on to. - * @param indent The indent string (just a bunch of spaces). - * @param wave The `ItemData` to export. - * @returns `inData`, with all the Item's data appended to it. - * - * @see printDRPD - */ -function printItem(inData: string, indent: string, item: ItemData) { - inData += indent + "{" - inData += "\n" + indent + " \"id\": \"" + item.id + "\"" - inData += ",\n" + indent + " \"name\": \"" + item.name + "\"" - inData += ",\n" + indent + " \"quantity\": " + item.quantity - inData += "\n" + indent + "}" - return inData; -} -/** - * Prints an item as a string, for saving a DRPD to your device. - * @param inData The data to add on to. - * @param indent The indent string (just a bunch of spaces). - * @param wave The `ItemData` to export. - * @returns `inData`, with all the Item's data appended to it. - * - * @see printDRPD - */ -function printItemNoNewline(inData: string, indent: string, item: ItemData) { - inData = "{\\\"id\\\": \\\"" + item.id + "\\\", \\\"name\\\": \\\"" + item.name + "\\\", \\\"quantity\\\": " + item.quantity + "}" - return inData; -} - - -function updateLog(drpd: DRPD): DRPD { - if (drpd.version == "1.0.0") { - drpd.version = "1.0.0a" - console.log("Updated to 1.0.0a - changed item IDs to strings") - for (var i = 0; i < drpd.waves.length; i++) { - if (drpd.waves[i] != undefined) { - if (drpd.waves[i].pokemon != undefined) { - for (var j = 0; j < drpd.waves[i].pokemon.length; j++) { - for (var k = 0; k < drpd.waves[i].pokemon[j].items.length; k++) { - drpd.waves[i].pokemon[j].items[k].id = drpd.waves[i].pokemon[j].items[k].id.toString() - } - } - } - } - } - for (var j = 0; j < drpd.starters.length; j++) { - for (var k = 0; k < drpd.starters[j].items.length; k++) { - drpd.starters[j].items[k].id = drpd.starters[j].items[k].id.toString() - } - } - } // 1.0.0 → 1.0.0a - return drpd; -} \ No newline at end of file +//#endregion \ No newline at end of file