Jofthomas's picture
Upload 4781 files
5c2ed06 verified
"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