mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-04-26 02:39:38 -05:00
Improve TypeScript typing
sim/dex.js and sim/prng.js are now valid strict TypeScript! Also they have slightly less "any" use than before.
This commit is contained in:
parent
1c96b80694
commit
22186f1903
|
|
@ -1126,7 +1126,7 @@ exports.BattleScripts = {
|
|||
// Spammable attacks are: Thunderbolt, Psychic, Surf, Blizzard, Earthquake.
|
||||
let pokemonWeaknesses = [];
|
||||
for (let type in weaknessCount) {
|
||||
let increaseCount = Dex.getImmunity(type, template) && Dex.getEffectiveness(type, template) > 0;
|
||||
let increaseCount = this.getImmunity(type, template) && this.getEffectiveness(type, template) > 0;
|
||||
if (!increaseCount) continue;
|
||||
if (weaknessCount[type] >= 2) {
|
||||
skip = true;
|
||||
|
|
|
|||
|
|
@ -1408,7 +1408,7 @@ class Battle extends Dex.ModdedDex {
|
|||
if (this.rated) {
|
||||
this.add('rated');
|
||||
}
|
||||
this.add('seed', Battle.logReplay.bind(this, this.prngSeed.join(',')));
|
||||
this.add('seed', side => Battle.logReplay(this.prngSeed.join(','), side));
|
||||
|
||||
if (format.onBegin) {
|
||||
format.onBegin.call(this);
|
||||
|
|
@ -1429,6 +1429,50 @@ class Battle extends Dex.ModdedDex {
|
|||
this.midTurn = true;
|
||||
if (!this.currentRequest) this.go();
|
||||
}
|
||||
/**
|
||||
* returns false if the target is immune; true otherwise
|
||||
*
|
||||
* also checks immunity to some statuses
|
||||
* @param {Sim.Pokemon} source
|
||||
* @param {Sim.Pokemon} target
|
||||
*/
|
||||
getImmunity(source, target) {
|
||||
let sourceType = source.type || source;
|
||||
let targetTyping = target.getTypes && target.getTypes() || target.types || target;
|
||||
if (Array.isArray(targetTyping)) {
|
||||
for (let i = 0; i < targetTyping.length; i++) {
|
||||
if (!this.getImmunity(sourceType, targetTyping[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
let typeData = this.data.TypeChart[targetTyping];
|
||||
if (typeData && typeData.damageTaken[sourceType] === 3) return false;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @param {Sim.Pokemon} source
|
||||
* @param {Sim.Pokemon} target
|
||||
*/
|
||||
getEffectiveness(source, target) {
|
||||
let sourceType = source.type || source;
|
||||
let totalTypeMod = 0;
|
||||
let targetTyping = target.getTypes && target.getTypes() || target.types || target;
|
||||
if (Array.isArray(targetTyping)) {
|
||||
for (let i = 0; i < targetTyping.length; i++) {
|
||||
totalTypeMod += this.getEffectiveness(sourceType, targetTyping[i]);
|
||||
}
|
||||
return totalTypeMod;
|
||||
}
|
||||
let typeData = this.data.TypeChart[targetTyping];
|
||||
if (!typeData) return 0;
|
||||
switch (typeData.damageTaken[sourceType]) {
|
||||
case 1: return 1; // super-effective
|
||||
case 2: return -1; // resist
|
||||
// in case of weird situations like Gravity, immunity is
|
||||
// handled elsewhere
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
boost(boost, target, source, effect, isSecondary, isSelf) {
|
||||
if (this.event) {
|
||||
if (!target) target = this.event.target;
|
||||
|
|
|
|||
0
sim/dex-data.js
Normal file
0
sim/dex-data.js
Normal file
340
sim/dex.js
340
sim/dex.js
|
|
@ -51,6 +51,7 @@ const FORMATS = path.resolve(__dirname, '../config/formats');
|
|||
|
||||
// shim Object.values
|
||||
if (!Object.values) {
|
||||
// @ts-ignore
|
||||
Object.values = function (object) {
|
||||
let values = [];
|
||||
for (let k in object) values.push(object[k]);
|
||||
|
|
@ -76,10 +77,14 @@ if (!Object.values) {
|
|||
// };
|
||||
// }
|
||||
|
||||
/** @typedef {{[k: string]: any}} AnyObject */
|
||||
|
||||
/** @type {{[mod: string]: ModdedDex}} */
|
||||
let dexes = {};
|
||||
|
||||
/** @typedef {'Pokedex' | 'FormatsData' | 'Learnsets' | 'Movedex' | 'Statuses' | 'TypeChart' | 'Scripts' | 'Items' | 'Abilities' | 'Natures' | 'Formats' | 'Aliases'} DataType */
|
||||
/** @type {DataType[]} */
|
||||
// @ts-ignore TypeScript bug
|
||||
const DATA_TYPES = ['Pokedex', 'FormatsData', 'Learnsets', 'Movedex', 'Statuses', 'TypeChart', 'Scripts', 'Items', 'Abilities', 'Natures', 'Formats', 'Aliases'];
|
||||
|
||||
const DATA_FILES = {
|
||||
|
|
@ -97,12 +102,10 @@ const DATA_FILES = {
|
|||
'Natures': 'natures',
|
||||
};
|
||||
|
||||
/** @typedef {{
|
||||
id: string,
|
||||
name: string,
|
||||
}} DexTemplate */
|
||||
/** @typedef {{id: string, name: string, [k: string]: any}} DexTemplate */
|
||||
/** @typedef {{[id: string]: AnyObject}} DexTable */
|
||||
|
||||
/** @typedef {{Pokedex: object, Movedex: object, Statuses: object, TypeChart: object, Scripts: object, Items: object, Abilities: object, FormatsData: object, Learnsets: object, Aliases: object, Natures: object}} ModdedDex */
|
||||
/** @typedef {{Pokedex: DexTable, Movedex: DexTable, Statuses: DexTable, TypeChart: DexTable, Scripts: DexTable, Items: DexTable, Abilities: DexTable, FormatsData: DexTable, Learnsets: DexTable, Aliases: DexTable, Natures: DexTable, Formats: DexTable, MoveCache: Map, ItemCache: Map, AbilityCache: Map, TemplateCache: Map}} DexData */
|
||||
|
||||
const BattleNatures = {
|
||||
adamant: {name:"Adamant", plus:'atk', minus:'spa'},
|
||||
|
|
@ -132,6 +135,10 @@ const BattleNatures = {
|
|||
timid: {name:"Timid", plus:'spe', minus:'atk'},
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} text
|
||||
* @return {string}
|
||||
*/
|
||||
function toId(text) {
|
||||
// this is a duplicate of Dex.getId, for performance reasons
|
||||
if (text && text.id) {
|
||||
|
|
@ -157,23 +164,32 @@ class ModdedDex {
|
|||
this.currentMod = mod;
|
||||
this.parentMod = '';
|
||||
|
||||
/** @type {any} */
|
||||
/** @type {?DexData} */
|
||||
this.dataCache = null;
|
||||
/** @type {any} */
|
||||
/** @type {?DexTable} */
|
||||
this.formatsCache = null;
|
||||
this.modsLoaded = false;
|
||||
|
||||
this.ModdedDex = ModdedDex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {DexData}
|
||||
*/
|
||||
get data() {
|
||||
this.includeData();
|
||||
return this.dataCache;
|
||||
return this.loadData();
|
||||
}
|
||||
/**
|
||||
* @return {DexTable}
|
||||
*/
|
||||
get formats() {
|
||||
this.includeFormats();
|
||||
// @ts-ignore
|
||||
return this.formatsCache;
|
||||
}
|
||||
/**
|
||||
* @return {{[mod: string]: ModdedDex}}
|
||||
*/
|
||||
get dexes() {
|
||||
this.includeMods();
|
||||
return dexes;
|
||||
|
|
@ -188,6 +204,10 @@ class ModdedDex {
|
|||
if (!mod) mod = 'base';
|
||||
return dexes[mod];
|
||||
}
|
||||
/**
|
||||
* @param {AnyObject | string} format
|
||||
* @return {ModdedDex}
|
||||
*/
|
||||
format(format) {
|
||||
if (!this.modsLoaded) this.includeMods();
|
||||
const mod = this.getFormat(format).mod;
|
||||
|
|
@ -286,51 +306,12 @@ class ModdedDex {
|
|||
return ('' + text).toLowerCase().replace(/[^a-z0-9]+/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* returns false if the target is immune; true otherwise
|
||||
*
|
||||
* also checks immunity to some statuses
|
||||
*/
|
||||
getImmunity(source, target) {
|
||||
let sourceType = source.type || source;
|
||||
let targetTyping = target.getTypes && target.getTypes() || target.types || target;
|
||||
if (Array.isArray(targetTyping)) {
|
||||
for (let i = 0; i < targetTyping.length; i++) {
|
||||
if (!this.getImmunity(sourceType, targetTyping[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
let typeData = this.data.TypeChart[targetTyping];
|
||||
if (typeData && typeData.damageTaken[sourceType] === 3) return false;
|
||||
return true;
|
||||
}
|
||||
getEffectiveness(source, target) {
|
||||
let sourceType = source.type || source;
|
||||
let totalTypeMod = 0;
|
||||
let targetTyping = target.getTypes && target.getTypes() || target.types || target;
|
||||
if (Array.isArray(targetTyping)) {
|
||||
for (let i = 0; i < targetTyping.length; i++) {
|
||||
totalTypeMod += this.getEffectiveness(sourceType, targetTyping[i]);
|
||||
}
|
||||
return totalTypeMod;
|
||||
}
|
||||
let typeData = this.data.TypeChart[targetTyping];
|
||||
if (!typeData) return 0;
|
||||
switch (typeData.damageTaken[sourceType]) {
|
||||
case 1: return 1; // super-effective
|
||||
case 2: return -1; // resist
|
||||
// in case of weird situations like Gravity, immunity is
|
||||
// handled elsewhere
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a pokemon name, ID, or template into its species name, preserving
|
||||
* form name (which is the main way Dex.getSpecies(id) differs from
|
||||
* Dex.getTemplate(id).species).
|
||||
*
|
||||
* @param {string|DexTemplate} species
|
||||
* @param {string | AnyObject} species
|
||||
* @return {string}
|
||||
*/
|
||||
getSpecies(species) {
|
||||
|
|
@ -345,6 +326,10 @@ class ModdedDex {
|
|||
return species;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | AnyObject} template
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getTemplate(template) {
|
||||
if (!template || typeof template === 'string') {
|
||||
let name = (template || '').trim();
|
||||
|
|
@ -446,11 +431,19 @@ class ModdedDex {
|
|||
}
|
||||
return template;
|
||||
}
|
||||
/**
|
||||
* @param {string | AnyObject} template
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getLearnset(template) {
|
||||
const id = toId(template);
|
||||
if (!this.data.Learnsets[id]) return null;
|
||||
return this.data.Learnsets[id].learnset;
|
||||
}
|
||||
/**
|
||||
* @param {string | AnyObject} move
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getMove(move) {
|
||||
if (!move || typeof move === 'string') {
|
||||
let name = (move || '').trim();
|
||||
|
|
@ -518,83 +511,98 @@ class ModdedDex {
|
|||
* If you really want to, use:
|
||||
* moveCopyCopy = Dex.getMoveCopy(moveCopy.id)
|
||||
*
|
||||
* @param move Move ID, move object, or movecopy object describing move to copy
|
||||
* @return movecopy object
|
||||
* @param {AnyObject | string} move - Move ID, move object, or movecopy object describing move to copy
|
||||
* @return {AnyObject} movecopy object
|
||||
*/
|
||||
getMoveCopy(move) {
|
||||
// @ts-ignore
|
||||
if (move && move.isCopy) return move;
|
||||
move = this.getMove(move);
|
||||
let moveCopy = this.deepClone(move);
|
||||
moveCopy.isCopy = true;
|
||||
return moveCopy;
|
||||
}
|
||||
getEffect(effect) {
|
||||
if (!effect || typeof effect === 'string') {
|
||||
let name = (effect || '').trim();
|
||||
let id = toId(name);
|
||||
effect = {};
|
||||
if (id && this.data.Statuses[id]) {
|
||||
effect = this.data.Statuses[id];
|
||||
effect.name = effect.name || this.data.Statuses[id].name;
|
||||
} else if (id && this.data.Movedex[id] && this.data.Movedex[id].effect) {
|
||||
effect = this.data.Movedex[id].effect;
|
||||
effect.name = effect.name || this.data.Movedex[id].name;
|
||||
} else if (id && this.data.Abilities[id] && this.data.Abilities[id].effect) {
|
||||
effect = this.data.Abilities[id].effect;
|
||||
effect.name = effect.name || this.data.Abilities[id].name;
|
||||
} else if (id && this.data.Items[id] && this.data.Items[id].effect) {
|
||||
effect = this.data.Items[id].effect;
|
||||
effect.name = effect.name || this.data.Items[id].name;
|
||||
} else if (id && this.data.Formats[id]) {
|
||||
effect = this.data.Formats[id];
|
||||
effect.name = effect.name || this.data.Formats[id].name;
|
||||
if (!effect.mod) effect.mod = 'gen6';
|
||||
if (!effect.effectType) effect.effectType = 'Format';
|
||||
} else if (id === 'recoil') {
|
||||
effect = {
|
||||
effectType: 'Recoil',
|
||||
};
|
||||
} else if (id === 'drain') {
|
||||
effect = {
|
||||
effectType: 'Drain',
|
||||
};
|
||||
}
|
||||
if (!effect.id) effect.id = id;
|
||||
if (!effect.name) effect.name = name;
|
||||
if (!effect.fullname) effect.fullname = effect.name;
|
||||
effect.toString = this.effectToString;
|
||||
if (!effect.category) effect.category = 'Effect';
|
||||
if (!effect.effectType) effect.effectType = 'Effect';
|
||||
/**
|
||||
* @param {string | AnyObject} name
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getEffect(name) {
|
||||
if (name && typeof name !== 'string') {
|
||||
return name;
|
||||
}
|
||||
name = (name || '').trim();
|
||||
let id = toId(name);
|
||||
let effect = {};
|
||||
if (id && this.data.Statuses[id]) {
|
||||
effect = this.data.Statuses[id];
|
||||
effect.name = effect.name || this.data.Statuses[id].name;
|
||||
} else if (id && this.data.Movedex[id] && this.data.Movedex[id].effect) {
|
||||
effect = this.data.Movedex[id].effect;
|
||||
effect.name = effect.name || this.data.Movedex[id].name;
|
||||
} else if (id && this.data.Abilities[id] && this.data.Abilities[id].effect) {
|
||||
effect = this.data.Abilities[id].effect;
|
||||
effect.name = effect.name || this.data.Abilities[id].name;
|
||||
} else if (id && this.data.Items[id] && this.data.Items[id].effect) {
|
||||
effect = this.data.Items[id].effect;
|
||||
effect.name = effect.name || this.data.Items[id].name;
|
||||
} else if (id && this.data.Formats[id]) {
|
||||
effect = this.data.Formats[id];
|
||||
effect.name = effect.name || this.data.Formats[id].name;
|
||||
if (!effect.mod) effect.mod = 'gen6';
|
||||
if (!effect.effectType) effect.effectType = 'Format';
|
||||
} else if (id === 'recoil') {
|
||||
effect = {
|
||||
effectType: 'Recoil',
|
||||
};
|
||||
} else if (id === 'drain') {
|
||||
effect = {
|
||||
effectType: 'Drain',
|
||||
};
|
||||
}
|
||||
if (!effect.id) effect.id = id;
|
||||
if (!effect.name) effect.name = name;
|
||||
if (!effect.fullname) effect.fullname = effect.name;
|
||||
effect.toString = this.effectToString;
|
||||
if (!effect.category) effect.category = 'Effect';
|
||||
if (!effect.effectType) effect.effectType = 'Effect';
|
||||
return effect;
|
||||
}
|
||||
getFormat(effect) {
|
||||
if (!effect || typeof effect === 'string') {
|
||||
let name = (effect || '').trim();
|
||||
let id = toId(name);
|
||||
if (this.data.Aliases[id]) {
|
||||
name = this.data.Aliases[id];
|
||||
id = toId(name);
|
||||
}
|
||||
effect = {};
|
||||
if (this.data.Formats.hasOwnProperty(id)) {
|
||||
effect = this.data.Formats[id];
|
||||
if (effect.cached) return effect;
|
||||
effect.cached = true;
|
||||
effect.exists = true;
|
||||
effect.name = effect.name || this.data.Formats[id].name;
|
||||
if (!effect.mod) effect.mod = 'gen6';
|
||||
if (!effect.effectType) effect.effectType = 'Format';
|
||||
}
|
||||
if (!effect.id) effect.id = id;
|
||||
if (!effect.name) effect.name = name;
|
||||
if (!effect.fullname) effect.fullname = effect.name;
|
||||
effect.toString = this.effectToString;
|
||||
if (!effect.category) effect.category = 'Effect';
|
||||
if (!effect.effectType) effect.effectType = 'Effect';
|
||||
/**
|
||||
* @param {string | AnyObject} name
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getFormat(name) {
|
||||
if (name && typeof name !== 'string') {
|
||||
return name;
|
||||
}
|
||||
name = (name || '').trim();
|
||||
let id = toId(name);
|
||||
if (this.data.Aliases[id]) {
|
||||
name = this.data.Aliases[id];
|
||||
id = toId(name);
|
||||
}
|
||||
let effect = {};
|
||||
if (this.data.Formats.hasOwnProperty(id)) {
|
||||
effect = this.data.Formats[id];
|
||||
if (effect.cached) return effect;
|
||||
effect.cached = true;
|
||||
effect.exists = true;
|
||||
effect.name = effect.name || this.data.Formats[id].name;
|
||||
if (!effect.mod) effect.mod = 'gen6';
|
||||
if (!effect.effectType) effect.effectType = 'Format';
|
||||
}
|
||||
if (!effect.id) effect.id = id;
|
||||
if (!effect.name) effect.name = name;
|
||||
if (!effect.fullname) effect.fullname = effect.name;
|
||||
effect.toString = this.effectToString;
|
||||
if (!effect.category) effect.category = 'Effect';
|
||||
if (!effect.effectType) effect.effectType = 'Effect';
|
||||
return effect;
|
||||
}
|
||||
/**
|
||||
* @param {string | AnyObject} item
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getItem(item) {
|
||||
if (!item || typeof item === 'string') {
|
||||
let name = (item || '').trim();
|
||||
|
|
@ -648,6 +656,10 @@ class ModdedDex {
|
|||
}
|
||||
return item;
|
||||
}
|
||||
/**
|
||||
* @param {string | AnyObject} ability
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getAbility(ability) {
|
||||
if (!ability || typeof ability === 'string') {
|
||||
let name = (ability || '').trim();
|
||||
|
|
@ -687,6 +699,10 @@ class ModdedDex {
|
|||
}
|
||||
return ability;
|
||||
}
|
||||
/**
|
||||
* @param {string | AnyObject} type
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getType(type) {
|
||||
if (!type || typeof type === 'string') {
|
||||
let id = toId(type);
|
||||
|
|
@ -708,6 +724,10 @@ class ModdedDex {
|
|||
}
|
||||
return type;
|
||||
}
|
||||
/**
|
||||
* @param {string | AnyObject} nature
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getNature(nature) {
|
||||
if (!nature || typeof nature === 'string') {
|
||||
let name = (nature || '').trim();
|
||||
|
|
@ -726,6 +746,11 @@ class ModdedDex {
|
|||
}
|
||||
return nature;
|
||||
}
|
||||
/**
|
||||
* @param {AnyObject} stats
|
||||
* @param {AnyObject} set
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
spreadModify(stats, set) {
|
||||
const modStats = {atk:10, def:10, spa:10, spd:10, spe:10};
|
||||
for (let statName in modStats) {
|
||||
|
|
@ -738,6 +763,11 @@ class ModdedDex {
|
|||
}
|
||||
return this.natureModify(modStats, set.nature);
|
||||
}
|
||||
/**
|
||||
* @param {AnyObject} stats
|
||||
* @param {string | AnyObject} nature
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
natureModify(stats, nature) {
|
||||
nature = this.getNature(nature);
|
||||
if (nature.plus) stats[nature.plus] = Math.floor(stats[nature.plus] * 1.1);
|
||||
|
|
@ -745,6 +775,9 @@ class ModdedDex {
|
|||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AnyObject} ivs
|
||||
*/
|
||||
getHiddenPower(ivs) {
|
||||
const hpTypes = ['Fighting', 'Flying', 'Poison', 'Ground', 'Rock', 'Bug', 'Ghost', 'Steel', 'Fire', 'Water', 'Grass', 'Electric', 'Psychic', 'Ice', 'Dragon', 'Dark'];
|
||||
const stats = {hp: 31, atk: 31, def: 31, spe: 31, spa: 31, spd: 31};
|
||||
|
|
@ -775,6 +808,12 @@ class ModdedDex {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AnyObject} format
|
||||
* @param {AnyObject=} subformat
|
||||
* @param {number=} depth
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
getBanlistTable(format, subformat, depth) {
|
||||
let banlistTable;
|
||||
if (!depth) depth = 0;
|
||||
|
|
@ -849,6 +888,11 @@ class ModdedDex {
|
|||
return banlistTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: TypeScript generics
|
||||
* @param {Array} arr
|
||||
* @return {Array}
|
||||
*/
|
||||
shuffle(arr) {
|
||||
// In-place shuffle by Fisher-Yates algorithm
|
||||
for (let i = arr.length - 1; i > 0; i--) {
|
||||
|
|
@ -864,6 +908,7 @@ class ModdedDex {
|
|||
* @param {string} s - string 1
|
||||
* @param {string} t - string 2
|
||||
* @param {number} l - limit
|
||||
* @return {number} - distance
|
||||
*/
|
||||
levenshtein(s, t, l) {
|
||||
// Original levenshtein distance function by James Westgate, turned out to be the fastest
|
||||
|
|
@ -913,6 +958,13 @@ class ModdedDex {
|
|||
return d[n][m];
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces num to be an integer (between min and max).
|
||||
* @param {any} num
|
||||
* @param {number=} min
|
||||
* @param {number=} max
|
||||
* @return {number}
|
||||
*/
|
||||
clampIntRange(num, min, max) {
|
||||
if (typeof num !== 'number') num = 0;
|
||||
num = Math.floor(num);
|
||||
|
|
@ -921,6 +973,12 @@ class ModdedDex {
|
|||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} target
|
||||
* @param {DataType[] | null=} searchIn
|
||||
* @param {boolean=} isInexact
|
||||
* @return {AnyObject[] | false}
|
||||
*/
|
||||
dataSearch(target, searchIn, isInexact) {
|
||||
if (!target) {
|
||||
return false;
|
||||
|
|
@ -932,6 +990,8 @@ class ModdedDex {
|
|||
let searchTypes = {Pokedex: 'pokemon', Movedex: 'move', Abilities: 'ability', Items: 'item', Natures: 'nature'};
|
||||
let searchResults = [];
|
||||
for (let i = 0; i < searchIn.length; i++) {
|
||||
/** @type {AnyObject} */
|
||||
// @ts-ignore TypeScript bug
|
||||
let res = this[searchFunctions[searchIn[i]]](target);
|
||||
if (res.exists) {
|
||||
searchResults.push({
|
||||
|
|
@ -997,6 +1057,10 @@ class ModdedDex {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AnyObject[]} team
|
||||
* @return {string}
|
||||
*/
|
||||
packTeam(team) {
|
||||
if (!team) return '';
|
||||
|
||||
|
|
@ -1099,6 +1163,10 @@ class ModdedDex {
|
|||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} buf
|
||||
* @return {AnyObject[]}
|
||||
*/
|
||||
fastUnpackTeam(buf) {
|
||||
if (!buf) return null;
|
||||
|
||||
|
|
@ -1218,6 +1286,10 @@ class ModdedDex {
|
|||
return team;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AnyObject} obj
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
deepClone(obj) {
|
||||
if (typeof obj === 'function') return obj;
|
||||
if (obj === null || typeof obj !== 'object') return obj;
|
||||
|
|
@ -1230,6 +1302,11 @@ class ModdedDex {
|
|||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} basePath
|
||||
* @param {DataType} dataType
|
||||
* @return {AnyObject}
|
||||
*/
|
||||
loadDataFile(basePath, dataType) {
|
||||
try {
|
||||
const filePath = basePath + DATA_FILES[dataType];
|
||||
|
|
@ -1246,6 +1323,9 @@ class ModdedDex {
|
|||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {ModdedDex}
|
||||
*/
|
||||
includeMods() {
|
||||
if (!this.isBase) throw new Error(`This must be called on the base Dex`);
|
||||
if (this.modsLoaded) return this;
|
||||
|
|
@ -1259,14 +1339,28 @@ class ModdedDex {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {ModdedDex}
|
||||
*/
|
||||
includeModData() {
|
||||
for (const mod in this.dexes) {
|
||||
dexes[mod].includeData();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {ModdedDex}
|
||||
*/
|
||||
includeData() {
|
||||
if (this.dataCache) return this;
|
||||
this.loadData();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @return {DexData}
|
||||
*/
|
||||
loadData() {
|
||||
if (this.dataCache) return this.dataCache;
|
||||
dexes['base'].includeMods();
|
||||
this.dataCache = {};
|
||||
|
||||
|
|
@ -1336,9 +1430,12 @@ class ModdedDex {
|
|||
// Execute initialization script.
|
||||
if (BattleScripts.init) BattleScripts.init.call(this);
|
||||
|
||||
return this;
|
||||
return this.dataCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {ModdedDex}
|
||||
*/
|
||||
includeFormats() {
|
||||
if (!this.isBase) throw new Error(`This should only be run on the base mod`);
|
||||
this.includeMods();
|
||||
|
|
@ -1379,23 +1476,20 @@ class ModdedDex {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} id - Format ID
|
||||
* @param {object} format - Format
|
||||
*/
|
||||
installFormat(id, format) {
|
||||
dexes['base'].includeFormats();
|
||||
// @ts-ignore
|
||||
dexes['base'].formatsCache[id] = format;
|
||||
if (this.dataCache) this.dataCache.Formats[id] = format;
|
||||
if (!this.isBase) {
|
||||
// @ts-ignore
|
||||
if (dexes['base'].dataCache) dexes['base'].dataCache.Formats[id] = format;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install our Dex functions into the battle object
|
||||
*/
|
||||
install(battle) {
|
||||
for (let i in this.data.Scripts) {
|
||||
battle[i] = this.data.Scripts[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dexes['base'] = new ModdedDex();
|
||||
|
|
|
|||
|
|
@ -27,7 +27,11 @@ exports.construct = function (format, rated, send, prng) {
|
|||
const dex = Dex.mod(mod);
|
||||
const proto = Object.create(Battle.prototype);
|
||||
Object.assign(proto, dex);
|
||||
dex.install(proto);
|
||||
|
||||
for (let i in dex.data.Scripts) {
|
||||
proto[i] = dex.data.Scripts[i];
|
||||
}
|
||||
|
||||
battleProtoCache.set(mod, proto);
|
||||
}
|
||||
const battle = Object.create(battleProtoCache.get(mod));
|
||||
|
|
|
|||
|
|
@ -21,9 +21,10 @@ class PRNG {
|
|||
constructor(seed = PRNG.generateSeed()) {
|
||||
// We slice() the seed so we get a copy of it instead of the original seed.
|
||||
/** @type {PRNGSeed} */
|
||||
// @ts-ignore
|
||||
// @ts-ignore TypeScript bug
|
||||
this.initialSeed = seed.slice();
|
||||
/** @type {PRNGSeed} */
|
||||
// @ts-ignore TypeScript bug
|
||||
this.seed = seed.slice();
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +128,7 @@ class PRNG {
|
|||
This is all ignoring overflow/carry because that cannot be shown in a pseudo-mathematical equation.
|
||||
The below code implements a optimised version of that equation while also checking for overflow/carry.
|
||||
|
||||
@param {PRNGSeed} initialSeed
|
||||
@param {number} [framesToAdvance = 1]
|
||||
@return {PRNGSeed} the new seed
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class Side {
|
|||
let sideScripts = battle.data.Scripts.side;
|
||||
if (sideScripts) Object.assign(this, sideScripts);
|
||||
|
||||
this.getChoice = (this.getChoice || Side.getChoice).bind(this);
|
||||
this.getChoice = (side => this.getChoiceInner(side));
|
||||
|
||||
this.battle = battle;
|
||||
this.n = n;
|
||||
|
|
@ -106,7 +106,7 @@ class Side {
|
|||
}
|
||||
}
|
||||
|
||||
static getChoice(side) {
|
||||
getChoiceInner(side) {
|
||||
if (side !== this && side !== true) return '';
|
||||
return this.choice.actions.map(action => {
|
||||
switch (action.choice) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"lib": ["es2017"],
|
||||
"noEmit": true,
|
||||
"target": "ESNext",
|
||||
"strictNullChecks": true,
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user