diff --git a/commands/pokedex/pokedex-ability.js b/commands/pokedex/pokedex-ability.js new file mode 100644 index 00000000..b926f4c1 --- /dev/null +++ b/commands/pokedex/pokedex-ability.js @@ -0,0 +1,48 @@ +const Command = require('../../structures/Command'); +const { MessageEmbed } = require('discord.js'); + +module.exports = class PokedexAbilityCommand extends Command { + constructor(client) { + super(client, { + name: 'pokedex-ability', + aliases: ['pokemon-ability', 'pokémon-ability', 'pokédex-ability', 'pkmn-ability'], + group: 'pokedex', + memberName: 'pokedex-ability', + description: 'Searches the Pokédex for a Pokémon ability.', + clientPermissions: ['EMBED_LINKS'], + credit: [ + { + name: 'Pokémon', + url: 'https://www.pokemon.com/us/', + reason: 'Original Game' + }, + { + name: 'PokéAPI', + url: 'https://pokeapi.co/', + reason: 'API' + } + ], + args: [ + { + key: 'ability', + prompt: 'What ability would you like to get information on?', + type: 'string' + } + ] + }); + } + + async run(msg, { ability }) { + try { + const data = await this.client.pokemon.abilities.fetch(ability); + if (!data) return msg.say('Could not find any results.'); + const embed = new MessageEmbed() + .setColor(0xED1C24) + .setTitle(data.name) + .setDescription(data.description); + return msg.embed(embed); + } catch (err) { + return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); + } + } +}; diff --git a/commands/pokedex/pokedex-move.js b/commands/pokedex/pokedex-move.js new file mode 100644 index 00000000..7b8cea23 --- /dev/null +++ b/commands/pokedex/pokedex-move.js @@ -0,0 +1,54 @@ +const Command = require('../../structures/Command'); +const { MessageEmbed } = require('discord.js'); + +module.exports = class PokedexMoveCommand extends Command { + constructor(client) { + super(client, { + name: 'pokedex-move', + aliases: ['pokemon-move', 'pokémon-move', 'pokédex-move', 'pkmn-move'], + group: 'pokedex', + memberName: 'pokedex-move', + description: 'Searches the Pokédex for a Pokémon move.', + clientPermissions: ['EMBED_LINKS'], + credit: [ + { + name: 'Pokémon', + url: 'https://www.pokemon.com/us/', + reason: 'Original Game' + }, + { + name: 'PokéAPI', + url: 'https://pokeapi.co/', + reason: 'API' + } + ], + args: [ + { + key: 'move', + prompt: 'What move would you like to get information on?', + type: 'string' + } + ] + }); + } + + async run(msg, { move }) { + try { + const data = await this.client.pokemon.moves.fetch(move); + if (!data) return msg.say('Could not find any results.'); + const embed = new MessageEmbed() + .setColor(0xED1C24) + .setTitle(data.name) + .setDescription(data.cleanDescription) + .addField('❯ Accuracy', `${data.accuracy}%`, true) + .addField('❯ Power', data.power, true) + .addField('❯ PP', data.pp, true) + .addField('❯ Type', data.type, true) + .addField('❯ Contest Type', data.contestType, true) + .addField('❯ Class', data.class, true); + return msg.embed(embed); + } catch (err) { + return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); + } + } +}; diff --git a/commands/pokedex/pokedex-moveset.js b/commands/pokedex/pokedex-moveset.js index 2cf09286..f06018e1 100644 --- a/commands/pokedex/pokedex-moveset.js +++ b/commands/pokedex/pokedex-moveset.js @@ -61,7 +61,7 @@ module.exports = class PokedexMovesetCommand extends Command { const embed = new MessageEmbed() .setColor(0xED1C24) .setAuthor(`#${data.displayID} - ${data.name}`, data.boxImageURL, data.serebiiURL) - .setDescription(data.moveSet.map(move => `**Level ${move.level}:** ${move.name}`).join('\n')) + .setDescription(data.moveSet.map(move => `**Level ${move.level}:** ${move.move.name}`).join('\n')) .setThumbnail(data.spriteImageURL) .setFooter(`Moveset data taken from ${versions[data.moveSetVersion]}.`); return msg.embed(embed); diff --git a/commands/pokedex/pokedex-stats.js b/commands/pokedex/pokedex-stats.js index 287d4b59..852adbfa 100644 --- a/commands/pokedex/pokedex-stats.js +++ b/commands/pokedex/pokedex-stats.js @@ -88,7 +88,7 @@ module.exports = class PokedexCommand extends Command { \`-----------------------------------\` \`Total: [${'█'.repeat(repeat.total)}${' '.repeat(20 - repeat.total)}]\` **${statTotal}** `) - .addField('❯ Abilities', variety.abilities.join('/')) + .addField('❯ Abilities', variety.abilities.map(ability => ability.name).join('/')) .addField('❯ Other Forms', stripIndents` _Use ${this.usage(`${data.id}
`)} to get stats for another form._ diff --git a/package.json b/package.json index 3a2ad1a5..c191fdc9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xiao", - "version": "126.10.0", + "version": "126.11.0", "description": "Your personal server companion.", "main": "Xiao.js", "scripts": { diff --git a/structures/pokemon/Ability.js b/structures/pokemon/Ability.js new file mode 100644 index 00000000..28e82144 --- /dev/null +++ b/structures/pokemon/Ability.js @@ -0,0 +1,13 @@ +const { firstUpperCase } = require('../../util/Util'); + +module.exports = class Ability { + constructor(store, data) { + this.store = store; + this.id = data.id; + const slugName = firstUpperCase(data.name).replaceAll('-', ' '); + this.name = data.names.length + ? data.names.find(entry => entry.language.name === 'en').name + : slugName; + this.description = data.effect_entries.find(entry => entry.language.name === 'en').effect; + } +}; diff --git a/structures/pokemon/AbilityStore.js b/structures/pokemon/AbilityStore.js new file mode 100644 index 00000000..b33d51b8 --- /dev/null +++ b/structures/pokemon/AbilityStore.js @@ -0,0 +1,29 @@ +const Collection = require('@discordjs/collection'); +const request = require('node-superfetch'); +const Ability = require('./Ability'); + +module.exports = class AbilityStore extends Collection { + constructor(options) { + super(options); + } + + async fetch(query) { + query = this.makeSlug(query); + if (!query) return null; + const found = this.find(pokemon => pokemon.slug === query); + if (found) return found; + try { + const { body } = await request.get(`https://pokeapi.co/api/v2/ability/${query}/`); + const ability = new Ability(this, body); + this.set(ability.id, ability); + return ability; + } catch (err) { + if (err.status === 404) return null; + throw err; + } + } + + makeSlug(query) { + return encodeURIComponent(query.toLowerCase().replaceAll(' ', '-').replace(/[^a-zA-Z0-9-]/g, '')); + } +}; diff --git a/structures/pokemon/Move.js b/structures/pokemon/Move.js new file mode 100644 index 00000000..3f267e64 --- /dev/null +++ b/structures/pokemon/Move.js @@ -0,0 +1,25 @@ +const { firstUpperCase } = require('../../util/Util'); + +module.exports = class Move { + constructor(store, data) { + this.store = store; + this.id = data.id; + const slugName = firstUpperCase(data.name).replaceAll('-', ' '); + this.name = data.names.length + ? data.names.find(entry => entry.language.name === 'en').name + : slugName; + this.description = data.effect_entries.find(entry => entry.language.name === 'en').effect; + this.accuracy = data.accuracy; + this.effectChance = data.effect_chance; + this.power = data.power; + this.pp = data.pp; + this.type = firstUpperCase(data.type.name); + this.contestType = firstUpperCase(data.contest_type.name); + this.class = firstUpperCase(data.damage_class.name); + } + + get cleanDescription() { + return this.description + .replace(/\$effect_chance/gi, this.effectChance); + } +}; diff --git a/structures/pokemon/MoveStore.js b/structures/pokemon/MoveStore.js new file mode 100644 index 00000000..74b356f4 --- /dev/null +++ b/structures/pokemon/MoveStore.js @@ -0,0 +1,29 @@ +const Collection = require('@discordjs/collection'); +const request = require('node-superfetch'); +const Move = require('./Move'); + +module.exports = class MoveStore extends Collection { + constructor(options) { + super(options); + } + + async fetch(query) { + query = this.makeSlug(query); + if (!query) return null; + const found = this.find(pokemon => pokemon.slug === query); + if (found) return found; + try { + const { body } = await request.get(`https://pokeapi.co/api/v2/move/${query}/`); + const move = new Move(this, body); + this.set(move.id, move); + return move; + } catch (err) { + if (err.status === 404) return null; + throw err; + } + } + + makeSlug(query) { + return encodeURIComponent(query.toLowerCase().replaceAll(' ', '-').replace(/[^a-zA-Z0-9-]/g, '')); + } +}; diff --git a/structures/pokemon/Pokemon.js b/structures/pokemon/Pokemon.js index 3fbad17f..b59ba0d4 100644 --- a/structures/pokemon/Pokemon.js +++ b/structures/pokemon/Pokemon.js @@ -179,8 +179,8 @@ module.exports = class Pokemon { const { body: defaultBody } = await request.get(`https://pokeapi.co/api/v2/pokemon/${defaultVariety.id}`); defaultVariety.types.push(...defaultBody.types.map(type => firstUpperCase(type.type.name))); for (const ability of defaultBody.abilities) { - const { body: defaultAbilityBody } = await request.get(ability.ability.url); - defaultVariety.abilities.push(defaultAbilityBody.names.find(name => name.language.name === 'en').name); + const defaultAbilityData = await this.store.abilities.fetch(ability.ability.id); + defaultVariety.abilities.push(defaultAbilityData); } defaultVariety.stats = { hp: defaultBody.stats.find(stat => stat.stat.name === 'hp').base_stat, @@ -226,8 +226,8 @@ module.exports = class Pokemon { || baseStats.sDef !== variety.stats.sDef || baseStats.spd !== variety.stats.spd; for (const ability of body.abilities) { - const { body: abilityBody } = await request.get(ability.ability.url); - variety.abilities.push(abilityBody.names.find(name => name.language.name === 'en').name); + const abilityData = await this.store.abilities.fetch(ability.ability.id); + variety.abilities.push(abilityData); } } return this.varieties; @@ -237,11 +237,10 @@ module.exports = class Pokemon { for (const move of moves) { const versionGroup = move.version_group_details.find(mve => mve.version_group.name === this.moveSetVersion); if (!versionGroup || !versionGroup.level_learned_at) continue; - const { body: moveBody } = await request.get(move.move.url); - const nme = moveBody.names.find(name => name.language.name === 'en').name; - if (this.moveSet.some(mve => mve.name === nme)) continue; + const moveData = await this.store.moves.fetch(move.id); + if (this.moveSet.some(mve => mve.move.id === moveData.id)) continue; this.moveSet.push({ - name: nme, + move: moveData, level: versionGroup.level_learned_at }); } diff --git a/structures/pokemon/PokemonStore.js b/structures/pokemon/PokemonStore.js index 99c04495..e30fa6f6 100644 --- a/structures/pokemon/PokemonStore.js +++ b/structures/pokemon/PokemonStore.js @@ -1,6 +1,8 @@ const Collection = require('@discordjs/collection'); const request = require('node-superfetch'); const Pokemon = require('./Pokemon'); +const MoveStore = require('./MoveStore'); +const AbilityStore = require('./AbilityStore'); const missingno = require('../../assets/json/missingno'); module.exports = class PokemonStore extends Collection { @@ -10,6 +12,8 @@ module.exports = class PokemonStore extends Collection { this.pokemonCount = 898; this.pokemonCountWithCry = 893; this.smogonData = {}; + this.moves = new MoveStore(); + this.abilities = new AbilityStore(); } async fetch(query) {