Updated formatting

This commit is contained in:
Michael 2023-09-13 02:17:31 -04:00
parent ecbd2bdc4e
commit 25346f9ab2
11 changed files with 601 additions and 601 deletions

View file

@ -9,24 +9,24 @@ const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { clientId, botName, botOwner } = require('../config.json');
module.exports = {
data: new SlashCommandBuilder()
.setName('about')
.setDescription('Gives basic information about the bot'),
async execute(interaction) {
data: new SlashCommandBuilder()
.setName('about')
.setDescription('Gives basic information about the bot'),
async execute(interaction) {
const exampleEmbed = new EmbedBuilder()
.setColor(interaction.member.displayHexColor)
.setTitle(`About ${botName}`)
.setURL(`https://discord.com/oauth2/authorize?client_id=${clientId}&permissions=274877908992&scope=bot%20applications.commands`)
.addFields(
{ name: 'Admin of this bot', value: `${botOwner}` },
{ name: 'Websocket Heartbeat / Ping', value: `${interaction.client.ws.ping}ms` },
{ name: 'Invite Link', value: `https://discord.com/oauth2/authorize?client_id=${clientId}&permissions=274877908992&scope=bot%20applications.commands`, inline: true },
{ name: 'Based on the open source Konpeki Discord Bot', value: 'https://github.com/TheShadowEevee/Konpeki-Discord-Bot', inline: true },
)
.setFooter({ text: `Support for custom changes should go through the admin of this bot, ${botOwner}. Support for the underlying Konpeki Discord Bot is available at https://discord.gg/Zt8zruXexJ.` });
const exampleEmbed = new EmbedBuilder()
.setColor(interaction.member.displayHexColor)
.setTitle(`About ${botName}`)
.setURL(`https://discord.com/oauth2/authorize?client_id=${clientId}&permissions=274877908992&scope=bot%20applications.commands`)
.addFields(
{ name: 'Admin of this bot', value: `${botOwner}` },
{ name: 'Websocket Heartbeat / Ping', value: `${interaction.client.ws.ping}ms` },
{ name: 'Invite Link', value: `https://discord.com/oauth2/authorize?client_id=${clientId}&permissions=274877908992&scope=bot%20applications.commands`, inline: true },
{ name: 'Based on the open source Konpeki Discord Bot', value: 'https://github.com/TheShadowEevee/Konpeki-Discord-Bot', inline: true },
)
.setFooter({ text: `Support for custom changes should go through the admin of this bot, ${botOwner}. Support for the underlying Konpeki Discord Bot is available at https://discord.gg/Zt8zruXexJ.` });
await interaction.reply({ embeds: [exampleEmbed], ephemeral: true });
},
await interaction.reply({ embeds: [exampleEmbed], ephemeral: true });
},
};

View file

@ -6,62 +6,62 @@
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('avatar')
.setDescription('Shares a users current avatar')
data: new SlashCommandBuilder()
.setName('avatar')
.setDescription('Shares a users current avatar')
// Optional user selection for avatar target; target selves if none.
.addUserOption(option =>
option.setName('user')
.setDescription('Select the user to get an avatar from'))
// Optional user selection for avatar target; target selves if none.
.addUserOption(option =>
option.setName('user')
.setDescription('Select the user to get an avatar from'))
// Optional choice for user to choose avatar size; 4096 if no selection.
.addStringOption(option =>
option.setName('format')
.setDescription('Select what format you want the output to be')
.addChoices(
{ name: 'WebP', value: 'webp' },
{ name: 'PNG', value: 'png' },
{ name: 'JPEG', value: 'jpg' },
))
// Optional choice for user to choose avatar size; 4096 if no selection.
.addStringOption(option =>
option.setName('format')
.setDescription('Select what format you want the output to be')
.addChoices(
{ name: 'WebP', value: 'webp' },
{ name: 'PNG', value: 'png' },
{ name: 'JPEG', value: 'jpg' },
))
// Optional choice for user to choose avatar format; webp if no selection.
.addStringOption(option =>
option.setName('size')
.setDescription('Select what size you want the output to be')
.addChoices(
{ name: '4096px', value: '4096' },
{ name: '2048px', value: '2048' },
{ name: '1024px', value: '1024' },
{ name: '600px', value: '600' },
{ name: '512px', value: '512' },
{ name: '300px', value: '300' },
{ name: '256px', value: '256' },
{ name: '128px', value: '128' },
{ name: '96px', value: '96' },
{ name: '64px', value: '64' },
{ name: '56px', value: '56' },
{ name: '32px', value: '32' },
{ name: '16px', value: '16' },
))
// Optional choice for user to choose avatar format; webp if no selection.
.addStringOption(option =>
option.setName('size')
.setDescription('Select what size you want the output to be')
.addChoices(
{ name: '4096px', value: '4096' },
{ name: '2048px', value: '2048' },
{ name: '1024px', value: '1024' },
{ name: '600px', value: '600' },
{ name: '512px', value: '512' },
{ name: '300px', value: '300' },
{ name: '256px', value: '256' },
{ name: '128px', value: '128' },
{ name: '96px', value: '96' },
{ name: '64px', value: '64' },
{ name: '56px', value: '56' },
{ name: '32px', value: '32' },
{ name: '16px', value: '16' },
))
// Optional Ephemeral check to allow user to choose command results to be shared publicly or private; send to self only if no selection.
.addStringOption(option =>
option.setName('ephemeral')
.setDescription('Post the avatar in the current channel')
.addChoices(
{ name: 'Send to me only', value: 'true' },
{ name: 'Send in channel', value: 'false' },
)),
// Optional Ephemeral check to allow user to choose command results to be shared publicly or private; send to self only if no selection.
.addStringOption(option =>
option.setName('ephemeral')
.setDescription('Post the avatar in the current channel')
.addChoices(
{ name: 'Send to me only', value: 'true' },
{ name: 'Send in channel', value: 'false' },
)),
async execute(interaction) {
const discordUser = interaction.options.getUser('user') ?? interaction.user;
const avatarFormat = interaction.options.getString('format') ?? 'webp';
const avatarSize = Number(interaction.options.getString('size')) ?? 4096;
const isEphemeral = interaction.options.getString('ephemeral') ?? 'true';
async execute(interaction) {
const discordUser = interaction.options.getUser('user') ?? interaction.user;
const avatarFormat = interaction.options.getString('format') ?? 'webp';
const avatarSize = Number(interaction.options.getString('size')) ?? 4096;
const isEphemeral = interaction.options.getString('ephemeral') ?? 'true';
await interaction.reply({ content: `${discordUser.avatarURL({ extension:avatarFormat, size:avatarSize, forceStatic:false })}`, ephemeral: (isEphemeral === 'true') });
},
await interaction.reply({ content: `${discordUser.avatarURL({ extension:avatarFormat, size:avatarSize, forceStatic:false })}`, ephemeral: (isEphemeral === 'true') });
},
};

