diff --git a/.vscode/settings.json b/.vscode/settings.json index e504606c9..4f94afb0e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,12 @@ { - "cSpell.words": ["Abhi", "accountinfo", "SKLLD", "wargaming", "winrate"], + "cSpell.words": [ + "Abhi", + "accountinfo", + "SKLLD", + "Smri", + "wargaming", + "winrate" + ], "deno.enable": false, "deno.unstable": false } diff --git a/src/behaviors/interactionCreate.ts b/src/behaviors/interactionCreate.ts index 4ba4e0afc..bd4ae2925 100644 --- a/src/behaviors/interactionCreate.ts +++ b/src/behaviors/interactionCreate.ts @@ -10,9 +10,10 @@ import { import { readdirSync } from 'fs'; import discord from '../../discord.json' assert { type: 'json' }; import getClientId from '../utilities/getClientId.js'; +import isDev from '../utilities/isDev.js'; export interface CommandRegistry { - disabled?: boolean; + inDev?: boolean; data: SlashCommandBuilder; execute: (interaction: Interaction) => void; } @@ -25,7 +26,7 @@ const rest = new REST().setToken(process.env.DISCORD_TOKEN!); for (const file of commandFolders) { const command = (await import(`../commands/${file}`)) as CommandRegistry; - if (!command.disabled) { + if (isDev() ? command.inDev ?? false : true) { commands.push(command.data.toJSON()); commandCollection.set(command.data.name, command); } diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts new file mode 100644 index 000000000..0d53b5d4f --- /dev/null +++ b/src/commands/eligible.ts @@ -0,0 +1,131 @@ +import { + CacheType, + ChatInputCommandInteraction, + EmbedBuilder, + SlashCommandBuilder, +} from 'discord.js'; +import { NEGATIVE_COLOR, POSITIVE_COLOR } from '../constants/colors.js'; +import { SERVERS } from '../constants/servers.js'; +import blitzLinks from '../utilities/blitzLinks.js'; +import getBlitzAccount from '../utilities/getBlitzAccount.js'; +import getBlitzStarsAccount from '../utilities/getBlitzStarsAccount.js'; +import poweredByBlitzStars from '../utilities/poweredByBlitzStars.js'; + +export async function execute( + interaction: ChatInputCommandInteraction, +) { + const ign = interaction.options.getString('ign')!; + const server = interaction.options.getString( + 'server', + ) as keyof typeof SERVERS; + + getBlitzAccount(interaction, ign, server, async (account) => { + getBlitzStarsAccount(interaction, account.account_id, ign, async (data) => { + const sklldIssues: string[] = []; + const smriIssues: string[] = []; + + if (data.period30d.all.battles < 150) { + sklldIssues.push( + `**Battles**: ${data.period30d.all.battles} (${ + data.period30d.all.battles - 150 + })`, + ); + } + if (data.period30d.avg_tier < 8) { + sklldIssues.push( + `**Tier**: ${data.period30d.avg_tier.toFixed(2)} (${( + data.period30d.avg_tier - 8 + ).toFixed(2)})`, + ); + } + if (data.period30d.special.winrate < 60) { + sklldIssues.push( + `**Winrate**: ${data.period30d.special.winrate.toFixed(2)}% (${( + data.period30d.special.winrate - 60 + ).toFixed(2)}%)`, + ); + } + if (data.period30d.wn8 < 2100) { + sklldIssues.push( + `**WN8**: ${data.period30d.wn8.toFixed(0)} (${( + data.period30d.wn8 - 2100 + ).toFixed(0)})`, + ); + } + if (data.period30d.special.dpb < 2400) { + sklldIssues.push( + `**Damage per battle**: ${data.period30d.special.dpb.toFixed(0)} (${( + data.period30d.special.dpb - 2400 + ).toFixed(0)})`, + ); + } + + if (data.statistics.all.battles < 1500) { + smriIssues.push( + `**Battles**: ${data.statistics.all.battles} (${ + data.statistics.all.battles - 1500 + })`, + ); + } + if (data.statistics.special.winrate < 53) { + smriIssues.push( + `**Winrate**: ${data.statistics.special.winrate.toFixed(2)}% (${( + data.statistics.special.winrate - 53 + ).toFixed(2)}%)`, + ); + } + + await interaction.reply({ + embeds: [ + poweredByBlitzStars( + new EmbedBuilder() + .setTitle(`${data.nickname}'s eligibility for Skilled clans`) + .setColor( + sklldIssues.length === 0 || smriIssues.length === 0 + ? POSITIVE_COLOR + : NEGATIVE_COLOR, + ) + .setDescription( + `${ + sklldIssues.length === 0 + ? '**✅ Player is eligible for `[SKLLD]`**' + : `**❌ \`[SKLLD] short by (30 days):\`**\n${sklldIssues.join( + '\n', + )}` + }\n\n${ + smriIssues.length === 0 + ? '**✅ Player is eligible for `[SMRI]`**' + : `**❌ \`[SMRI] short by (career):\`**\n${smriIssues.join( + '\n', + )}` + }\n\n${blitzLinks(data)}`, + ), + ), + ], + }); + + console.log(`Showing ${data.nickname}'s eligibility for Skilled clans`); + }); + }); +} + +export const data = new SlashCommandBuilder() + .setName('eligible') + .setDescription("Gets the user's eligibility for Skilled clans") + .addStringOption((option) => + option + .setName('server') + .setDescription('The Blitz server you are in') + .addChoices( + { name: SERVERS.com, value: 'com' }, + { name: SERVERS.eu, value: 'eu' }, + { name: SERVERS.asia, value: 'asia' }, + ) + .setRequired(true), + ) + .addStringOption((option) => + option + .setName('ign') + .setDescription('The username you use in Blitz') + .setRequired(true), + ); diff --git a/src/commands/stats.ts b/src/commands/stats.ts index 63f05086e..f1ce22882 100644 --- a/src/commands/stats.ts +++ b/src/commands/stats.ts @@ -4,11 +4,12 @@ import { EmbedBuilder, SlashCommandBuilder, } from 'discord.js'; -import fetch from 'node-fetch'; -import { NEGATIVE_COLOR, SKILLED_COLOR } from '../constants/colors.js'; +import { SKILLED_COLOR } from '../constants/colors.js'; import { SERVERS } from '../constants/servers.js'; -import { PlayerStatistics } from '../types/statistics.js'; +import blitzLinks from '../utilities/blitzLinks.js'; import getBlitzAccount from '../utilities/getBlitzAccount.js'; +import getBlitzStarsAccount from '../utilities/getBlitzStarsAccount.js'; +import poweredByBlitzStars from '../utilities/poweredByBlitzStars.js'; export async function execute( interaction: ChatInputCommandInteraction, @@ -23,89 +24,71 @@ export async function execute( | 'career'; getBlitzAccount(interaction, ign, server, async (account) => { - fetch(`https://www.blitzstars.com/api/top/player/${account.account_id}`) - .then(async (response) => { - const data = (await response.json()) as PlayerStatistics; + getBlitzStarsAccount(interaction, account.account_id, ign, async (data) => { + { const stats = period === 'career' ? data.statistics : data[`period${period}d`]; - interaction.reply({ + await interaction.reply({ embeds: [ - new EmbedBuilder() - .setColor(SKILLED_COLOR) - .setTitle( - `${data.nickname}'s ${ - period === 'career' ? period : `${period} day` - } stats`, - ) - .setDescription( - `${[ - ['Winrate', `${stats.special.winrate.toFixed(2)}%`], - ['Survival', `${stats.special.survivalRate.toFixed(2)}%`], - [ - 'Accuracy', - `${((stats.all.hits / stats.all.shots) * 100).toFixed(2)}%`, - ], - ['WN8', stats.wn8.toFixed(0)], - ['WN7', stats.wn7.toFixed(0)], - [], - ['Battles', stats.all.battles], - ['Wins', stats.all.wins], - ['Losses', stats.all.losses], - ['Average tier', stats.avg_tier.toFixed(2)], - [], - ['Hits per battle', stats.special.hpb.toFixed(2)], - ['Damage per battle', stats.special.dpb.toFixed(0)], - ['Kills per battle', stats.special.kpb.toFixed(2)], - ['Spots per battle', stats.special.spb.toFixed(2)], - [ - 'Shots per battle', - (stats.all.shots / stats.all.battles).toFixed(2), - ], - [ - 'Hits per battle', - (stats.all.hits / stats.all.battles).toFixed(2), - ], - [ - 'XP per battle', - (stats.all.xp / stats.all.battles).toFixed(0), - ], - [], - ['Damage ratio', stats.special.damageRatio.toFixed(2)], - ['Kills to death ratio', stats.special.kdr.toFixed(2)], - ] - .map((array) => - array.length === 0 ? '' : `**${array[0]}**: ${array[1]}`, - ) - .join( - '\n', - )}\n\n[View full stats](https://www.blitzstars.com/player/${ - data.region - }/${ - data.nickname - }) • [Support BlitzStars](https://www.blitzstars.com/supporters)`, - ) - .setTimestamp() - .setFooter({ - text: 'Powered by BlitzStars', - iconURL: - 'https://www.blitzstars.com/assets/images/TankyMcPewpew.png', - }), + poweredByBlitzStars( + new EmbedBuilder() + .setColor(SKILLED_COLOR) + .setTitle( + `${data.nickname}'s ${ + period === 'career' ? period : `${period} day` + } stats`, + ) + .setDescription( + `${[ + ['Winrate', `${stats.special.winrate.toFixed(2)}%`], + ['Survival', `${stats.special.survivalRate.toFixed(2)}%`], + [ + 'Accuracy', + `${((stats.all.hits / stats.all.shots) * 100).toFixed( + 2, + )}%`, + ], + ['WN8', stats.wn8.toFixed(0)], + ['WN7', stats.wn7.toFixed(0)], + [], + ['Battles', stats.all.battles], + ['Wins', stats.all.wins], + ['Losses', stats.all.losses], + ['Average tier', stats.avg_tier.toFixed(2)], + [], + ['Hits per battle', stats.special.hpb.toFixed(2)], + ['Damage per battle', stats.special.dpb.toFixed(0)], + ['Kills per battle', stats.special.kpb.toFixed(2)], + ['Spots per battle', stats.special.spb.toFixed(2)], + [ + 'Shots per battle', + (stats.all.shots / stats.all.battles).toFixed(2), + ], + [ + 'Hits per battle', + (stats.all.hits / stats.all.battles).toFixed(2), + ], + [ + 'XP per battle', + (stats.all.xp / stats.all.battles).toFixed(0), + ], + [], + ['Damage ratio', stats.special.damageRatio.toFixed(2)], + ['Kills to death ratio', stats.special.kdr.toFixed(2)], + ] + .map((array) => + array.length === 0 ? '' : `**${array[0]}**: ${array[1]}`, + ) + .join('\n')}\n\n${blitzLinks(data)}`, + ), + ), ], }); console.log(`Showing ${data.nickname}'s ${period} stats`); - }) - .catch(() => { - interaction.reply({ - embeds: [ - new EmbedBuilder() - .setTitle('No data to display') - .setDescription(`${ign} is not tracked by BlitzStars.`) - .setColor(NEGATIVE_COLOR), - ], - }); - }); + } + }); }); } diff --git a/src/utilities/blitzLinks.ts b/src/utilities/blitzLinks.ts new file mode 100644 index 000000000..18c79373a --- /dev/null +++ b/src/utilities/blitzLinks.ts @@ -0,0 +1,5 @@ +import { PlayerStatistics } from '../types/statistics.js'; + +export default function blitzLinks(data: PlayerStatistics) { + return `[View full stats](https://www.blitzstars.com/player/${data.region}/${data.nickname}) • [Support BlitzStars](https://www.blitzstars.com/supporters)`; +} diff --git a/src/utilities/getBlitzStarsAccount.ts b/src/utilities/getBlitzStarsAccount.ts new file mode 100644 index 000000000..f47cf8962 --- /dev/null +++ b/src/utilities/getBlitzStarsAccount.ts @@ -0,0 +1,29 @@ +import { + CacheType, + ChatInputCommandInteraction, + EmbedBuilder, +} from 'discord.js'; +import { NEGATIVE_COLOR } from '../constants/colors.js'; +import { PlayerStatistics } from '../types/statistics.js'; + +export default async function getBlitzStarsAccount( + interaction: ChatInputCommandInteraction, + accountId: number, + ign: string, + callback: (account: PlayerStatistics) => void, +) { + fetch(`https://www.blitzstars.com/api/top/player/${accountId}`) + .then(async (response) => { + callback((await response.json()) as PlayerStatistics); + }) + .catch(() => { + interaction.reply({ + embeds: [ + new EmbedBuilder() + .setTitle('No data to display') + .setDescription(`${ign} is not tracked by BlitzStars.`) + .setColor(NEGATIVE_COLOR), + ], + }); + }); +} diff --git a/src/utilities/getClientId.ts b/src/utilities/getClientId.ts index 0e2873bbd..fb554028a 100644 --- a/src/utilities/getClientId.ts +++ b/src/utilities/getClientId.ts @@ -1,8 +1,6 @@ -import { argv } from 'process'; import discord from '../../discord.json' assert { type: 'json' }; - -const isDev = argv.includes('--dev'); +import isDev from './isDev.js'; export default function getClientId() { - return isDev ? discord.client_id_dev : discord.client_id; + return isDev() ? discord.client_id_dev : discord.client_id; } diff --git a/src/utilities/isDev.ts b/src/utilities/isDev.ts new file mode 100644 index 000000000..e8db4aef4 --- /dev/null +++ b/src/utilities/isDev.ts @@ -0,0 +1,7 @@ +import { argv } from 'process'; + +const isDevBoolean = argv.includes('--dev'); + +export default function isDev() { + return isDevBoolean; +} diff --git a/src/utilities/poweredByBlitzStars.ts b/src/utilities/poweredByBlitzStars.ts new file mode 100644 index 000000000..4967e0461 --- /dev/null +++ b/src/utilities/poweredByBlitzStars.ts @@ -0,0 +1,8 @@ +import { EmbedBuilder } from 'discord.js'; + +export default function poweredByBlitzStars(embed: EmbedBuilder) { + return embed.setTimestamp().setFooter({ + text: 'Powered by BlitzStars', + iconURL: 'https://www.blitzstars.com/assets/images/TankyMcPewpew.png', + }); +}