Spaces:
Running
Running
; | |
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 | |