View file

@ -11,258 +11,258 @@ let helpFile = '';
// Import help text file
if (fs.existsSync('./data/help-text.json')) {
helpFile = JSON.parse(fs.readFileSync('./data/help-text.json', 'utf8'));
helpFile = JSON.parse(fs.readFileSync('./data/help-text.json', 'utf8'));
}
// List of all commands, by category
// Command help, listing options.
module.exports = {
data: new SlashCommandBuilder()
.setName('help')
.setDescription('Provides information on avalible commands')
data: new SlashCommandBuilder()
.setName('help')
.setDescription('Provides information on avalible commands')
// Allow choosing the help page to open
.addNumberOption(option =>
option.setName('page')
.setDescription('Choose help page to skip to'),
),
// Allow choosing the help page to open
.addNumberOption(option =>
option.setName('page')
.setDescription('Choose help page to skip to'),
),
async execute(interaction) {
async execute(interaction) {
let pageNumber = interaction.options.getNumber('page') ?? 1;
const commandsPerPage = 5;
let commandsThisPage = 0;
let pageNumber = interaction.options.getNumber('page') ?? 1;
const commandsPerPage = 5;
let commandsThisPage = 0;
const numberOfCommands = Object.keys(helpFile).length;
const pageTotal = String(Math.ceil(numberOfCommands / commandsPerPage));
let userRoleColor = Number('0x' + interaction.member.displayHexColor.split('#')[1]);
const numberOfCommands = Object.keys(helpFile).length;
const pageTotal = String(Math.ceil(numberOfCommands / commandsPerPage));
let userRoleColor = Number('0x' + interaction.member.displayHexColor.split('#')[1]);
// This will also unintentionally catch roles with full black color (#000000), but it should be fine.
if (userRoleColor == 0) {
userRoleColor = Number(0x55ffff);
}
// This will also unintentionally catch roles with full black color (#000000), but it should be fine.
if (userRoleColor == 0) {
userRoleColor = Number(0x55ffff);
}
if (pageNumber > pageTotal) {
pageNumber = 1;
}
if (pageNumber > pageTotal) {
pageNumber = 1;
}
let embedPartOne = {
color: userRoleColor,
title: 'Help Text',
description: `Page ${pageNumber} of ${pageTotal}`,
};
let embedPartOne = {
color: userRoleColor,
title: 'Help Text',
description: `Page ${pageNumber} of ${pageTotal}`,
};
if (pageNumber != pageTotal) {
commandsThisPage = commandsPerPage;
}
else {
commandsThisPage = numberOfCommands % commandsPerPage;
}
if (pageNumber != pageTotal) {
commandsThisPage = commandsPerPage;
}
else {
commandsThisPage = numberOfCommands % commandsPerPage;
}
let embedPartTwo = '';
let embedPartTwo = '';
embedPartTwo += '{"fields": [';
for (let i = 0; i < commandsThisPage; i++) {
embedPartTwo += '{"fields": [';
for (let i = 0; i < commandsThisPage; i++) {
const currentCommandName = Object.keys(helpFile)[i + (commandsPerPage * (pageNumber - 1))];
const currentCommandName = Object.keys(helpFile)[i + (commandsPerPage * (pageNumber - 1))];
embedPartTwo += '{';
embedPartTwo += '{';
embedPartTwo += ' "name": "/' + currentCommandName + '",',
embedPartTwo += ' "value": "' + helpFile[currentCommandName].description + '"',
embedPartTwo += ' "name": "/' + currentCommandName + '",',
embedPartTwo += ' "value": "' + helpFile[currentCommandName].description + '"',
embedPartTwo += '},';
}
embedPartTwo = embedPartTwo.substring(0, embedPartTwo.length - 1) + ']}';
embedPartTwo += '},';
}
embedPartTwo = embedPartTwo.substring(0, embedPartTwo.length - 1) + ']}';
let buttonList = '';
let buttonList = '';
// Change buttons based on page number. Is there an easier/shorter way to do this?
if (pageNumber == 1) {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Primary),
);
}
else if (pageNumber == pageTotal) {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Primary),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
);
}
else {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Primary),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Primary),
);
}
// Change buttons based on page number. Is there an easier/shorter way to do this?
if (pageNumber == 1) {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Primary),
);
}
else if (pageNumber == pageTotal) {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Primary),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
);
}
else {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Primary),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Primary),
);
}
// Button code
const collector = interaction.channel.createMessageComponentCollector({ time: 300000 });
// Button code
const collector = interaction.channel.createMessageComponentCollector({ time: 300000 });
collector.on('collect', async i => {
collector.on('collect', async i => {
if (i.customId === 'next') {
pageNumber += 1;
}
if (i.customId === 'back') {
pageNumber -= 1;
}
if (i.customId === 'next') {
pageNumber += 1;
}
if (i.customId === 'back') {
pageNumber -= 1;
}
// Replicate the above code to remake the help model for the new page. Again, there has to be an easier way to do this.
embedPartOne = {
color: userRoleColor,
title: 'Help Text',
description: `Page ${pageNumber} of ${pageTotal}`,
};
// Replicate the above code to remake the help model for the new page. Again, there has to be an easier way to do this.
embedPartOne = {
color: userRoleColor,
title: 'Help Text',
description: `Page ${pageNumber} of ${pageTotal}`,
};
embedPartTwo = '';
embedPartTwo = '';
if (pageNumber != pageTotal) {
commandsThisPage = commandsPerPage;
}
else {
commandsThisPage = numberOfCommands % commandsPerPage;
}
if (pageNumber != pageTotal) {
commandsThisPage = commandsPerPage;
}
else {
commandsThisPage = numberOfCommands % commandsPerPage;
}
embedPartTwo += '{"fields": [';
for (let j = 0; j < commandsThisPage; j++) {
embedPartTwo += '{"fields": [';
for (let j = 0; j < commandsThisPage; j++) {
const currentCommandName = Object.keys(helpFile)[j + (commandsPerPage * (pageNumber - 1))];
const currentCommandName = Object.keys(helpFile)[j + (commandsPerPage * (pageNumber - 1))];
embedPartTwo += '{';
embedPartTwo += '{';
embedPartTwo += ' "name": "/' + currentCommandName + '",',
embedPartTwo += ' "value": "' + helpFile[currentCommandName].description + '"',
embedPartTwo += ' "name": "/' + currentCommandName + '",',
embedPartTwo += ' "value": "' + helpFile[currentCommandName].description + '"',
embedPartTwo += '},';
}
embedPartTwo = embedPartTwo.substring(0, embedPartTwo.length - 1) + ']}';
embedPartTwo += '},';
}
embedPartTwo = embedPartTwo.substring(0, embedPartTwo.length - 1) + ']}';
// Change buttons based on page number. Is there an easier/shorter way to do this?
if (pageNumber == 1) {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Primary),
);
}
else if (pageNumber == pageTotal) {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Primary),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
);
}
else {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Primary),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Primary),
);
}
// Change buttons based on page number. Is there an easier/shorter way to do this?
if (pageNumber == 1) {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Primary),
);
}
else if (pageNumber == pageTotal) {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Primary),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
);
}
else {
buttonList = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back')
.setLabel('Previous')
.setStyle(ButtonStyle.Primary),
)
.addComponents(
new ButtonBuilder()
.setCustomId('page')
.setLabel(`${pageNumber}/${pageTotal}`)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
)
.addComponents(
new ButtonBuilder()
.setCustomId('next')
.setLabel('Next')
.setStyle(ButtonStyle.Primary),
);
}
await i.update({ embeds: [Object.assign({}, embedPartOne, JSON.parse(embedPartTwo))], components: [ buttonList ], ephemeral: true });
});
await i.update({ embeds: [Object.assign({}, embedPartOne, JSON.parse(embedPartTwo))], components: [ buttonList ], ephemeral: true });
});
await interaction.reply({ embeds: [Object.assign({}, embedPartOne, JSON.parse(embedPartTwo))], components: [ buttonList ], ephemeral: true });
await interaction.reply({ embeds: [Object.assign({}, embedPartOne, JSON.parse(embedPartTwo))], components: [ buttonList ], ephemeral: true });
},
},
};

