"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var dex_exports = {}; __export(dex_exports, { Dex: () => Dex, ModdedDex: () => ModdedDex, default: () => dex_default, toID: () => toID }); module.exports = __toCommonJS(dex_exports); var fs = __toESM(require("fs")); var path = __toESM(require("path")); var Data = __toESM(require("./dex-data")); var import_dex_conditions = require("./dex-conditions"); var import_dex_moves = require("./dex-moves"); var import_dex_items = require("./dex-items"); var import_dex_abilities = require("./dex-abilities"); var import_dex_species = require("./dex-species"); var import_dex_formats = require("./dex-formats"); var import_utils = require("../lib/utils"); /** * Dex * Pokemon Showdown - http://pokemonshowdown.com/ * * Handles getting data about pokemon, items, etc. Also contains some useful * helper functions for using dex data. * * By default, nothing is loaded until you call Dex.mod(mod) or * Dex.forFormat(format). * * You may choose to preload some things: * - Dex.includeMods() ~10ms * This will preload `Dex.dexes`, giving you a list of possible mods. * - Dex.includeFormats() ~30ms * As above, but will also preload `Dex.formats.all()`. * - Dex.includeData() ~500ms * As above, but will also preload all of Dex.data for Gen 8, so * functions like `Dex.species.get`, etc will be instantly usable. * - Dex.includeModData() ~1500ms * As above, but will also preload `Dex.dexes[...].data` for all mods. * * Note that preloading is never necessary. All the data will be * automatically preloaded when needed, preloading will just spend time * now so you don't need to spend time later. * * @license MIT */ const BASE_MOD = "gen9"; const DATA_DIR = path.resolve(__dirname, "../data"); const MODS_DIR = path.resolve(DATA_DIR, "./mods"); const dexes = /* @__PURE__ */ Object.create(null); const DATA_TYPES = [ "Abilities", "Rulesets", "FormatsData", "Items", "Learnsets", "Moves", "Natures", "Pokedex", "Scripts", "Conditions", "TypeChart", "PokemonGoData" ]; const DATA_FILES = { Abilities: "abilities", Aliases: "aliases", Rulesets: "rulesets", FormatsData: "formats-data", Items: "items", Learnsets: "learnsets", Moves: "moves", Natures: "natures", Pokedex: "pokedex", PokemonGoData: "pokemongo", Scripts: "scripts", Conditions: "conditions", TypeChart: "typechart" }; const toID = Data.toID; class ModdedDex { constructor(mod = "base") { this.Data = Data; this.Condition = import_dex_conditions.Condition; this.Ability = import_dex_abilities.Ability; this.Item = import_dex_items.Item; this.Move = import_dex_moves.DataMove; this.Species = import_dex_species.Species; this.Format = import_dex_formats.Format; this.ModdedDex = ModdedDex; this.name = "[ModdedDex]"; this.toID = Data.toID; this.gen = 0; this.parentMod = ""; this.modsLoaded = false; this.deepClone = import_utils.Utils.deepClone; this.deepFreeze = import_utils.Utils.deepFreeze; this.Multiset = import_utils.Utils.Multiset; this.isBase = mod === "base"; this.currentMod = mod; this.dataDir = this.isBase ? DATA_DIR : MODS_DIR + "/" + this.currentMod; this.dataCache = null; this.textCache = null; this.formats = new import_dex_formats.DexFormats(this); this.abilities = new import_dex_abilities.DexAbilities(this); this.items = new import_dex_items.DexItems(this); this.moves = new import_dex_moves.DexMoves(this); this.species = new import_dex_species.DexSpecies(this); this.conditions = new import_dex_conditions.DexConditions(this); this.natures = new Data.DexNatures(this); this.types = new Data.DexTypes(this); this.stats = new Data.DexStats(this); } get data() { return this.loadData(); } get dexes() { this.includeMods(); return dexes; } mod(mod) { if (!dexes["base"].modsLoaded) dexes["base"].includeMods(); return dexes[mod || "base"].includeData(); } forGen(gen) { if (!gen) return this; return this.mod(`gen${gen}`); } forFormat(format) { if (!this.modsLoaded) this.includeMods(); const mod = this.formats.get(format).mod; return dexes[mod || BASE_MOD].includeData(); } modData(dataType, id) { if (this.isBase) return this.data[dataType][id]; if (this.data[dataType][id] !== dexes[this.parentMod].data[dataType][id]) return this.data[dataType][id]; return this.data[dataType][id] = import_utils.Utils.deepClone(this.data[dataType][id]); } effectToString() { return this.name; } /** * Sanitizes a username or Pokemon nickname * * Returns the passed name, sanitized for safe use as a name in the PS * protocol. * * Such a string must uphold these guarantees: * - must not contain any ASCII whitespace character other than a space * - must not start or end with a space character * - must not contain any of: | , [ ] * - must not be the empty string * - must not contain Unicode RTL control characters * * If no such string can be found, returns the empty string. Calling * functions are expected to check for that condition and deal with it * accordingly. * * getName also enforces that there are not multiple consecutive space * characters in the name, although this is not strictly necessary for * safety. */ getName(name) { if (typeof name !== "string" && typeof name !== "number") return ""; name = `${name}`.replace(/[|\s[\],\u202e]+/g, " ").trim(); if (name.length > 18) name = name.substr(0, 18).trim(); name = name.replace( /[\u0300-\u036f\u0483-\u0489\u0610-\u0615\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06ED\u0E31\u0E34-\u0E3A\u0E47-\u0E4E]{3,}/g, "" ); name = name.replace(/[\u239b-\u23b9]/g, ""); return name; } /** * Returns false if the target is immune; true otherwise. * Also checks immunity to some statuses. */ getImmunity(source, target) { const sourceType = typeof source !== "string" ? source.type : source; const targetTyping = target.getTypes?.() || target.types || target; if (Array.isArray(targetTyping)) { for (const type of targetTyping) { if (!this.getImmunity(sourceType, type)) return false; } return true; } const typeData = this.types.get(targetTyping); if (typeData && typeData.damageTaken[sourceType] === 3) return false; return true; } getEffectiveness(source, target) { const sourceType = typeof source !== "string" ? source.type : source; const targetTyping = target.getTypes?.() || target.types || target; let totalTypeMod = 0; if (Array.isArray(targetTyping)) { for (const type of targetTyping) { totalTypeMod += this.getEffectiveness(sourceType, type); } return totalTypeMod; } const typeData = this.types.get(targetTyping); if (!typeData) return 0; switch (typeData.damageTaken[sourceType]) { case 1: return 1; case 2: return -1; default: return 0; } } getDescs(table, id, dataEntry) { if (dataEntry.shortDesc) { return { desc: dataEntry.desc, shortDesc: dataEntry.shortDesc }; } const entry = this.loadTextData()[table][id]; if (!entry) return null; const descs = { desc: "", shortDesc: "" }; for (let i = this.gen; i < dexes["base"].gen; i++) { const curDesc = entry[`gen${i}`]?.desc; const curShortDesc = entry[`gen${i}`]?.shortDesc; if (!descs.desc && curDesc) { descs.desc = curDesc; } if (!descs.shortDesc && curShortDesc) { descs.shortDesc = curShortDesc; } if (descs.desc && descs.shortDesc) break; } if (!descs.shortDesc) descs.shortDesc = entry.shortDesc || ""; if (!descs.desc) descs.desc = entry.desc || descs.shortDesc; return descs; } /** * Ensure we're working on a copy of a move (and make a copy if we aren't) * * Remember: "ensure" - by default, it won't make a copy of a copy: * moveCopy === Dex.getActiveMove(moveCopy) * * If you really want to, use: * moveCopyCopy = Dex.getActiveMove(moveCopy.id) */ getActiveMove(move) { if (move && typeof move.hit === "number") return move; move = this.moves.get(move); const moveCopy = this.deepClone(move); moveCopy.hit = 0; return moveCopy; } getHiddenPower(ivs) { const hpTypes = [ "Fighting", "Flying", "Poison", "Ground", "Rock", "Bug", "Ghost", "Steel", "Fire", "Water", "Grass", "Electric", "Psychic", "Ice", "Dragon", "Dark" ]; const tr = this.trunc; const stats = { hp: 31, atk: 31, def: 31, spe: 31, spa: 31, spd: 31 }; if (this.gen <= 2) { const atkDV = tr(ivs.atk / 2); const defDV = tr(ivs.def / 2); const speDV = tr(ivs.spe / 2); const spcDV = tr(ivs.spa / 2); return { type: hpTypes[4 * (atkDV % 4) + defDV % 4], power: tr( (5 * ((spcDV >> 3) + 2 * (speDV >> 3) + 4 * (defDV >> 3) + 8 * (atkDV >> 3)) + spcDV % 4) / 2 + 31 ) }; } else { let hpTypeX = 0; let hpPowerX = 0; let i = 1; for (const s in stats) { hpTypeX += i * (ivs[s] % 2); hpPowerX += i * (tr(ivs[s] / 2) % 2); i *= 2; } return { type: hpTypes[tr(hpTypeX * 15 / 63)], // After Gen 6, Hidden Power is always 60 base power power: this.gen && this.gen < 6 ? tr(hpPowerX * 40 / 63) + 30 : 60 }; } } /** * Truncate a number into an unsigned 32-bit integer, for * compatibility with the cartridge games' math systems. */ trunc(num, bits = 0) { if (bits) return (num >>> 0) % 2 ** bits; return num >>> 0; } dataSearch(target, searchIn, isInexact) { if (!target) return null; searchIn = searchIn || ["Pokedex", "Moves", "Abilities", "Items", "Natures"]; const searchObjects = { Pokedex: "species", Moves: "moves", Abilities: "abilities", Items: "items", Natures: "natures", TypeChart: "types" }; const searchTypes = { Pokedex: "pokemon", Moves: "move", Abilities: "ability", Items: "item", Natures: "nature", TypeChart: "type" }; let searchResults = []; for (const table of searchIn) { const res = this[searchObjects[table]].get(target); if (res.exists && res.gen <= this.gen) { searchResults.push({ isInexact, searchType: searchTypes[table], name: res.name }); } } if (searchResults.length) return searchResults; if (isInexact) return null; const cmpTarget = toID(target); let maxLd = 3; if (cmpTarget.length <= 1) { return null; } else if (cmpTarget.length <= 4) { maxLd = 1; } else if (cmpTarget.length <= 6) { maxLd = 2; } searchResults = null; for (const table of [...searchIn, "Aliases"]) { const searchObj = this.data[table]; if (!searchObj) continue; for (const j in searchObj) { const ld = import_utils.Utils.levenshtein(cmpTarget, j, maxLd); if (ld <= maxLd) { const word = searchObj[j].name || j; const results = this.dataSearch(word, searchIn, word); if (results) { searchResults = results; maxLd = ld; } } } } return searchResults; } loadDataFile(basePath, dataType) { try { const filePath = basePath + DATA_FILES[dataType]; const dataObject = require(filePath); if (!dataObject || typeof dataObject !== "object") { throw new TypeError(`${filePath}, if it exists, must export a non-null object`); } if (dataObject[dataType]?.constructor?.name !== "Object") { throw new TypeError(`${filePath}, if it exists, must export an object whose '${dataType}' property is an Object`); } return dataObject[dataType]; } catch (e) { if (e.code !== "MODULE_NOT_FOUND" && e.code !== "ENOENT") { throw e; } } } loadTextFile(name, exportName) { return require(`${DATA_DIR}/text/${name}`)[exportName]; } includeMods() { if (!this.isBase) throw new Error(`This must be called on the base Dex`); if (this.modsLoaded) return this; for (const mod of fs.readdirSync(MODS_DIR)) { dexes[mod] = new ModdedDex(mod); } this.modsLoaded = true; return this; } includeModData() { for (const mod in this.dexes) { dexes[mod].includeData(); } return this; } includeData() { this.loadData(); return this; } loadTextData() { if (dexes["base"].textCache) return dexes["base"].textCache; dexes["base"].textCache = { Pokedex: this.loadTextFile("pokedex", "PokedexText"), Moves: this.loadTextFile("moves", "MovesText"), Abilities: this.loadTextFile("abilities", "AbilitiesText"), Items: this.loadTextFile("items", "ItemsText"), Default: this.loadTextFile("default", "DefaultText") }; return dexes["base"].textCache; } loadData() { if (this.dataCache) return this.dataCache; dexes["base"].includeMods(); const dataCache = {}; const basePath = this.dataDir + "/"; const Scripts = this.loadDataFile(basePath, "Scripts") || {}; const init = Scripts.init; this.parentMod = this.isBase ? "" : Scripts.inherit || "base"; let parentDex; if (this.parentMod) { parentDex = dexes[this.parentMod]; if (!parentDex || parentDex === this) { throw new Error( `Unable to load ${this.currentMod}. 'inherit' in scripts.ts should specify a parent mod from which to inherit data, or must be not specified.` ); } } if (!parentDex) { this.includeFormats(); } for (const dataType of DATA_TYPES.concat("Aliases")) { dataCache[dataType] = this.loadDataFile(basePath, dataType); if (dataType === "Rulesets" && !parentDex) { for (const format of this.formats.all()) { dataCache.Rulesets[format.id] = { ...format, ruleTable: null }; } } } if (parentDex) { for (const dataType of DATA_TYPES) { const parentTypedData = parentDex.data[dataType]; if (!dataCache[dataType] && !init) { dataCache[dataType] = parentTypedData; continue; } const childTypedData = dataCache[dataType] || (dataCache[dataType] = {}); for (const entryId in parentTypedData) { if (childTypedData[entryId] === null) { delete childTypedData[entryId]; } else if (!(entryId in childTypedData)) { childTypedData[entryId] = parentTypedData[entryId]; } else if (childTypedData[entryId]?.inherit) { delete childTypedData[entryId].inherit; childTypedData[entryId] = { ...parentTypedData[entryId], ...childTypedData[entryId] }; } } } dataCache["Aliases"] = parentDex.data["Aliases"]; } this.gen = dataCache.Scripts.gen; if (!this.gen) throw new Error(`Mod ${this.currentMod} needs a generation number in scripts.js`); this.dataCache = dataCache; if (init) init.call(this); return this.dataCache; } includeFormats() { this.formats.load(); return this; } } dexes["base"] = new ModdedDex(); dexes[BASE_MOD] = dexes["base"]; const Dex = dexes["base"]; var dex_default = Dex; //# sourceMappingURL=dex.js.map