diff --git a/bot/assets/constants/typeColours.json b/bot/assets/constants/typeColours.json new file mode 100644 index 0000000..33885a9 --- /dev/null +++ b/bot/assets/constants/typeColours.json @@ -0,0 +1,20 @@ +{ + "Normal": "#A8A77A", + "Fire": "#EE8130", + "Water": "#6390F0", + "Electric": "#F7D02C", + "Grass": "#7AC74C", + "Ice": "#96D9D6", + "Fighting": "#C22E28", + "Poison": "#A33EA1", + "Ground": "#E2BF65", + "Flying": "#A98FF3", + "Psychic": "#F95587", + "Bug": "#A6B91A", + "Rock": "#B6A136", + "Ghost": "#735797", + "Dragon": "#6F35FC", + "Dark": "#705746", + "Steel": "#B7B7CE", + "Fairy": "#D685AD" +} \ No newline at end of file diff --git a/bot/commands/Fun/pokedex.js b/bot/commands/Fun/pokedex.js deleted file mode 100644 index 892d5c2..0000000 --- a/bot/commands/Fun/pokedex.js +++ /dev/null @@ -1,77 +0,0 @@ -const Embed = require('../../util/embed'); -const API = new (require('../../util/pokeapi')); - -module.exports = class { - constructor (name, category) { - this.name = name, - this.category = category, - this.enabled = true, - this.devOnly = false, - this.aliases = [], - this.userPerms = [], - this.botPerms = [], - this.cooldown = 2000, - this.help = { - description: '', - arguments: '', - details: '', - examples: '' - }; - } - - async run (client, message, args, data) { //eslint-disable-line no-unused-vars - - - let query = args.join(' '); - query = query.trim(); - - const pokemon = await API.fetchPokemon(args.join(' ')); - - const typeArray = []; - - for (let i = 0; i < pokemon.info.types.length; i++) { - typeArray.push(pokemon.info.types[i].type.name.toProperCase()); - } - - const abilityArray = []; - - for (let i = 0; i < pokemon.info.abilities.length; i++) { - let ability = pokemon.info.abilities[i].ability.name.toProperCase(); - if (pokemon.info.abilities[i].is_hidden === true) ability = `*${ability}*`; - abilityArray.push(ability); - } - - const evoArray = []; - - do { - const numberOfEvolutions = pokemon.evolutions.chain.evolves_to.length; - - evoArray.push(pokemon.evolutions.chain.species.name.toProperCase()); - - if (numberOfEvolutions > 1) { - for (let i = 1;i < numberOfEvolutions; i++) { - evoArray.push(pokemon.evolutions.chain.species.name.toProperCase()); - } - } - - pokemon.evolutions.chain = pokemon.evolutions.chain.evolves_to[0]; - - } while (pokemon.evolutions.chain != undefined && pokemon.evolutions.chain.hasOwnProperty('evolves_to')); //eslint-disable-line no-prototype-builtins - - - const filtered = pokemon.species.flavor_text_entries.filter(text => text.language.name === 'en'); - const description = filtered[0].flavor_text.replace(/(\r\n|\n|\r)/gm, ' ').replace(/\s+/g,' '); - const sprite = API.fetchSprite(query); - - - const embed = new Embed() - .setTitle(pokemon.info.name.toProperCase()) - .setThumbnail(sprite) - .setDescription(description.replace('\n', '')) - .addField('**Types:**', typeArray.join(', '), true) - .addField('**Abilities:**', abilityArray.join(', '), true); - if (evoArray.length > 1) embed.addField('**Evolution Chain:**', evoArray.join(' → ').replace(pokemon.species.name.toProperCase(), `**${pokemon.species.name.toProperCase()}**`)); - embed.addField('**Base Stats:**', `**HP:** ${pokemon.info.stats[0].base_stat} **Atk:** ${pokemon.info.stats[1].base_stat} **Def:** ${pokemon.info.stats[2].base_stat} **SpA:** ${pokemon.info.stats[3].base_stat} **SpD:** ${pokemon.info.stats[4].base_stat} **Spe:** ${pokemon.info.stats[5].base_stat}`); - message.channel.createMessage({ embed: embed }); - } -}; \ No newline at end of file diff --git a/bot/commands/Fun/pokemon.js b/bot/commands/Fun/pokemon.js new file mode 100644 index 0000000..d57efdf --- /dev/null +++ b/bot/commands/Fun/pokemon.js @@ -0,0 +1,176 @@ +const Embed = require('../../util/embed'); +const colours = require('../../assets/constants/typeColours.json'); +const fetch = require('node-fetch'); + +module.exports = class { + constructor (name, category) { + this.name = name, + this.category = category, + this.enabled = true, + this.devOnly = false, + this.aliases = ['pokedex', 'dex'], + this.userPerms = [], + this.botPerms = [], + this.cooldown = 2000, + this.help = { + description: '', + arguments: '', + details: '', + examples: '' + }; + } + + async run (client, message, args, data) { //eslint-disable-line no-unused-vars + + + let query = args.join(' '); + query = query.trim(); + + fetch('https://graphqlpokemon.favware.tech/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ query: ` + { + getPokemonDetails(pokemon: ${query}) { + num + species + types + abilities { first second hidden special } + baseStats { hp attack defense specialattack specialdefense speed } + eggGroups + evolutionLevel + evolutions { species evolutionLevel evolutions { species evolutionLevel } } + preevolutions { species evolutionLevel preevolutions { species evolutionLevel } } + gender { male female } + height + weight + otherFormes + cosmeticFormes + baseStatsTotal + flavorTexts { game flavor } + sprite + shinySprite + smogonTier + bulbapediaPage + serebiiPage + smogonPage + } + } + `}) + }) + .then((res) => res.json()) + .then((json) => { + const pokemon = json.data.getPokemonDetails; + const evoChain = this.parseEvoChain(pokemon); + const genderRatio = this.parseGenderRatio(pokemon.gender); + const abilities = this.parseAbilities(pokemon.abilities); + let sprite = pokemon.sprite; + if (Math.floor((Math.random() * 100) + 1) === 69) sprite = pokemon.shinySprite; + let formes = '(No Alternate Formes)'; + if (pokemon.otherFormes) { + formes = pokemon.otherFormes.join(', '); + if (pokemon.cosmeticFormes) { + formes = formes.split().concat(pokemon.cosmeticFormes); + } + } + const embed = new Embed() + .setColour(colours[pokemon.types[0]]) + .setTitle(`${pokemon.species.toProperCase()} (No. ${pokemon.num})`) + .setDescription(pokemon.flavorTexts[0].flavor) + .setThumbnail(sprite) + .addField('**Types:**', pokemon.types.join(', '), true) + .addField('**Abilities:**', abilities.join(', '), true) + .addField('**Gender Ratio:**', genderRatio, true) + .addField('**Base Stats:**', `**HP:** ${pokemon.baseStats.hp} **Atk:** ${pokemon.baseStats.attack} **Def:** ${pokemon.baseStats.defense} **SpA:** ${pokemon.baseStats.specialattack} **SpD:** ${pokemon.baseStats.specialdefense} **Spe:** ${pokemon.baseStats.speed} **BST:** ${pokemon.baseStatsTotal}`) + .addField('**Evolution Chain:**', evoChain) + .addField('**Other Formes:**', formes) + .addField('**Height:**', `${pokemon.height}m`, true) + .addField('**Weight:**', `${pokemon.weight}kg`, true) + .addField('**Egg Groups:**', pokemon.eggGroups.join(', '), true) + .addField('**Smogon Tier:**', pokemon.smogonTier, true) + .addField('**External Resources:**', `[Bulbapedia](${pokemon.bulbapediaPage}) | [Serebii](${pokemon.serebiiPage}) | [Smogon](${pokemon.smogonPage})`); + message.channel.createMessage({ embed: embed }); + }) + .catch(err => console.log(err)); + } + + constructEvoLink (species, level, evoChain, isEvo = true) { + if (isEvo) { + return `${evoChain} → \`${species.toProperCase()}\` ${level ? `(${level})` : ''}`; + } + return `\`${species.toProperCase()}\` ${level ? `(${level})` : ''} → ${evoChain}`; + } + + parseEvoChain (pokeDetails) { + // Set evochain if there are no evolutions + let evoChain = `**${pokeDetails.species.toProperCase()} ${pokeDetails.evolutionLevel ? `(${pokeDetails.evolutionLevel})` : ''}**`; + if (!pokeDetails.evolutions && !pokeDetails.preevolutions) { + evoChain += ' (No Evolutions)'; + } + + // Parse pre-evolutions and add to evochain + if (pokeDetails.preevolutions) { + const { evolutionLevel } = pokeDetails.preevolutions[0]; + evoChain = this.constructEvoLink(pokeDetails.preevolutions[0].species, evolutionLevel, evoChain, false); + + // If the direct pre-evolution has another pre-evolution (charizard -> charmeleon -> charmander) + if (pokeDetails.preevolutions[0].preevolutions) { + evoChain = this.constructEvoLink(pokeDetails.preevolutions[0].preevolutions[0].species, null, evoChain, false); + } + } + + // Parse evolution chain and add to evochain + if (pokeDetails.evolutions) { + evoChain = this.constructEvoLink(pokeDetails.evolutions[0].species, pokeDetails.evolutions[0].evolutionLevel, evoChain); + + // In case there are multiple evolutionary paths + const otherFormeEvos = pokeDetails.evolutions.slice(1); + if (otherFormeEvos) { + evoChain = `${evoChain}, ${otherFormeEvos.map((oevo) => `\`${oevo.species}\` (${oevo.evolutionLevel})`).join(', ')}`; + } + + // If the direct evolution has another evolution (charmander -> charmeleon -> charizard) + if (pokeDetails.evolutions[0].evolutions) { + evoChain = this.constructEvoLink( + pokeDetails.evolutions[0].evolutions[0].species, + pokeDetails.evolutions[0].evolutions[0].evolutionLevel, + evoChain + ); + } + } + + return evoChain; + } + + parseGenderRatio (genderRatio) { + if (genderRatio.male === '0%' && genderRatio.female === '0%') { + return 'Genderless'; + } + + return `${genderRatio.male} ♂ | ${genderRatio.female} ♀`; + } + + parseAbilities (abilitiesData) { + const abilities = []; + for (const [type, ability] of Object.entries(abilitiesData)) { + if (!ability) continue; + abilities.push(type === 'hidden' ? `*${ability}*` : ability); + } + + return abilities; + } +}; + +/** + * const embed = new Embed() + .setTitle(pokemon.info.name.toProperCase()) + .setThumbnail(sprite) + .setDescription(description.replace('\n', '')) + .addField('**Types:**', typeArray.join(', '), true) + .addField('**Abilities:**', abilityArray.join(', '), true); + if (evoArray.length > 1) embed.addField('**Evolution Chain:**', evoArray.join(' → ').replace(pokemon.species.name.toProperCase(), `**${pokemon.species.name.toProperCase()}**`)); + embed.addField('**Base Stats:**', `**HP:** ${pokemon.info.stats[0].base_stat} **Atk:** ${pokemon.info.stats[1].base_stat} **Def:** ${pokemon.info.stats[2].base_stat} **SpA:** ${pokemon.info.stats[3].base_stat} **SpD:** ${pokemon.info.stats[4].base_stat} **Spe:** ${pokemon.info.stats[5].base_stat}`); + message.channel.createMessage({ embed: embed }); + */ \ No newline at end of file diff --git a/bot/util/pokeapi.js b/bot/util/pokeapi.js deleted file mode 100644 index 4212d12..0000000 --- a/bot/util/pokeapi.js +++ /dev/null @@ -1,76 +0,0 @@ -const fetch = require('node-fetch'); -const { Collection } = require('eris'); - -class PokeAPI { - constructor (client) { - this.client = client; - this.cache = new Collection(); - this.url = 'https://pokeapi.co/api/v2'; - this.forms = [ - 'mega', - 'alola', - 'alolan', - 'galar', - 'galarian' - ]; - } - - async fetchPokemon (query) { - let form = ''; - - for (let i = 0; i < this.forms.length; i++) { - if (query.indexOf( this.forms[i]) > -1) { - query = query.replace( this.forms[i], ''); - if ( this.forms[i] === '-galarian') { - form += 'galar'; - } else if ( this.forms[i] === '-alolan') { - form += '-alola'; - } else { - form += `-${ this.forms[i]}`; - } - break; - } - } - - query = query.trim(); - - if (this.cache.has(query + form)) return this.cache.get(query + form); - - const pokeData = {}; - - const info = await fetch(this.url + '/pokemon/' + query + form); - pokeData.info = await info.json(); - const species = await fetch(this.url + '/pokemon-species/' + pokeData.info.species.name); - pokeData.species = await species.json(); - const evolutions = await fetch(pokeData.species.evolution_chain.url); - pokeData.evolutions = await evolutions.json(); - - this.cache.set(query + form, pokeData); - return pokeData; - } - - fetchSprite (query) { - let spritePrefix = ''; - - for (let i = 0; i < this.forms.length; i++) { - if (query.indexOf( this.forms[i]) > -1) { - query = query.replace( this.forms[i], ''); - if ( this.forms[i] === 'alola') { - spritePrefix = 'alolan-'; - } else if ( this.forms[i] === 'galar') { - spritePrefix = 'galarian-'; - } else { - spritePrefix = `${ this.forms[i]}-`; - } - break; - } - } - - let spritePath = 'normal'; - if (Math.floor((Math.random() * 100) + 1) === 69) spritePath = 'shiny'; - - return `https://raw.githubusercontent.com/woomyware/rotom-b-data/master/sprites/pokemon/${spritePath}/${spritePrefix}${query}.gif`; - } -} - -module.exports = PokeAPI; \ No newline at end of file