View file

@ -9,10 +9,10 @@ const { SlashCommandBuilder } = require('discord.js');
const { botName, clientId } = require('../config.json');
module.exports = {
data: new SlashCommandBuilder()
.setName('invite')
.setDescription(`Invite ${botName} to your own server`),
async execute(interaction) {
await interaction.reply({ content: `Use this link to invite ${botName} (That's me!) to your own server!\nhttps://discord.com/oauth2/authorize?client_id=${clientId}&permissions=274877908992&scope=bot%20applications.commands`, ephemeral: true });
},
data: new SlashCommandBuilder()
.setName('invite')
.setDescription(`Invite ${botName} to your own server`),
async execute(interaction) {
await interaction.reply({ content: `Use this link to invite ${botName} (That's me!) to your own server!\nhttps://discord.com/oauth2/authorize?client_id=${clientId}&permissions=274877908992&scope=bot%20applications.commands`, ephemeral: true });
},
};

View file

@ -7,69 +7,69 @@ const { SlashCommandBuilder } = require('discord.js');
const { randomInt } = require('node:crypto');
module.exports = {
data: new SlashCommandBuilder()
.setName('lottery')
.setDescription('Rolls a set of numbers you can use for whatever')
data: new SlashCommandBuilder()
.setName('lottery')
.setDescription('Rolls a set of numbers you can use for whatever')
// Get number of numbers to roll
.addNumberOption(option =>
option.setName('count')
.setDescription('How many numbers to roll'),
)
// Get number of numbers to roll
.addNumberOption(option =>
option.setName('count')
.setDescription('How many numbers to roll'),
)
// Get max number to roll
.addNumberOption(option =>
option.setName('max')
.setDescription('Set the maximum roll'),
)
// Get max number to roll
.addNumberOption(option =>
option.setName('max')
.setDescription('Set the maximum roll'),
)
// Optional Ephemeral check to allow user to choose command results to be shared publicly or private; send to self only if no selection.
.addStringOption(option =>
option.setName('ephemeral')
.setDescription('Post the avatar in the current channel')
.addChoices(
{ name: 'Send to me only', value: 'true' },
{ name: 'Send in channel', value: 'false' },
)),
// Optional Ephemeral check to allow user to choose command results to be shared publicly or private; send to self only if no selection.
.addStringOption(option =>
option.setName('ephemeral')
.setDescription('Post the avatar in the current channel')
.addChoices(
{ name: 'Send to me only', value: 'true' },
{ name: 'Send in channel', value: 'false' },
)),
async execute(interaction) {
const isEphemeral = interaction.options.getString('ephemeral') ?? 'true';
const rollCount = interaction.options.getNumber('count') ?? 6;
const maxRoll = interaction.options.getNumber('max') ?? 99;
async execute(interaction) {
const isEphemeral = interaction.options.getString('ephemeral') ?? 'true';
const rollCount = interaction.options.getNumber('count') ?? 6;
const maxRoll = interaction.options.getNumber('max') ?? 99;
// Limit max number rollable to prevent spam and API issues
if (maxRoll > 999) {
await interaction.reply({ content: `Big roller! Unfortunatly ${maxRoll} is too big a number for me. Try somewhere below 1000!`, ephemeral: true });
return;
}
// Prevent 0 or less numbers
else if (maxRoll < 1) {
await interaction.reply({ content: `The fewer numbers, the higher the odds! Unfortunatly ${maxRoll} is too low a number... Try a positive number under 1000!`, ephemeral:true });
return;
}
// Limit max number rollable to prevent spam and API issues
if (maxRoll > 999) {
await interaction.reply({ content: `Big roller! Unfortunatly ${maxRoll} is too big a number for me. Try somewhere below 1000!`, ephemeral: true });
return;
}
// Prevent 0 or less numbers
else if (maxRoll < 1) {
await interaction.reply({ content: `The fewer numbers, the higher the odds! Unfortunatly ${maxRoll} is too low a number... Try a positive number under 1000!`, ephemeral:true });
return;
}
// Limit numbers rollable to prevent spam and API issues
if (rollCount > 9) {
await interaction.reply({ content: `You want ${rollCount} numbers?! That's a bit much, even for me...\nTry 9 or less please!`, ephemeral: true });
return;
}
// Prevent 0 or less numbers
else if (rollCount < 1) {
await interaction.reply({ content: `It's kinda difficult to roll ${rollCount} numbers...\nTry a positive single digit number!`, ephemeral:true });
return;
}
// Limit numbers rollable to prevent spam and API issues
if (rollCount > 9) {
await interaction.reply({ content: `You want ${rollCount} numbers?! That's a bit much, even for me...\nTry 9 or less please!`, ephemeral: true });
return;
}
// Prevent 0 or less numbers
else if (rollCount < 1) {
await interaction.reply({ content: `It's kinda difficult to roll ${rollCount} numbers...\nTry a positive single digit number!`, ephemeral:true });
return;
}
const lotteryNumbers = [];
const lotteryNumbers = [];
for (let i = 0; i < rollCount; i++) {
lotteryNumbers.push(randomInt(1, maxRoll));
}
for (let i = 0; i < rollCount; i++) {
lotteryNumbers.push(randomInt(1, maxRoll));
}
if (rollCount === 1) {
await interaction.reply({ content: `Your lucky number is...\n${lotteryNumbers.toString().split(',').join(', ')}.`, ephemeral: (isEphemeral === 'true') });
}
else {
await interaction.reply({ content: `Your lucky numbers are...\n${lotteryNumbers.toString().split(',').join(', ')}.`, ephemeral: (isEphemeral === 'true') });
}
},
if (rollCount === 1) {
await interaction.reply({ content: `Your lucky number is...\n${lotteryNumbers.toString().split(',').join(', ')}.`, ephemeral: (isEphemeral === 'true') });
}
else {
await interaction.reply({ content: `Your lucky numbers are...\n${lotteryNumbers.toString().split(',').join(', ')}.`, ephemeral: (isEphemeral === 'true') });
}
},
};

