diff --git a/config/formats.ts b/config/formats.ts index 534112a06c..4b35444b36 100644 --- a/config/formats.ts +++ b/config/formats.ts @@ -1193,7 +1193,7 @@ export const Formats: FormatList = [ const mixedSpecies = this.dex.deepClone(species); mixedSpecies.weightkg = - parseInt(Math.max(0.1, +(species.weightkg + crossSpecies.weightkg - crossPrevoSpecies.weightkg)).toFixed(1)); + Math.max(0.1, +(species.weightkg + crossSpecies.weightkg - crossPrevoSpecies.weightkg)).toFixed(1); mixedSpecies.nfe = false; mixedSpecies.evos = []; mixedSpecies.eggGroups = crossSpecies.eggGroups; diff --git a/data/mods/gen1/rulesets.ts b/data/mods/gen1/rulesets.ts index 6c4553578d..1e5edd92a9 100644 --- a/data/mods/gen1/rulesets.ts +++ b/data/mods/gen1/rulesets.ts @@ -17,7 +17,7 @@ export const Rulesets: {[k: string]: ModdedFormatData} = { const bst = newSpecies.bst; if (bst <= 350) { newSpecies.bst = 0; - for (const stat of Stats.statIDs) { + for (const stat in newSpecies.baseStats) { if (stat === 'spd') continue; newSpecies.baseStats[stat] = this.clampIntRange(newSpecies.baseStats[stat] * 2, 1, 255); newSpecies.bst += newSpecies.baseStats[stat]; @@ -43,8 +43,8 @@ export const Rulesets: {[k: string]: ModdedFormatData} = { spd: newSpecies.baseStats.atk, spe: newSpecies.baseStats.hp, }; - for (const statName of Stats.statIDs) { - newSpecies.baseStats[statName] = stats[statName]; + for (const i in newSpecies.baseStats) { + newSpecies.baseStats[i] = stats[i]; } return newSpecies; }, @@ -61,7 +61,7 @@ export const Rulesets: {[k: string]: ModdedFormatData} = { const pst: number = newSpecies.bst - newSpecies.baseStats['hp']; const scale = 500 - newSpecies.baseStats['hp']; newSpecies.bst = newSpecies.baseStats['hp']; - for (const stat of Stats.statIDs) { + for (const stat in newSpecies.baseStats) { if (stat === 'hp' || stat === 'spd') continue; newSpecies.baseStats[stat] = this.clampIntRange(newSpecies.baseStats[stat] * scale / pst, 1, 255); newSpecies.bst += newSpecies.baseStats[stat]; diff --git a/data/mods/gen7mixandmega/scripts.ts b/data/mods/gen7mixandmega/scripts.ts index 431c41f82c..44cf1eb9e9 100644 --- a/data/mods/gen7mixandmega/scripts.ts +++ b/data/mods/gen7mixandmega/scripts.ts @@ -99,11 +99,10 @@ export const Scripts: ModdedBattleScriptsData = { species.types = [species.types[0], deltas.type]; } const baseStats = species.baseStats; - for (const statName of Stats.statIDs) { + for (const statName in baseStats) { baseStats[statName] = this.battle.clampIntRange(baseStats[statName] + deltas.baseStats[statName], 1, 255); } species.weighthg = Math.max(1, species.weighthg + deltas.weighthg); - // @ts-ignore originalMega is not a defined property of the Species class, but we need to add it here species.originalMega = deltas.originalMega; species.requiredItem = deltas.requiredItem; if (deltas.isMega) species.isMega = true; diff --git a/data/mods/mixandmega/scripts.ts b/data/mods/mixandmega/scripts.ts index 7263d3e4e7..8aa985f35f 100644 --- a/data/mods/mixandmega/scripts.ts +++ b/data/mods/mixandmega/scripts.ts @@ -95,12 +95,10 @@ export const Scripts: ModdedBattleScriptsData = { species.types = [species.types[0], deltas.type]; } const baseStats = species.baseStats; - let statName: StatID; - for (statName in baseStats) { + for (const statName in baseStats) { baseStats[statName] = this.battle.clampIntRange(baseStats[statName] + deltas.baseStats[statName], 1, 255); } species.weighthg = Math.max(1, species.weighthg + deltas.weighthg); - // @ts-ignore species.originalMega = deltas.originalMega; species.requiredItem = deltas.requiredItem; if (deltas.isMega) species.isMega = true; diff --git a/data/rulesets.ts b/data/rulesets.ts index f9ad0370ca..5c63d32df0 100644 --- a/data/rulesets.ts +++ b/data/rulesets.ts @@ -1384,7 +1384,7 @@ export const Rulesets: {[k: string]: FormatData} = { const newSpecies = this.dex.deepClone(species); if (newSpecies.bst <= 350) { newSpecies.bst = 0; - for (const stat of Stats.statIDs) { + for (const stat in newSpecies.baseStats) { newSpecies.baseStats[stat] = this.clampIntRange(newSpecies.baseStats[stat] * 2, 1, 255); newSpecies.bst += newSpecies.baseStats[stat]; } @@ -1404,7 +1404,7 @@ export const Rulesets: {[k: string]: FormatData} = { const newSpecies = this.dex.deepClone(species); const reversedNums = Object.values(newSpecies.baseStats).reverse(); for (const [i, statName] of Object.keys(newSpecies.baseStats).entries()) { - newSpecies.baseStats[statName as StatID] = reversedNums[i]; + newSpecies.baseStats[statName] = reversedNums[i]; } return newSpecies; }, @@ -1422,7 +1422,8 @@ export const Rulesets: {[k: string]: FormatData} = { const bstWithoutHp: number = newSpecies.bst - newSpecies.baseStats['hp']; const scale = 600 - newSpecies.baseStats['hp']; newSpecies.bst = newSpecies.baseStats['hp']; - for (const stat of Stats.statIDsExceptHP) { + for (const stat in newSpecies.baseStats) { + if (stat === 'hp') continue; newSpecies.baseStats[stat] = this.clampIntRange(newSpecies.baseStats[stat] * scale / bstWithoutHp, 1, 255); newSpecies.bst += newSpecies.baseStats[stat]; } @@ -1852,7 +1853,8 @@ export const Rulesets: {[k: string]: FormatData} = { pokemon.bst = pokemon.baseStats['hp']; const boost = boosts[tier]; let statName: StatID; - for (statName of Stats.statIDsExceptHP) { + for (statName in pokemon.baseStats as StatsTable) { + if (statName === 'hp') continue; pokemon.baseStats[statName] = this.clampIntRange(pokemon.baseStats[statName] + boost, 1, 255); pokemon.bst += pokemon.baseStats[statName]; } diff --git a/lib/utils.ts b/lib/utils.ts index c46b985a91..b117ede0c2 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -153,6 +153,7 @@ export function visualize(value: any, depth = 0): string { /** * Compares two variables; intended to be used as a smarter comparator. + * The two variables must be the same type (TypeScript will not check this). * * - Numbers are sorted low-to-high, use `-val` to reverse * - Strings are sorted A to Z case-semi-insensitively, use `{reverse: val}` to reverse @@ -161,7 +162,7 @@ export function visualize(value: any, depth = 0): string { * * In other words: `[num, str]` will be sorted A to Z, `[num, {reverse: str}]` will be sorted Z to A. */ -export function compare(a: T, b: T): number { +export function compare(a: Comparable, b: Comparable): number { if (typeof a === 'number') { return a - (b as number); } @@ -179,7 +180,7 @@ export function compare(a: T, b: T): number { return 0; } if ('reverse' in a) { - return compare((b as {reverse: Comparable}).reverse, a.reverse); + return compare((b as {reverse: string}).reverse, a.reverse); } throw new Error(`Passed value ${a} is not comparable`); } @@ -317,12 +318,12 @@ export function clearRequireCache(options: {exclude?: string[]} = {}) { } } -export function deepClone(obj: T): Mutable { +export function deepClone(obj: any): any { if (obj === null || typeof obj !== 'object') return obj; - if (Array.isArray(obj)) return obj.map(prop => deepClone(prop)) as T; + if (Array.isArray(obj)) return obj.map(prop => deepClone(prop)); const clone = Object.create(Object.getPrototypeOf(obj)); for (const key of Object.keys(obj)) { - clone[key] = deepClone(obj[key as keyof typeof obj]); + clone[key] = deepClone(obj[key]); } return clone; } diff --git a/server/chat-plugins/datasearch.ts b/server/chat-plugins/datasearch.ts index 4fb104fea5..76e0fc90b0 100644 --- a/server/chat-plugins/datasearch.ts +++ b/server/chat-plugins/datasearch.ts @@ -1613,7 +1613,7 @@ function runMovesearch(target: string, cmd: string, canAll: boolean, message: st const getFullLearnsetOfPokemon = (species: Species) => { let usedSpecies: Species = Utils.deepClone(species); - let usedSpeciesLearnset: LearnsetData | undefined = Utils.deepClone(mod.species.getLearnset(usedSpecies.id)); + let usedSpeciesLearnset: LearnsetData = Utils.deepClone(mod.species.getLearnset(usedSpecies.id)); if (!usedSpeciesLearnset) { usedSpecies = Utils.deepClone(mod.species.get(usedSpecies.baseSpecies)); usedSpeciesLearnset = Utils.deepClone(mod.species.getLearnset(usedSpecies.id) || {}); diff --git a/server/chat-plugins/othermetas.ts b/server/chat-plugins/othermetas.ts index fbeab04791..fc40f6ac58 100644 --- a/server/chat-plugins/othermetas.ts +++ b/server/chat-plugins/othermetas.ts @@ -311,7 +311,7 @@ export const commands: Chat.ChatCommands = { } const bst = species.bst; species.bst = 0; - for (const i of Stats.statIDs) { + for (const i in species.baseStats) { if (dex.gen === 1 && i === 'spd') continue; species.baseStats[i] = species.baseStats[i] * (bst <= 350 ? 2 : 1); species.bst += species.baseStats[i]; @@ -362,11 +362,12 @@ export const commands: Chat.ChatCommands = { LC: 40, }; let tier = species.tier; - if (tier.startsWith("(")) tier = tier.slice(1, -1) as TierTypes.Singles | TierTypes.Other; + if (tier[0] === '(') tier = tier.slice(1, -1); if (!(tier in boosts)) return this.sendReply(`|html|${Chat.getDataPokemonHTML(species, dex.gen)}`); const boost = boosts[tier as TierShiftTiers]; species.bst = species.baseStats.hp; - for (const statName of Stats.statIDsExceptHP) { + for (const statName in species.baseStats) { + if (statName === 'hp') continue; if (dex.gen === 1 && statName === 'spd') continue; species.baseStats[statName] = Utils.clampIntRange(species.baseStats[statName] + boost, 1, 255); species.bst += species.baseStats[statName]; @@ -409,7 +410,7 @@ export const commands: Chat.ChatCommands = { const bstNoHP = species.bst - species.baseStats.hp; const scale = (dex.gen !== 1 ? 600 : 500) - species.baseStats['hp']; species.bst = 0; - for (const stat of Stats.statIDs) { + for (const stat in species.baseStats) { if (stat === 'hp') continue; if (dex.gen === 1 && stat === 'spd') continue; species.baseStats[stat] = Utils.clampIntRange(species.baseStats[stat] * scale / bstNoHP, 1, 255); @@ -461,7 +462,7 @@ export const commands: Chat.ChatCommands = { spd: species.baseStats.atk, spe: species.baseStats.hp, }; - for (const stat of Stats.statIDs) { + for (const stat in species.baseStats) { species.baseStats[stat] = flippedStats[stat]; } this.sendReply(`|raw|${Chat.getDataPokemonHTML(species, dex.gen)}`); @@ -469,7 +470,7 @@ export const commands: Chat.ChatCommands = { } const stats = Object.values(species.baseStats).reverse(); for (const [i, statName] of Object.keys(species.baseStats).entries()) { - species.baseStats[statName as keyof typeof species.baseStats] = stats[i]; + species.baseStats[statName] = stats[i]; } this.sendReply(`|raw|${Chat.getDataPokemonHTML(species, dex.gen)}`); }, @@ -590,7 +591,7 @@ export const commands: Chat.ChatCommands = { } else if (mixedSpecies.weighthg >= 100) { weighthit = 40; } - const details: {[k: string]: string | number} = { + const details: {[k: string]: string} = { "Dex#": mixedSpecies.num, Gen: mixedSpecies.gen, Height: mixedSpecies.heightm + " m", @@ -636,6 +637,8 @@ export const commands: Chat.ChatCommands = { deltas.types = deltas.types.filter((type: string | undefined) => type !== undefined); if (deltas.types[0] === deltas.types[1]) deltas.types = [deltas.types[0]]; + } else { + deltas.types = null; } } deltas.bst = 0; diff --git a/sim/dex.ts b/sim/dex.ts index 6e1fbb8d14..6fa39035c4 100644 --- a/sim/dex.ts +++ b/sim/dex.ts @@ -310,7 +310,7 @@ export class ModdedDex { getActiveMove(move: Move | string): ActiveMove { if (move && typeof (move as ActiveMove).hit === 'number') return move as ActiveMove; move = this.moves.get(move); - const moveCopy = this.deepClone(move) as ActiveMove; + const moveCopy: ActiveMove = this.deepClone(move); moveCopy.hit = 0; return moveCopy; } diff --git a/sim/global-types.ts b/sim/global-types.ts index e08145bdbf..820d598db0 100644 --- a/sim/global-types.ts +++ b/sim/global-types.ts @@ -24,14 +24,8 @@ type PokemonSlot = '' | string & {__isSlot: true}; interface AnyObject {[k: string]: any} type GenderName = 'M' | 'F' | 'N' | ''; -const _statIDsExceptHP = ['atk', 'def', 'spa', 'spd', 'spe'] as const; -const _statIDs = [..._statIDsExceptHP, 'hp'] as const; -namespace Stats { - export const statIDsExceptHP = _statIDsExceptHP; - export const statIDs = _statIDs; -} -type StatIDExceptHP = typeof _statIDsExceptHP[number]; -type StatID = typeof _statIDs[number]; +type StatIDExceptHP = 'atk' | 'def' | 'spa' | 'spd' | 'spe'; +type StatID = 'hp' | StatIDExceptHP; type StatsExceptHPTable = {[stat in StatIDExceptHP]: number}; type StatsTable = {[stat in StatID]: number}; type SparseStatsTable = Partial; @@ -70,7 +64,7 @@ namespace TierTypes { export type Singles = "AG" | "Uber" | "(Uber)" | "OU" | "(OU)" | "UUBL" | "UU" | "RUBL" | "RU" | "NUBL" | "NU" | "(NU)" | "PUBL" | "PU" | "(PU)" | "NFE" | "LC"; export type Doubles = "DUber" | "(DUber)" | "DOU" | "(DOU)" | "DBL" | "DUU" | "(DUU)" | "NFE" | "LC"; - export type Other = "Unreleased" | "Illegal" | "CAP" | "CAP NFE" | "CAP LC" | "MnM" | "NS" | "CE"; + export type Other = "Unreleased" | "Illegal" | "CAP" | "CAP NFE" | "CAP LC"; } interface EventInfo {