diff --git a/server/chat-commands/info.js b/server/chat-commands/info.ts
similarity index 81%
rename from server/chat-commands/info.js
rename to server/chat-commands/info.ts
index ba53799948..31139ff993 100644
--- a/server/chat-commands/info.js
+++ b/server/chat-commands/info.ts
@@ -8,14 +8,9 @@
*
* @license MIT
*/
+import * as net from 'net';
-'use strict';
-
-const net = require('net');
-
-/** @type {ChatCommands} */
-const commands = {
-
+export const commands: ChatCommands = {
'!whois': true,
ip: 'whois',
rooms: 'whois',
@@ -23,8 +18,9 @@ const commands = {
alts: 'whois',
whoare: 'whois',
whois(target, room, user, connection, cmd) {
- if (room && room.roomid === 'staff' && !this.runBroadcast()) return;
- if (!room) room = Rooms.global;
+ let usedRoom: ChatRoom | GameRoom | GlobalRoom = room;
+ if (usedRoom?.roomid === 'staff' && !this.runBroadcast()) return;
+ if (!usedRoom) usedRoom = Rooms.global;
const targetUser = this.targetUserOrSelf(target, user.group === ' ');
const showAll = (cmd === 'ip' || cmd === 'whoare' || cmd === 'alt' || cmd === 'alts');
if (!targetUser) {
@@ -37,14 +33,16 @@ const commands = {
let buf = Chat.html`${targetUser.group}${targetUser.name} `;
const ac = targetUser.autoconfirmed;
- if (ac && showAll) buf += ` (ac${targetUser.id === ac ? `` : `: ${ac}`})`;
+ if (ac && showAll) {
+ buf += ` (ac${targetUser.id === ac ? `` : `: ${ac}`})`;
+ }
const trusted = targetUser.trusted;
if (trusted && showAll) {
buf += ` (trusted${targetUser.id === trusted ? `` : `: ${trusted}`})`;
}
if (!targetUser.connected) buf += ` (offline)`;
let roomauth = '';
- if (room.auth && targetUser.id in room.auth) roomauth = room.auth[targetUser.id];
+ if (usedRoom.auth && targetUser.id in usedRoom.auth) roomauth = usedRoom.auth[targetUser.id];
if (Config.groups[roomauth] && Config.groups[roomauth].name) {
buf += `
${Config.groups[roomauth].name} (${roomauth})`;
}
@@ -57,42 +55,43 @@ const commands = {
if (!targetUser.registered) {
buf += `
(Unregistered)`;
}
- let publicrooms = "";
- let hiddenrooms = "";
- let privaterooms = "";
+ let publicrooms = ``;
+ let hiddenrooms = ``;
+ let privaterooms = ``;
for (const roomid of targetUser.inRooms) {
if (roomid === 'global') continue;
- const targetRoom = Rooms.get(roomid);
+ const targetRoom = Rooms.get(roomid)!;
const authSymbol = (targetRoom.auth && targetRoom.auth[targetUser.id] ? targetRoom.auth[targetUser.id] : '');
- const battleTitle = (roomid.battle ? ` title="${roomid.title}"` : '');
+ const battleTitle = (targetRoom.battle ? ` title="${targetRoom.title}"` : '');
const output = `${authSymbol}${roomid}`;
if (targetRoom.isPrivate === true) {
if (targetRoom.modjoin === '~') continue;
- if (privaterooms) privaterooms += " | ";
+ if (privaterooms) privaterooms += ` | `;
privaterooms += output;
} else if (targetRoom.isPrivate) {
- if (hiddenrooms) hiddenrooms += " | ";
+ if (hiddenrooms) hiddenrooms += ` | `;
hiddenrooms += output;
} else {
- if (publicrooms) publicrooms += " | ";
+ if (publicrooms) publicrooms += ` | `;
publicrooms += output;
}
}
- buf += '
Rooms: ' + (publicrooms || '(no public rooms)');
+ buf += `
Rooms: ${publicrooms || `(no public rooms)`}`;
if (!showAll) {
return this.sendReplyBox(buf);
}
const canViewAlts = (user === targetUser || user.can('alts', targetUser));
- const canViewPunishments = canViewAlts || (room.isPrivate !== true && user.can('mute', targetUser, room) && targetUser.id in room.users);
+ const canViewPunishments = canViewAlts ||
+ (usedRoom.isPrivate !== true && user.can('mute', targetUser, usedRoom) && targetUser.id in usedRoom.users);
const canViewSecretRooms = user === targetUser || (canViewAlts && targetUser.locked) || user.can('makeroom');
- buf += '
';
+ buf += `
`;
if (canViewAlts) {
let prevNames = Object.keys(targetUser.prevNames).map(userid => {
const punishment = Punishments.userids.get(userid);
- return userid + (punishment ? ` (${Punishments.punishmentTypes.get(punishment[0]) || 'punished'}${punishment[1] !== targetUser.id ? ` as ${punishment[1]}` : ''})` : '');
+ return `${userid}${punishment ? ` (${Punishments.punishmentTypes.get(punishment[0]) || `punished`}${punishment[1] !== targetUser.id ? ` as ${punishment[1]}` : ``})` : ``}`;
}).join(", ");
if (prevNames) buf += Chat.html`
Previous names: ${prevNames}`;
@@ -101,12 +100,13 @@ const commands = {
if (targetAlt.group === '~' && user.group !== '~') continue;
const punishment = Punishments.userids.get(targetAlt.id);
- const punishMsg = punishment ? ` (${Punishments.punishmentTypes.get(punishment[0]) || 'punished'}${punishment[1] !== targetAlt.id ? ` as ${punishment[1]}` : ''})` : '';
+ const punishMsg = punishment ? ` (${Punishments.punishmentTypes.get(punishment[0]) || 'punished'}` +
+ `${punishment[1] !== targetAlt.id ? ` as ${punishment[1]}` : ''})` : '';
buf += Chat.html`
Alt: ${targetAlt.name}${punishMsg}`;
if (!targetAlt.connected) buf += ` (offline)`;
prevNames = Object.keys(targetAlt.prevNames).map(userid => {
- const punishment = Punishments.userids.get(userid);
- return userid + (punishment ? ` (${Punishments.punishmentTypes.get(punishment[0]) || 'punished'}${punishment[1] !== targetAlt.id ? ` as ${punishment[1]}` : ''})` : '');
+ const p = Punishments.userids.get(userid);
+ return `${userid}${p ? ` (${Punishments.punishmentTypes.get(p[0]) || 'punished'}${p[1] !== targetAlt.id ? ` as ${p[1]}` : ``})` : ``}`;
}).join(", ");
if (prevNames) buf += `
Previous names: ${prevNames}`;
}
@@ -114,7 +114,7 @@ const commands = {
if (canViewPunishments) {
if (targetUser.namelocked) {
buf += `
NAMELOCKED: ${targetUser.namelocked}`;
- const punishment = Punishments.userids.get(targetUser.locked);
+ const punishment = Punishments.userids.get(targetUser.locked!);
if (punishment) {
const expiresIn = Punishments.checkLockExpiration(targetUser.locked);
if (expiresIn) buf += expiresIn;
@@ -142,7 +142,7 @@ const commands = {
buf += `
BATTLEBANNED: ${battlebanned[1]}`;
const expiresIn = new Date(battlebanned[2]).getTime() - Date.now();
const expiresDays = Math.round(expiresIn / 1000 / 60 / 60 / 24);
- let expiresText = '';
+ let expiresText = ``;
if (expiresDays >= 1) {
expiresText = `in around ${Chat.count(expiresDays, "days")}`;
} else {
@@ -190,21 +190,21 @@ const commands = {
}
const gameRooms = [];
- for (const room of Rooms.rooms.values()) {
- if (!room.game) continue;
- if ((targetUser.id in room.game.playerTable && !targetUser.inRooms.has(room.roomid)) ||
- (room.auth && room.auth[targetUser.id] === Users.PLAYER_SYMBOL)) {
- if (room.isPrivate && !canViewAlts) {
+ for (const curRoom of Rooms.rooms.values()) {
+ if (!curRoom.game) continue;
+ if ((targetUser.id in curRoom.game.playerTable && !targetUser.inRooms.has(curRoom.roomid)) ||
+ (curRoom.auth && curRoom.auth[targetUser.id] === Users.PLAYER_SYMBOL)) {
+ if (curRoom.isPrivate && !canViewAlts) {
continue;
}
- gameRooms.push(room.roomid);
+ gameRooms.push(curRoom.roomid);
}
}
if (gameRooms.length) {
- buf += '
Recent games: ' + gameRooms.map(id => {
+ buf += `
Recent games: ${gameRooms.map(id => {
const shortId = id.startsWith('battle-') ? id.slice(7) : id;
return Chat.html`${shortId}`;
- }).join(' | ');
+ }).join(' | ')}`;
}
if (canViewPunishments) {
@@ -213,8 +213,8 @@ const commands = {
if (punishments.length) {
buf += `
Room punishments: `;
- buf += punishments.map(([room, punishment]) => {
- const [punishType, punishUserid, expireTime, reason] = punishment;
+ buf += punishments.map(([curRoom, curPunishment]) => {
+ const [punishType, punishUserid, expireTime, reason] = curPunishment;
let punishDesc = Punishments.roomPunishmentTypes.get(punishType);
if (!punishDesc) punishDesc = `punished`;
if (punishUserid !== targetUser.id) punishDesc += ` as ${punishUserid}`;
@@ -223,7 +223,7 @@ const commands = {
punishDesc += ` for ${expireString}`;
if (reason) punishDesc += `: ${reason}`;
- return `${room} (${punishDesc})`;
+ return `${curRoom} (${punishDesc})`;
}).join(', ');
}
}
@@ -248,7 +248,7 @@ const commands = {
if (!targetUser || !targetUser.connected) buf += ` (offline)`;
let roomauth = '';
- if (room && room.auth && userid in room.auth) roomauth = room.auth[userid];
+ if (room?.auth && userid in room.auth) roomauth = room.auth[userid];
if (Config.groups[roomauth] && Config.groups[roomauth].name) {
buf += `
${Config.groups[roomauth].name} (${roomauth})`;
}
@@ -279,13 +279,13 @@ const commands = {
}
}
- const punishments = Punishments.getRoomPunishments(targetUser || {id: userid});
+ const punishments = Punishments.getRoomPunishments(targetUser || {id: userid} as User);
- if (punishments && punishments.length) {
+ if (punishments?.length) {
buf += `
Room punishments: `;
- buf += punishments.map(([room, punishment]) => {
- const [punishType, punishUserid, expireTime, reason] = punishment;
+ buf += punishments.map(([curRoom, curPunishment]) => {
+ const [punishType, punishUserid, expireTime, reason] = curPunishment;
let punishDesc = Punishments.roomPunishmentTypes.get(punishType);
if (!punishDesc) punishDesc = `punished`;
if (punishUserid !== userid) punishDesc += ` as ${punishUserid}`;
@@ -294,7 +294,7 @@ const commands = {
punishDesc += ` for ${expireString}`;
if (reason) punishDesc += `: ${reason}`;
- return `${room} (${punishDesc})`;
+ return `${curRoom} (${punishDesc})`;
}).join(', ');
atLeastOne = true;
}
@@ -315,11 +315,11 @@ const commands = {
const userID2 = toID(targetUsername2);
const battles = [];
- for (const room of Rooms.rooms.values()) {
- if (!room.battle) continue;
- if ((user1 && user1.inRooms.has(room.roomid) || (room.auth && room.auth[userID1])) &&
- (user2 && user2.inRooms.has(room.roomid) || (room.auth && room.auth[userID2]))) {
- battles.push(room.roomid);
+ for (const curRoom of Rooms.rooms.values()) {
+ if (!curRoom.battle) continue;
+ if ((user1?.inRooms.has(curRoom.roomid) || (curRoom.auth && curRoom.auth[userID1])) &&
+ (user2?.inRooms.has(curRoom.roomid) || (curRoom.auth && curRoom.auth[userID2]))) {
+ battles.push(curRoom.roomid);
}
}
@@ -334,7 +334,9 @@ const commands = {
sp: 'showpunishments',
showpunishments(target, room, user) {
- if (!room.chatRoomData || room.roomid.includes('-')) return this.errorReply("This command is unavailable in temporary rooms.");
+ if (!room.chatRoomData || room.roomid.includes('-')) {
+ return this.errorReply("This command is unavailable in temporary rooms.");
+ }
return this.parse(`/join view-punishments-${room}`);
},
showpunishmentshelp: [`/showpunishments - Shows the current punishments in the room. Requires: % @ # & ~`],
@@ -352,7 +354,7 @@ const commands = {
if (!this.can('ip')) return;
target = target.trim();
if (!net.isIPv4(target)) return this.errorReply('You must pass a valid IPv4 IP to /host.');
- IPTools.lookup(target).then(({dnsbl, host, hostType}) => {
+ void IPTools.lookup(target).then(({dnsbl, host, hostType}) => {
const dnsblMessage = dnsbl ? ` [${dnsbl}]` : ``;
this.sendReply(`IP ${target}: ${host || "ERROR"} [${hostType}]${dnsblMessage}`);
});
@@ -369,8 +371,10 @@ const commands = {
let [ip, roomid] = this.splitOne(target);
const targetRoom = roomid ? Rooms.get(roomid) : null;
- if (!targetRoom && targetRoom !== null) return this.errorReply(`The room "${roomid}" does not exist.`);
- const results = /** @type {string[]} */ ([]);
+ if (typeof targetRoom === 'undefined') {
+ return this.errorReply(`The room "${roomid}" does not exist.`);
+ }
+ const results: string[] = [];
const isAll = (cmd === 'ipsearchall');
if (/[a-z]/.test(ip)) {
@@ -380,7 +384,7 @@ const commands = {
if (results.length > 100 && !isAll) continue;
if (!curUser.latestHost || !curUser.latestHost.endsWith(ip)) continue;
if (targetRoom && !curUser.inRooms.has(targetRoom.roomid)) continue;
- results.push((curUser.connected ? " \u25C9 " : " \u25CC ") + " " + curUser.name);
+ results.push(`${curUser.connected ? ` \u25C9 ` : ` \u25CC `} ${curUser.name}`);
}
if (results.length > 100 && !isAll) {
return this.sendReply(`More than 100 users match the specified IP range. Use /ipsearchall to retrieve the full list.`);
@@ -393,7 +397,7 @@ const commands = {
if (results.length > 100 && !isAll) continue;
if (!curUser.latestIp.startsWith(ip)) continue;
if (targetRoom && !curUser.inRooms.has(targetRoom.roomid)) continue;
- results.push((curUser.connected ? " \u25C9 " : " \u25CC ") + " " + curUser.name);
+ results.push(`${curUser.connected ? ` \u25C9 ` : ` \u25CC `} ${curUser.name}`);
}
if (results.length > 100 && !isAll) {
return this.sendReply(`More than 100 users match the specified IP range. Use /ipsearchall to retrieve the full list.`);
@@ -403,7 +407,7 @@ const commands = {
for (const curUser of Users.users.values()) {
if (curUser.latestIp !== ip) continue;
if (targetRoom && !curUser.inRooms.has(targetRoom.roomid)) continue;
- results.push((curUser.connected ? " \u25C9 " : " \u25CC ") + " " + curUser.name);
+ results.push(`${curUser.connected ? ` \u25C9 ` : ` \u25CC `} ${curUser.name}`);
}
}
if (!results.length) {
@@ -425,7 +429,7 @@ const commands = {
const user1 = this.targetUser;
const user2 = Users.get(target);
if (!user1 || !user2 || user1 === user2) return this.parse(`/help checkchallenges`);
- if (!(user1 in room.users) || !(user2 in room.users)) {
+ if (!(user1.id in room.users) || !(user2.id in room.users)) {
return this.errorReply(`Both users must be in this room.`);
}
const challenges = [];
@@ -460,7 +464,9 @@ const commands = {
unignore: 'ignore',
ignore(target, room, user) {
- if (!room) this.errorReply(`In PMs, this command can only be used by itself to ignore the person you're talking to: "/${this.cmd}", not "/${this.cmd} ${target}"`);
+ if (!room) {
+ this.errorReply(`In PMs, this command can only be used by itself to ignore the person you're talking to: "/${this.cmd}", not "/${this.cmd} ${target}"`);
+ }
this.errorReply(`You're using a custom client that doesn't support the ignore command.`);
},
@@ -483,7 +489,7 @@ const commands = {
const targetId = toID(target);
if (!targetId) return this.parse('/help data');
const targetNum = parseInt(target);
- if (!isNaN(targetNum) && '' + targetNum === target) {
+ if (!isNaN(targetNum) && `${targetNum}` === target) {
for (const p in Dex.data.Pokedex) {
const pokemon = Dex.getSpecies(p);
if (pokemon.num === targetNum) {
@@ -493,8 +499,7 @@ const commands = {
}
}
let dex = Dex;
- /** @type {Format?} */
- let format = null;
+ let format: Format | null = null;
if (sep[1] && toID(sep[1]) in Dex.dexes) {
dex = Dex.mod(toID(sep[1]));
} else if (sep[1]) {
@@ -503,7 +508,7 @@ const commands = {
return this.errorReply(`Unrecognized format or mod "${format.name}"`);
}
dex = Dex.mod(format.mod);
- } else if (room && room.battle) {
+ } else if (room?.battle) {
format = Dex.getFormat(room.battle.format);
dex = Dex.mod(format.mod);
}
@@ -517,30 +522,34 @@ const commands = {
if (newTarget.isInexact && !i) {
buffer = `No Pok\u00e9mon, item, move, ability or nature named '${target}' was found${Dex.gen > dex.gen ? ` in Gen ${dex.gen}` : ""}. Showing the data of '${newTargets[0].name}' instead.\n`;
}
- /** @type {AnyObject} */
- let details = null;
+ let details: {[k: string]: string} = {};
switch (newTarget.searchType) {
case 'nature':
const nature = Dex.getNature(newTarget.name);
- buffer += "" + nature.name + " nature: ";
+ buffer += `${nature.name} nature: `;
if (nature.plus) {
- const statNames = {'atk': "Attack", 'def': "Defense", 'spa': "Special Attack", 'spd': "Special Defense", 'spe': "Speed"};
- buffer += "+10% " + statNames[nature.plus] + ", -10% " + statNames[nature.minus] + ".";
+ const statNames = {
+ atk: "Attack", def: "Defense", spa: "Special Attack", spd: "Special Defense", spe: "Speed",
+ };
+ buffer += `+10% ${statNames[nature.plus]}, -10% ${statNames[nature.minus!]}.`;
} else {
- buffer += "No effect.";
+ buffer += `No effect.`;
}
return this.sendReply(buffer);
case 'pokemon':
let pokemon = dex.getSpecies(newTarget.name);
- if (format && format.onModifySpecies) {
- pokemon = format.onModifySpecies.call({dex}, pokemon) || pokemon;
+ if (format?.onModifySpecies) {
+ pokemon = format.onModifySpecies.call({dex} as Battle, pokemon) || pokemon;
}
- let tier = pokemon.tier;
- if (room && (room.roomid === 'smogondoubles' ||
- ['gen7doublesou', 'gen7doublesubers', 'gen7doublesuu'].includes(room.battle && room.battle.format))) {
- tier = pokemon.doublesTier;
+ let displayedTier = pokemon.tier;
+ if (room?.battle) {
+ if (room.battle.format.includes('doubles') || room.battle.format.includes('vgc')) {
+ displayedTier = pokemon.doublesTier;
+ } else if (room.battle.format.includes('nationaldex')) {
+ displayedTier = pokemon.num >= 0 ? String(pokemon.num) : pokemon.tier;
+ }
}
- buffer += `|raw|${Chat.getDataPokemonHTML(pokemon, dex.gen, tier)}\n`;
+ buffer += `|raw|${Chat.getDataPokemonHTML(pokemon, dex.gen, displayedTier)}\n`;
if (showDetails) {
let weighthit = 20;
if (pokemon.weighthg >= 2000) {
@@ -555,16 +564,19 @@ const commands = {
weighthit = 40;
}
details = {
- "Dex#": pokemon.num,
- "Gen": pokemon.gen || 'CAP',
- "Height": pokemon.heightm + " m",
+ "Dex#": String(pokemon.num),
+ Gen: String(pokemon.gen) || 'CAP',
+ Height: `${pokemon.heightm} m`,
};
- if (!pokemon.forme || pokemon.forme !== "Gmax") details["Weight"] = pokemon.weighthg / 10 + " kg (" + weighthit + " BP)";
- else details["Weight"] = "0 kg (GK/LK fail)";
+ if (!pokemon.forme || pokemon.forme !== "Gmax") {
+ details["Weight"] = `${pokemon.weighthg / 10} kg (${weighthit} BP)`;
+ } else {
+ details["Weight"] = "0 kg (GK/LK fail)";
+ }
if (pokemon.isGigantamax) details["G-Max Move"] = pokemon.isGigantamax;
if (pokemon.color && dex.gen >= 5) details["Dex Colour"] = pokemon.color;
if (pokemon.eggGroups && dex.gen >= 2) details["Egg Group(s)"] = pokemon.eggGroups.join(", ");
- const evos = /** @type {string[]} */ ([]);
+ const evos: string[] = [];
for (const evoName of pokemon.evos) {
const evo = dex.getSpecies(evoName);
if (evo.gen <= dex.gen) {
@@ -597,7 +609,7 @@ const commands = {
}
}
if (!evos.length) {
- details['Does Not Evolve'] = "";
+ details[`Does Not Evolve`] = "";
} else {
details["Evolution"] = evos.join(", ");
}
@@ -608,27 +620,30 @@ const commands = {
buffer += `|raw|${Chat.getDataItemHTML(item)}\n`;
if (showDetails) {
details = {
- "Gen": item.gen,
+ Gen: String(item.gen),
};
if (dex.gen >= 4) {
if (item.fling) {
- details["Fling Base Power"] = item.fling.basePower;
+ details["Fling Base Power"] = String(item.fling.basePower);
if (item.fling.status) details["Fling Effect"] = item.fling.status;
if (item.fling.volatileStatus) details["Fling Effect"] = item.fling.volatileStatus;
if (item.isBerry) details["Fling Effect"] = "Activates the Berry's effect on the target.";
if (item.id === 'whiteherb') details["Fling Effect"] = "Restores the target's negative stat stages to 0.";
- if (item.id === 'mentalherb') details["Fling Effect"] = "Removes the effects of Attract, Disable, Encore, Heal Block, Taunt, and Torment from the target.";
+ if (item.id === 'mentalherb') {
+ const flingEffect = "Removes the effects of Attract, Disable, Encore, Heal Block, Taunt, and Torment from the target.";
+ details["Fling Effect"] = flingEffect;
+ }
} else {
details["Fling"] = "This item cannot be used with Fling.";
}
}
if (item.naturalGift && dex.gen >= 3) {
details["Natural Gift Type"] = item.naturalGift.type;
- details["Natural Gift Base Power"] = item.naturalGift.basePower;
+ details["Natural Gift Base Power"] = String(item.naturalGift.basePower);
}
if (item.isNonstandard) {
- details["Unobtainable in Gen " + dex.gen] = "";
+ details[`Unobtainable in Gen ${dex.gen}`] = "";
}
}
break;
@@ -637,8 +652,8 @@ const commands = {
buffer += `|raw|${Chat.getDataMoveHTML(move)}\n`;
if (showDetails) {
details = {
- "Priority": move.priority,
- "Gen": move.gen || 'CAP',
+ Priority: String(move.priority),
+ Gen: String(move.gen) || 'CAP',
};
if (move.isNonstandard === "Past" && dex.gen >= 8) details["✗ Past Gens Only"] = "";
@@ -662,30 +677,35 @@ const commands = {
if (dex.gen >= 7) {
if (move.gen >= 8 && move.isMax) {
// Don't display Z-Power for Max/G-Max moves
- } else if (move.zMove && move.zMove.basePower) {
- details["Z-Power"] = move.zMove.basePower;
- } else if (move.zMove && move.zMove.effect) {
- details["Z-Effect"] = {
- 'clearnegativeboost': "Restores negative stat stages to 0",
- 'crit2': "Crit ratio +2",
- 'heal': "Restores HP 100%",
- 'curse': "Restores HP 100% if user is Ghost type, otherwise Attack +1",
- 'redirect': "Redirects opposing attacks to user",
- 'healreplacement': "Restores replacement's HP 100%",
- }[move.zMove.effect];
- } else if (move.zMove && move.zMove.boost) {
+ } else if (move.zMove?.basePower) {
+ details["Z-Power"] = String(move.zMove.basePower);
+ } else if (move.zMove?.effect) {
+ const zEffects: {[k: string]: string} = {
+ clearnegativeboost: "Restores negative stat stages to 0",
+ crit2: "Crit ratio +2",
+ heal: "Restores HP 100%",
+ curse: "Restores HP 100% if user is Ghost type, otherwise Attack +1",
+ redirect: "Redirects opposing attacks to user",
+ healreplacement: "Restores replacement's HP 100%",
+ };
+ details["Z-Effect"] = zEffects[move.zMove.effect];
+ } else if (move.zMove?.boost) {
details["Z-Effect"] = "";
const boost = move.zMove.boost;
- const stats = {atk: 'Attack', def: 'Defense', spa: 'Sp. Atk', spd: 'Sp. Def', spe: 'Speed', accuracy: 'Accuracy', evasion: 'Evasiveness'};
- for (const i in boost) {
- details["Z-Effect"] += " " + stats[i] + " +" + boost[i];
+ const stats: {[k in BoostName]: string} = {
+ atk: 'Attack', def: 'Defense', spa: 'Sp. Atk', spd: 'Sp. Def', spe: 'Speed', accuracy: 'Accuracy', evasion: 'Evasiveness',
+ };
+ let h: BoostName;
+ for (h in boost) {
+ details["Z-Effect"] += ` ${stats[h]} +${boost[h]}`;
}
- } else if (move.isZ) {
+ } else if (move.isZ && typeof move.isZ === 'string') {
details["✓ Z-Move"] = "";
- details["Z-Crystal"] = dex.getItem(move.isZ).name;
- if (move.basePower !== 1) {
- details["User"] = dex.getItem(move.isZ).itemUser.join(", ");
- details["Required Move"] = dex.getItem(move.isZ).zMoveFrom;
+ const zCrystal = dex.getItem(move.isZ);
+ details["Z-Crystal"] = zCrystal.name;
+ if (zCrystal.itemUser) {
+ details["User"] = zCrystal.itemUser.join(", ");
+ details["Required Move"] = dex.getItem(move.isZ).zMoveFrom!;
}
} else {
details["Z-Effect"] = "None";
@@ -695,26 +715,27 @@ const commands = {
if (dex.gen >= 8) {
if (move.isMax) {
details["✓ Max Move"] = "";
- if (typeof move.isMax === "string") details["User"] = move.isMax + "-Gmax";
- } else if (move.maxMove && move.maxMove.basePower) {
- details["Dynamax Power"] = move.maxMove.basePower;
+ if (typeof move.isMax === "string") details["User"] = `${move.isMax}-Gmax`;
+ } else if (move.maxMove?.basePower) {
+ details["Dynamax Power"] = String(move.maxMove.basePower);
}
}
- details["Target"] = {
- 'normal': "One Adjacent Pok\u00e9mon",
- 'self': "User",
- 'adjacentAlly': "One Ally",
- 'adjacentAllyOrSelf': "User or Ally",
- 'adjacentFoe': "One Adjacent Opposing Pok\u00e9mon",
- 'allAdjacentFoes': "All Adjacent Opponents",
- 'foeSide': "Opposing Side",
- 'allySide': "User's Side",
- 'allyTeam': "User's Side",
- 'allAdjacent': "All Adjacent Pok\u00e9mon",
- 'any': "Any Pok\u00e9mon",
- 'all': "All Pok\u00e9mon",
- }[move.target] || "Unknown";
+ const targetTypes: {[k: string]: string} = {
+ normal: "One Adjacent Pok\u00e9mon",
+ self: "User",
+ adjacentAlly: "One Ally",
+ adjacentAllyOrSelf: "User or Ally",
+ adjacentFoe: "One Adjacent Opposing Pok\u00e9mon",
+ allAdjacentFoes: "All Adjacent Opponents",
+ foeSide: "Opposing Side",
+ allySide: "User's Side",
+ allyTeam: "User's Side",
+ allAdjacent: "All Adjacent Pok\u00e9mon",
+ any: "Any Pok\u00e9mon",
+ all: "All Pok\u00e9mon",
+ };
+ details["Target"] = targetTypes[move.target] || "Unknown";
if (move.id === 'snatch' && dex.gen >= 3) {
details[`Non-Snatchable Moves`] = '';
@@ -723,23 +744,28 @@ const commands = {
details[`Non-Mirrorable Moves`] = '';
}
if (move.isNonstandard === 'Unobtainable') {
- details["Unobtainable in Gen " + dex.gen] = "";
+ details[`Unobtainable in Gen ${dex.gen}`] = "";
}
}
break;
case 'ability':
const ability = dex.getAbility(newTarget.name);
buffer += `|raw|${Chat.getDataAbilityHTML(ability)}\n`;
+ if (showDetails) {
+ details = {
+ Gen: String(ability.gen) || 'CAP',
+ };
+ }
break;
default:
throw new Error(`Unrecognized searchType`);
}
if (details) {
- buffer += '|raw|' + Object.keys(details).map(detail => {
+ buffer += `|raw|${Object.keys(details).map(detail => {
if (details[detail] === '') return detail;
- return '' + detail + ': ' + details[detail];
- }).join(" |  ") + '\n';
+ return `${detail}: ${details[detail]}`;
+ }).join(" |  ")}\n`;
}
}
this.sendReply(buffer);
@@ -772,23 +798,21 @@ const commands = {
target = target.trim();
const modName = target.split(',');
let mod = Dex;
- /** @type {Format?} */
- let format = null;
+ let format: Format | null = null;
if (modName[modName.length - 1] && toID(modName[modName.length - 1]) in Dex.dexes) {
mod = Dex.mod(toID(modName[modName.length - 1]));
- } else if (room && room.battle) {
+ } else if (room?.battle) {
format = Dex.getFormat(room.battle.format);
mod = Dex.mod(format.mod);
}
const targets = target.split(/ ?[,/] ?/);
- /** @type {{types: string[], [k: string]: any}} */
- let species = mod.getSpecies(targets[0]);
+ let species: {types: string[], [k: string]: any} = mod.getSpecies(targets[0]);
const type1 = mod.getType(targets[0]);
const type2 = mod.getType(targets[1]);
const type3 = mod.getType(targets[2]);
if (species.exists) {
- target = species.species;
+ target = species.name;
} else {
const types = [];
if (type1.exists) {
@@ -820,19 +844,19 @@ const commands = {
weaknesses.push(type);
break;
case 2:
- weaknesses.push("" + type + "");
+ weaknesses.push(`${type}`);
break;
case 3:
- weaknesses.push("" + type + "");
+ weaknesses.push(`${type}`);
break;
case -1:
resistances.push(type);
break;
case -2:
- resistances.push("" + type + "");
+ resistances.push(`${type}`);
break;
case -3:
- resistances.push("" + type + "");
+ resistances.push(`${type}`);
break;
}
} else {
@@ -841,10 +865,10 @@ const commands = {
}
const buffer = [];
- buffer.push(species.exists ? "" + species.name + ' (ignoring abilities):' : '' + target + ':');
- buffer.push(': ' + (weaknesses.join(', ') || 'None'));
- buffer.push(': ' + (resistances.join(', ') || 'None'));
- buffer.push(': ' + (immunities.join(', ') || 'None'));
+ buffer.push(`${species.exists ? `${species.name} (ignoring abilities):` : `${target}:`}`);
+ buffer.push(`: ${weaknesses.join(', ') || 'None'}`);
+ buffer.push(`: ${resistances.join(', ') || 'None'}`);
+ buffer.push(`: ${immunities.join(', ') || 'None'}`);
this.sendReplyBox(buffer.join('
'));
},
weaknesshelp: [
@@ -865,13 +889,21 @@ const commands = {
let searchMethods = ['getType', 'getMove', 'getSpecies'];
const sourceMethods = ['getType', 'getMove'];
const targetMethods = ['getType', 'getSpecies'];
- let source, defender, foundData, atkName, defName;
+ let source;
+ let defender;
+ let foundData;
+ let atkName;
+ let defName;
+ const dex: any = Dex;
for (let i = 0; i < 2; ++i) {
- let method;
- for (method of searchMethods) {
- foundData = Dex[method](targets[i]);
- if (foundData.exists) break;
+ let method!: string;
+ for (const m of searchMethods) {
+ foundData = dex[m](targets[i]);
+ if (foundData.exists) {
+ method = m;
+ break;
+ }
}
if (!foundData.exists) return this.parse('/help effectiveness');
if (!source && sourceMethods.includes(method)) {
@@ -886,7 +918,7 @@ const commands = {
} else if (!defender && targetMethods.includes(method)) {
if (foundData.types) {
defender = foundData;
- defName = foundData.species + " (not counting abilities)";
+ defName = `${foundData.species} (not counting abilities)`;
} else {
defender = {types: [foundData.name]};
defName = foundData.name;
@@ -898,12 +930,13 @@ const commands = {
if (!this.runBroadcast()) return;
let factor = 0;
- if (Dex.getImmunity(source, defender) || source.ignoreImmunity && (source.ignoreImmunity === true || source.ignoreImmunity[source.type])) {
+ if (Dex.getImmunity(source, defender) ||
+ source.ignoreImmunity && (source.ignoreImmunity === true || source.ignoreImmunity[source.type])) {
let totalTypeMod = 0;
if (source.effectType !== 'Move' || source.category !== 'Status' && (source.basePower || source.basePowerCallback)) {
for (const type of defender.types) {
const baseMod = Dex.getEffectiveness(source, type);
- const moveMod = source.onEffectiveness && source.onEffectiveness.call({dex: Dex}, baseMod, null, type, source);
+ const moveMod = source.onEffectiveness?.call({dex: Dex} as Battle, baseMod, null, type, source);
totalTypeMod += typeof moveMod === 'number' ? moveMod : baseMod;
}
}
@@ -913,7 +946,7 @@ const commands = {
const hasThousandArrows = source.id === 'thousandarrows' && defender.types.includes('Flying');
const additionalInfo = hasThousandArrows ? "
However, Thousand Arrows will be 1x effective on the first hit." : "";
- this.sendReplyBox("" + atkName + " is " + factor + "x effective against " + defName + "." + additionalInfo);
+ this.sendReplyBox(`${atkName} is ${factor}x effective against ${defName}.${additionalInfo}`);
},
effectivenesshelp: [
`/effectiveness [attack], [defender] - Provides the effectiveness of a move or type on another type or a Pok\u00e9mon.`,
@@ -927,9 +960,9 @@ const commands = {
if (!target) return this.parse("/help coverage");
const targets = target.split(/[,+]/);
- const sources = [];
+ const sources: (string | Move)[] = [];
let dex = Dex;
- if (room && room.battle) {
+ if (room?.battle) {
const format = Dex.getFormat(room.battle.format);
dex = Dex.mod(format.mod);
}
@@ -937,7 +970,7 @@ const commands = {
dex = Dex.mod(toID(targets[targets.length - 1]));
}
let dispTable = false;
- const bestCoverage = {};
+ const bestCoverage: {[k: string]: number} = {};
let hasThousandArrows = false;
for (const type in dex.data.TypeChart) {
@@ -988,7 +1021,7 @@ const commands = {
} else {
if (!dex.getImmunity(move.type, type) && !move.ignoreImmunity) continue;
const baseMod = dex.getEffectiveness(move, type);
- const moveMod = move.onEffectiveness && move.onEffectiveness.call({dex}, baseMod, null, type, move);
+ const moveMod = move.onEffectiveness?.call({dex} as Battle, baseMod, null, type, move as ActiveMove);
eff = typeof moveMod === 'number' ? moveMod : baseMod;
}
if (eff > bestCoverage[type]) bestCoverage[type] = eff;
@@ -1007,11 +1040,11 @@ const commands = {
}
if (!dispTable) {
- const buffer = [];
- const superEff = [];
- const neutral = [];
- const resists = [];
- const immune = [];
+ const buffer: string[] = [];
+ const superEff: string[] = [];
+ const neutral: string[] = [];
+ const resists: string[] = [];
+ const immune: string[] = [];
for (const type in bestCoverage) {
switch (bestCoverage[type]) {
@@ -1030,29 +1063,29 @@ const commands = {
superEff.push(type);
break;
default:
- throw new Error("/coverage effectiveness of " + bestCoverage[type] + " from parameters: " + target);
+ throw new Error(`/coverage effectiveness of ${bestCoverage[type]} from parameters: ${target}`);
}
}
- buffer.push('Coverage for ' + sources.join(' + ') + ':');
- buffer.push('Super Effective: ' + (superEff.join(', ') || 'None'));
- buffer.push(': ' + (neutral.join(', ') || 'None'));
- buffer.push(': ' + (resists.join(', ') || 'None'));
- buffer.push(': ' + (immune.join(', ') || 'None'));
+ buffer.push(`Coverage for ${sources.join(' + ')}:`);
+ buffer.push(`Super Effective: ${superEff.join(', ') || 'None'}`);
+ buffer.push(`: ${neutral.join(', ') || 'None'}`);
+ buffer.push(`: ${resists.join(', ') || 'None'}`);
+ buffer.push(`: ${immune.join(', ') || 'None'}`);
return this.sendReplyBox(buffer.join('
'));
} else {
let buffer = '
| '; - const icon = {}; + const icon: {[k: string]: string} = {}; for (const type in dex.data.TypeChart) { icon[type] = ` | ' + icon[type] + ' | '; + buffer += `${icon[type]} | `; } buffer += '|
|---|---|---|---|
| ' + icon[type1] + ' | '; + buffer += `|||
| ${icon[type1]} | `; for (const type2 in dex.data.TypeChart) { - let typing; + let typing: string; let cell = 'bestEff) bestEff = curEff; } @@ -1081,21 +1126,21 @@ const commands = { } switch (bestEff) { case 0: - cell += 'bgcolor=#666666 title="' + typing + '">' + bestEff + ''; + cell += `bgcolor=#666666 title="${typing}">${bestEff}`; break; case 0.25: case 0.5: - cell += 'bgcolor=#AA5544 title="' + typing + '">' + bestEff + ''; + cell += `bgcolor=#AA5544 title="${typing}">${bestEff}`; break; case 1: - cell += 'bgcolor=#6688AA title="' + typing + '">' + bestEff + ''; + cell += `bgcolor=#6688AA title="${typing}">${bestEff}`; break; case 2: case 4: - cell += 'bgcolor=#559955 title="' + typing + '">' + bestEff + ''; + cell += `bgcolor=#559955 title="${typing}">${bestEff}`; break; default: - throw new Error("/coverage effectiveness of " + bestEff + " from parameters: " + target); + throw new Error(`/coverage effectiveness of ${bestEff} from parameters: ${target}`); } cell += ' | '; buffer += cell; @@ -1107,7 +1152,7 @@ const commands = { buffer += "${sections[sectionId].name} | `); for (const section of sections[sectionId].formats) { - const format = Dex.getFormat(section); - const nameHTML = Chat.escapeHTML(format.name); - let desc = format.desc ? [format.desc] : []; - if (format.threads) desc = desc.concat(format.threads); + const subformat = Dex.getFormat(section); + const nameHTML = Chat.escapeHTML(subformat.name); + const desc = [...(subformat.desc ? [subformat.desc] : []), ...(subformat.threads || [])]; const descHTML = desc.length ? desc.join("|
| ${nameHTML} | ${descHTML} | ||