View file

@ -8,10 +8,10 @@
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Checks to see if the bot is online, as well as it\'s ping'),
async execute(interaction) {
await interaction.reply({ content: `Pong! Current Websocket Heartbeat / ping is ${interaction.client.ws.ping}ms.`, ephemeral: true });
},
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Checks to see if the bot is online, as well as it\'s ping'),
async execute(interaction) {
await interaction.reply({ content: `Pong! Current Websocket Heartbeat / ping is ${interaction.client.ws.ping}ms.`, ephemeral: true });
},
};

View file

@ -7,94 +7,94 @@ const { SlashCommandBuilder } = require('discord.js');
const { randomInt } = require('node:crypto');
module.exports = {
data: new SlashCommandBuilder()
.setName('roll')
.setDescription('Rolls a set of dice')
data: new SlashCommandBuilder()
.setName('roll')
.setDescription('Rolls a set of dice')
// Get number of numbers to roll
.addNumberOption(option =>
option.setName('die')
.setDescription('Type of dice to roll')
.addChoices(
{ name: 'd4', value: 4 },
{ name: 'd6', value: 6 },
{ name: 'd8', value: 8 },
{ name: 'd10', value: 10 },
{ name: 'd20', value: 20 },
{ name: 'd100', value: 100 },
))
// Get number of numbers to roll
.addNumberOption(option =>
option.setName('die')
.setDescription('Type of dice to roll')
.addChoices(
{ name: 'd4', value: 4 },
{ name: 'd6', value: 6 },
{ name: 'd8', value: 8 },
{ name: 'd10', value: 10 },
{ name: 'd20', value: 20 },
{ name: 'd100', value: 100 },
))
// Get max number to roll
.addNumberOption(option =>
option.setName('count')
.setDescription('Amount of dice to roll'),
)
// Get max number to roll
.addNumberOption(option =>
option.setName('count')
.setDescription('Amount of dice to roll'),
)
// Get max number to roll
.addNumberOption(option =>
option.setName('modifier')
.setDescription('+/- to a dice roll'),
)
// Get max number to roll
.addNumberOption(option =>
option.setName('modifier')
.setDescription('+/- to a dice roll'),
)
// Optional Ephemeral check to allow user to choose command results to be shared publicly or private; send to self only if no selection.
.addStringOption(option =>
option.setName('ephemeral')
.setDescription('Post the avatar in the current channel')
.addChoices(
{ name: 'Send to me only', value: 'true' },
{ name: 'Send in channel', value: 'false' },
)),
// Optional Ephemeral check to allow user to choose command results to be shared publicly or private; send to self only if no selection.
.addStringOption(option =>
option.setName('ephemeral')
.setDescription('Post the avatar in the current channel')
.addChoices(
{ name: 'Send to me only', value: 'true' },
{ name: 'Send in channel', value: 'false' },
)),
async execute(interaction) {
const isEphemeral = interaction.options.getString('ephemeral') ?? 'true';
const rollCount = interaction.options.getNumber('count') ?? 1;
const dieType = interaction.options.getNumber('die') ?? 6;
const rollMod = interaction.options.getNumber('modifier') ?? 0;
async execute(interaction) {
const isEphemeral = interaction.options.getString('ephemeral') ?? 'true';
const rollCount = interaction.options.getNumber('count') ?? 1;
const dieType = interaction.options.getNumber('die') ?? 6;
const rollMod = interaction.options.getNumber('modifier') ?? 0;
let modSign = '';
let rollModStr = '';
let rollModNota = '';
let modSign = '';
let rollModStr = '';
let rollModNota = '';
// Limit numbers rollable to prevent spam and API issues
if (rollCount > 100) {
await interaction.reply({ content: `You want ${rollCount} numbers?! That's a bit much, even for me...\nTry 100 or less please!`, ephemeral: true });
return;
}
// Prevent 0 or less numbers
else if (rollCount < 1) {
await interaction.reply({ content: `It's kinda difficult to roll ${rollCount} numbers...\nTry a positive number!`, ephemeral:true });
return;
}
// Limit numbers rollable to prevent spam and API issues
if (rollCount > 100) {
await interaction.reply({ content: `You want ${rollCount} numbers?! That's a bit much, even for me...\nTry 100 or less please!`, ephemeral: true });
return;
}
// Prevent 0 or less numbers
else if (rollCount < 1) {
await interaction.reply({ content: `It's kinda difficult to roll ${rollCount} numbers...\nTry a positive number!`, ephemeral:true });
return;
}
const diceRolls = [];
let rollSum = 0;
const diceRolls = [];
let rollSum = 0;
for (let i = 0; i < rollCount; i++) {
const randomNum = randomInt(1, dieType);
for (let i = 0; i < rollCount; i++) {
const randomNum = randomInt(1, dieType);
diceRolls.push(randomNum);
rollSum += randomNum;
diceRolls.push(randomNum);
rollSum += randomNum;
}
}
if (rollMod < 0) {
modSign = '-';
}
else if (rollMod > 0) {
modSign = '+';
}
if (rollMod < 0) {
modSign = '-';
}
else if (rollMod > 0) {
modSign = '+';
}
if (rollMod != 0) {
rollModStr = ' ' + modSign + ' ' + Math.abs(rollMod);
rollModNota = modSign + Math.abs(rollMod);
}
if (rollMod != 0) {
rollModStr = ' ' + modSign + ' ' + Math.abs(rollMod);
rollModNota = modSign + Math.abs(rollMod);
}
const diceRollsString = diceRolls.toString().split(',').join(' + ');
const diceRollsString = diceRolls.toString().split(',').join(' + ');
for (let i = 0; i < rollCount; i++) {
diceRolls.push(randomInt(1, dieType));
}
for (let i = 0; i < rollCount; i++) {
diceRolls.push(randomInt(1, dieType));
}
await interaction.reply({ content: `\`${rollCount}d${dieType}${rollModNota}\`\n\`Rolls: ( ${diceRollsString} )${rollModStr} = ${rollSum + rollMod}\``, ephemeral: (isEphemeral === 'true') });
},
await interaction.reply({ content: `\`${rollCount}d${dieType}${rollModNota}\`\n\`Rolls: ( ${diceRollsString} )${rollModStr} = ${rollSum + rollMod}\``, ephemeral: (isEphemeral === 'true') });
},
};

View file

@ -6,56 +6,56 @@
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('server-icon')
.setDescription('Shares this servers current icon')
data: new SlashCommandBuilder()
.setName('server-icon')
.setDescription('Shares this servers current icon')
// Optional choice for user to choose icon size; 4096 if no selection.
.addStringOption(option =>
option.setName('format')
.setDescription('Select what format you want the output to be')
.addChoices(
{ name: 'WebP', value: 'webp' },
{ name: 'PNG', value: 'png' },
{ name: 'JPEG', value: 'jpg' },
))
// Optional choice for user to choose icon size; 4096 if no selection.
.addStringOption(option =>
option.setName('format')
.setDescription('Select what format you want the output to be')
.addChoices(
{ name: 'WebP', value: 'webp' },
{ name: 'PNG', value: 'png' },
{ name: 'JPEG', value: 'jpg' },
))
// Optional choice for user to choose icon format; webp if no selection.
.addStringOption(option =>
option.setName('size')
.setDescription('Select what size you want the output to be')
.addChoices(
{ name: '4096px', value: '4096' },
{ name: '2048px', value: '2048' },
{ name: '1024px', value: '1024' },
{ name: '600px', value: '600' },
{ name: '512px', value: '512' },
{ name: '300px', value: '300' },
{ name: '256px', value: '256' },
{ name: '128px', value: '128' },
{ name: '96px', value: '96' },
{ name: '64px', value: '64' },
{ name: '56px', value: '56' },
{ name: '32px', value: '32' },
{ name: '16px', value: '16' },
))
// Optional choice for user to choose icon format; webp if no selection.
.addStringOption(option =>
option.setName('size')
.setDescription('Select what size you want the output to be')
.addChoices(
{ name: '4096px', value: '4096' },
{ name: '2048px', value: '2048' },
{ name: '1024px', value: '1024' },
{ name: '600px', value: '600' },
{ name: '512px', value: '512' },
{ name: '300px', value: '300' },
{ name: '256px', value: '256' },
{ name: '128px', value: '128' },
{ name: '96px', value: '96' },
{ name: '64px', value: '64' },
{ name: '56px', value: '56' },
{ name: '32px', value: '32' },
{ name: '16px', value: '16' },
))
// Optional Ephemeral check to allow user to choose command results to be shared publicly or private; send to self only if no selection.
.addStringOption(option =>
option.setName('ephemeral')
.setDescription('Post the icon in the current channel')
.addChoices(
{ name: 'Send to me only', value: 'true' },
{ name: 'Send in channel', value: 'false' },
)),
// Optional Ephemeral check to allow user to choose command results to be shared publicly or private; send to self only if no selection.
.addStringOption(option =>
option.setName('ephemeral')
.setDescription('Post the icon in the current channel')
.addChoices(
{ name: 'Send to me only', value: 'true' },
{ name: 'Send in channel', value: 'false' },
)),
async execute(interaction) {
const iconFormat = interaction.options.getString('format') ?? 'webp';
const iconSize = Number(interaction.options.getString('size')) ?? 4096;
const isEphemeral = interaction.options.getString('ephemeral') ?? 'true';
async execute(interaction) {
const iconFormat = interaction.options.getString('format') ?? 'webp';
const iconSize = Number(interaction.options.getString('size')) ?? 4096;
const isEphemeral = interaction.options.getString('ephemeral') ?? 'true';
await interaction.reply({ content: `${interaction.guild.iconURL({ extension:iconFormat, size:iconSize, forceStatic:false })}`, ephemeral: (isEphemeral === 'true') });
},
await interaction.reply({ content: `${interaction.guild.iconURL({ extension:iconFormat, size:iconSize, forceStatic:false })}`, ephemeral: (isEphemeral === 'true') });
},
};

View file

@ -14,17 +14,17 @@ const rest = new REST({ version: '10' }).setToken(token);
// and deploy your commands!
(async () => {
try {
console.log('Started deleting all application (/) commands.');
try {
console.log('Started deleting all application (/) commands.');
// The put method is used to fully refresh all commands
rest.put(Routes.applicationCommands(clientId), { body: [] })
.then(() => console.log('Successfully deleted all application (/) commands.'))
.catch(console.error);
// The put method is used to fully refresh all commands
rest.put(Routes.applicationCommands(clientId), { body: [] })
.then(() => console.log('Successfully deleted all application (/) commands.'))
.catch(console.error);
}
catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}
}
catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}
})();

View file

@ -17,9 +17,9 @@ const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
for (const file of commandFiles) {
const command = require(`./commands/${file}`);
commands.push(command.data.toJSON());
commandsHelp.push(command.data);
const command = require(`./commands/${file}`);
commands.push(command.data.toJSON());
commandsHelp.push(command.data);
}
// Construct and prepare an instance of the REST module
@ -27,85 +27,85 @@ const rest = new REST({ version: '10' }).setToken(token);
// Generate help-text.json
try {
console.log(`Generating ${commands.length} help text entries.`);
console.log(`Generating ${commands.length} help text entries.`);
let helpJSONString = '{\n';
let helpJSONString = '{\n';
for (let i = 0; i < commandsHelp.length; i++) {
helpJSONString += ` "${commandsHelp[i].name}": {\n`;
helpJSONString += ` "description": "${commandsHelp[i].description}",\n`;
helpJSONString += ' "options": {\n';
for (let i = 0; i < commandsHelp.length; i++) {
helpJSONString += ` "${commandsHelp[i].name}": {\n`;
helpJSONString += ` "description": "${commandsHelp[i].description}",\n`;
helpJSONString += ' "options": {\n';
for (let j = 0; j < commandsHelp[i].options.length; j++) {
for (let j = 0; j < commandsHelp[i].options.length; j++) {
helpJSONString += ` "${commandsHelp[i].options[j].name}": {\n`;
helpJSONString += ` "description": "${commandsHelp[i].options[j].description}",\n`;
helpJSONString += ` "required": "${commandsHelp[i].options[j].required}",\n`;
helpJSONString += ' "choices": {\n';
helpJSONString += ` "${commandsHelp[i].options[j].name}": {\n`;
helpJSONString += ` "description": "${commandsHelp[i].options[j].description}",\n`;
helpJSONString += ` "required": "${commandsHelp[i].options[j].required}",\n`;
helpJSONString += ' "choices": {\n';
if (typeof commandsHelp[i].options[j].choices !== 'undefined') {
for (let k = 0; k < commandsHelp[i].options[j].choices.length; k++) {
if (typeof commandsHelp[i].options[j].choices !== 'undefined') {
for (let k = 0; k < commandsHelp[i].options[j].choices.length; k++) {
helpJSONString += ` "${commandsHelp[i].options[j].choices[k].name}": {\n`;
helpJSONString += ` "value": "${commandsHelp[i].options[j].choices[k].value}",\n`;
helpJSONString += ' },\n';
helpJSONString += ` "${commandsHelp[i].options[j].choices[k].name}": {\n`;
helpJSONString += ` "value": "${commandsHelp[i].options[j].choices[k].value}",\n`;
helpJSONString += ' },\n';
}
}
}
}
helpJSONString += ' },\n';
helpJSONString += ' },\n';
helpJSONString += ' },\n';
helpJSONString += ' },\n';
}
}
helpJSONString += ' },\n';
helpJSONString += ' },\n';
}
helpJSONString += ' },\n';
helpJSONString += ' },\n';
}
helpJSONString += '}';
helpJSONString += '}';
// Lazy way out of removing trailing commas
// See https://stackoverflow.com/a/34347475
const helpJSON = JSON.stringify(JSON.parse(helpJSONString.replace(/,(?!\s*?[{["'\w])/g, '')), null, 4);
// Lazy way out of removing trailing commas
// See https://stackoverflow.com/a/34347475
const helpJSON = JSON.stringify(JSON.parse(helpJSONString.replace(/,(?!\s*?[{["'\w])/g, '')), null, 4);
// Create data folder if it doesn't exist
if (!fs.existsSync('data')) {
fs.mkdirSync('data');
}
// Create data folder if it doesn't exist
if (!fs.existsSync('data')) {
fs.mkdirSync('data');
}
// Write file to disk
fs.writeFile('./data/help-text.json', helpJSON, err => {
if (err) {
console.log(`Unable to write help-text.json: ${err}`);
console.log('Stopping...');
return;
}
});
// Write file to disk
fs.writeFile('./data/help-text.json', helpJSON, err => {
if (err) {
console.log(`Unable to write help-text.json: ${err}`);
console.log('Stopping...');
return;
}
});
console.log(`Successfully generated ${commandsHelp.length} help text entries.`);
console.log(`Successfully generated ${commandsHelp.length} help text entries.`);
console.log();
console.log();
// Update slash commands on Discord's side
(async () => {
try {
console.log(`Started refreshing ${commands.length} application (/) commands.`);
// Update slash commands on Discord's side
(async () => {
try {
console.log(`Started refreshing ${commands.length} application (/) commands.`);
// The put method is used to fully refresh all commands
const data = await rest.put(
Routes.applicationCommands(clientId),
{ body: commands },
);
// The put method is used to fully refresh all commands
const data = await rest.put(
Routes.applicationCommands(clientId),
{ body: commands },
);
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
}
catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}
})();
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
}
catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}
})();
}
catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
// And of course, make sure you catch and log any errors!
console.error(error);
}

110
index.js
View file

@ -28,91 +28,91 @@ const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file);
const command = require(filePath);
// Set a new item in the Collection with the key as the command name and the value as the exported module
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
}
else {
logger.log(logger.logLevels.WARN, `The command at ${filePath} is missing a required "data" or "execute" property.`);
}
const filePath = path.join(commandsPath, file);
const command = require(filePath);
// Set a new item in the Collection with the key as the command name and the value as the exported module
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
}
else {
logger.log(logger.logLevels.WARN, `The command at ${filePath} is missing a required "data" or "execute" property.`);
}
}
// When the client is ready, run this code (only once)
// We use 'c' for the event parameter to keep it separate from the already defined 'client'
client.once(Events.ClientReady, c => {
logger.log(logger.logLevels.INFO, `${logger.colorText('Ready!', logger.textColor.Green)} Logged in as ${logger.colorText(c.user.tag, logger.textColor.Blue)}`);
client.user.setPresence({ activities: [{ name: activity }], status: status });
logger.log(logger.logLevels.INFO, `${logger.colorText('Ready!', logger.textColor.Green)} Logged in as ${logger.colorText(c.user.tag, logger.textColor.Blue)}`);
client.user.setPresence({ activities: [{ name: activity }], status: status });
// Track websocket heartbeat with PM2 Histogram
let latency = 0;
setInterval(function() {
latency = c.ws.ping;
metrics.websocketHeartbeatHist.update(latency);
}, 1000);
// Track websocket heartbeat with PM2 Histogram
let latency = 0;
setInterval(function() {
latency = c.ws.ping;
metrics.websocketHeartbeatHist.update(latency);
}, 1000);
// Report current server count with PM2 (Servers counted anonymously)
metrics.serverCount.set(c.guilds.cache.size);
// Report current server count with PM2 (Servers counted anonymously)
metrics.serverCount.set(c.guilds.cache.size);
});
// Client "on" Events
// Someone used an interaction
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isChatInputCommand()) return;
if (!interaction.isChatInputCommand()) return;
const command = interaction.client.commands.get(interaction.commandName);
const command = interaction.client.commands.get(interaction.commandName);
if (!command) {
logger.log(logger.logLevels.ERROR, `No command matching ${interaction.commandName} was found.`);
await interaction.reply({ content: `This command no longer exists! Please contact ${botOwner} to report that this is happening!`, ephemeral: true });
if (!command) {
logger.log(logger.logLevels.ERROR, `No command matching ${interaction.commandName} was found.`);
await interaction.reply({ content: `This command no longer exists! Please contact ${botOwner} to report that this is happening!`, ephemeral: true });
// Report error to PM2 dashboard
metrics.interactionErrors.inc();
metrics.io.notifyError(new Error('Interaction doesn\'t exist'), {
custom: {
interactionCommand: interaction.commandName,
},
});
// Report error to PM2 dashboard
metrics.interactionErrors.inc();
metrics.io.notifyError(new Error('Interaction doesn\'t exist'), {
custom: {
interactionCommand: interaction.commandName,
},
});
return;
}
return;
}
try {
await command.execute(interaction);
}
catch (error) {
logger.log(logger.logLevels.ERROR, error);
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
try {
await command.execute(interaction);
}
catch (error) {
logger.log(logger.logLevels.ERROR, error);
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
// Report error to PM2 dashboard
metrics.interactionErrors.inc();
metrics.io.notifyError(new Error('Error executing interaction'), {
custom: {
interactionCommand: interaction.commandName,
error: error,
},
});
// Report error to PM2 dashboard
metrics.interactionErrors.inc();
metrics.io.notifyError(new Error('Error executing interaction'), {
custom: {
interactionCommand: interaction.commandName,
error: error,
},
});
}
}
// Successful Execution, report as a PM2 metric
// If the bot gets a lot of use, consider removing this for performance
metrics.interactionSuccess();
// Successful Execution, report as a PM2 metric
// If the bot gets a lot of use, consider removing this for performance
metrics.interactionSuccess();
});
// Joined a server
client.on(Events.GuildCreate, guild => {
// Report current server count with PM2 (Servers counted anonymously)
metrics.serverCount.set(guild.client.guilds.cache.size);
// Report current server count with PM2 (Servers counted anonymously)
metrics.serverCount.set(guild.client.guilds.cache.size);
});
// Removed from a server
client.on(Events.GuildDelete, guild => {
// Report current server count with PM2 (Servers counted anonymously)
metrics.serverCount.set(guild.client.guilds.cache.size);
// Report current server count with PM2 (Servers counted anonymously)
metrics.serverCount.set(guild.client.guilds.cache.size);
});
// Log in to Discord with your client's token