diff --git a/.gitignore b/.gitignore index 3cb8b87..7332d79 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ backup.json *.txt !spec/LevelsXP.txt *.sqlite -temp.js \ No newline at end of file +temp.js + +easySetup.js \ No newline at end of file diff --git a/commands/admin/setup.js b/commands/admin/setup.js index 1050e0f..d58023b 100644 --- a/commands/admin/setup.js +++ b/commands/admin/setup.js @@ -6,13 +6,6 @@ const { checkRole } = require('./verify.js'); const fetch = require('node-fetch'); -async function setWelcomeChannel(dbo, message, channelname) { - const channel = message.guild.channels.cache.find(ch => ch.name === channelname); - dbo.insertOne({welcomechannel: channel}); -} - - - async function execute(interaction, Discord, Client, bot) { const server = interaction.guildId; const owner = interaction.guild.members.cache.get(interaction.guild.ownerId); @@ -46,19 +39,22 @@ async function execute(interaction, Discord, Client, bot) { dbo.updateOne({welcomechannel: {$exists: true}}, {$set: {welcomechannel: `${channel.id}`}}); interaction.reply({content: `Set ${channel} as the new welcome channel`, ephemeral: true}) - } else if (command == 'welcome_message') { + } + else if (command == 'welcome_message') { // if (args.length < 2) { return interaction.reply('The command format is _!setup welcome\\_message_\nUse _{sn}_ to insert the server name, _{un}_ to insert the user name, and _{ut}_ to insert the user tag\nExample: _!setup welcome\\_message Welcome to {sn} Sir {un}#{ut}_'); } const msg = args[i].value; if (msg.length > 30 || msg.length < 1) { return interaction.reply({content: 'Please specify a welcome message between 0 and 30 characters!', ephemeral: true}); } dbo.updateOne({welcomemessage: {$exists: true}}, {$set: {welcomemessage: msg}}) - } else if (command == 'keep_logs') { + } + else if (command == 'keep_logs') { let keeplogs = args[i].value; dbo.updateOne({ _id: 'LOG'}, {$set: {keepLogs: keeplogs}}); interaction.reply({content: `Toggled log keeping to ${keeplogs}. Please use _!setup log_channel_ to choose the log channel`, ephemeral: true}); - } else if (command == 'log_channel') { + } + else if (command == 'log_channel') { // if (args.length != 2) { return message.reply('Please specify a parameter\nExample: _!setup log\\_channel true_'); } const channel = args[i].channel; @@ -66,7 +62,8 @@ async function execute(interaction, Discord, Client, bot) { dbo.updateOne({_id: 'LOG'}, {$set: {logchannel: `${channel.id}`}}); interaction.reply({content: `Made ${channel} the new Selmer Bot Logs channel!`, ephemeral: true}); - } else if (command == 'log_severity') { + } + else if (command == 'log_severity') { const tier = args[i].value; const l = ['none', 'low', 'medium', 'high']; if (!l.includes(tier)) { return interaction.reply({content: "Please select an existing tier ('none', 'low', 'medium', 'high')", ephemeral: true}); } @@ -74,7 +71,8 @@ async function execute(interaction, Discord, Client, bot) { dbo.updateOne({_id: 'LOG'}, {$set: {severity: tier}}) interaction.reply({content: `Severity updated to ${tier}`, ephemeral: true}); - } else if (command == 'announcement_role') { + } + else if (command == 'announcement_role') { const role = args[i].value; // if (message.mentions.roles.first() == undefined) { // return message.reply("Please mention a role (_!setup announcement\\_role **@role**_)\n_Note: Selmer Bot does NOT ping the @everyone role_"); @@ -83,12 +81,14 @@ async function execute(interaction, Discord, Client, bot) { dbo.updateOne({_id: 'announcement'}, { $set: { 'role': role.id } }); interaction.reply({content: `Role updated to ${role}`, ephemeral: true}); - } else if (command == "announcement_channel") { + } + else if (command == "announcement_channel") { const channel = args[i].channel; if (!channel) { return interaction.reply({content: 'The specified channel does not exist!', ephemeral: true}); } dbo.updateOne({_id: 'announcement'}, { $set: { 'channel': channel.id } }); - } else if (command == "add_mod_role") { + } + else if (command == "add_mod_role") { dbo.findOne({_id: "roles"}).then((doc) => { const role = args[i].value; if (!doc.commands.includes(role)) { @@ -98,16 +98,19 @@ async function execute(interaction, Discord, Client, bot) { interaction.reply({ content: "This role is already a command role!", ephemeral: true }); } }); - } else if (command == "remove_mod_role") { + } + else if (command == "remove_mod_role") { dbo.updateOne({_id: "roles"}, { $pull: { commands: { $in: [ args[i].value ] }} }); interaction.reply({ content: "Role removed!", ephemeral: true }); - } else if (command == "welcome_banner") { + } + else if (command == "welcome_banner") { const response = await fetch(interaction.options.data[0].attachment.attachment); const arrayBuffer = await response.arrayBuffer(); const imgbfr = Buffer.from(arrayBuffer); dbo.updateOne({_id: 'WELCOME'}, {$set: {welcomebanner: imgbfr.toString('base64')}}); interaction.reply({ content: "Banner updated!", ephemeral: true }); - } else if ("welcome_text_color") { + } + else if ("welcome_text_color") { const reg = /^#[0-9A-F]{6}$/i; const newCol = interaction.options.data[0].value; if (reg.test(newCol)) { @@ -116,8 +119,8 @@ async function execute(interaction, Discord, Client, bot) { } else { interaction.reply("Please chose a valid hex color"); } - - } else { + } + else { interaction.reply({content: "Please chose a valid option", ephemeral: true}); } /* Made obsolete by the change to Slash Commands @@ -146,8 +149,6 @@ async function execute(interaction, Discord, Client, bot) { - - module.exports = { name: 'setup', description: 'Set up server features', diff --git a/commands/games/external_game_functions.js b/commands/games/external_game_functions.js index 6a84b3c..8ba2ebb 100644 --- a/commands/games/external_game_functions.js +++ b/commands/games/external_game_functions.js @@ -5,16 +5,16 @@ const { addComplaintButton } = require('../dev only/submitcomplaint'); //#region game lose/win -function loseGame(user_dbo, xp_collection, message, bot = null) { +function loseGame(user_dbo, xp_collection, interaction, bot = null) { return new Promise(function(resolve, reject) { - user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){ + user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs) { const doc = docs[0]; if (doc == undefined) { - message.reply("Oops! There's been an error, click the ✅ to report this!"); - addComplaintButton(bot, message); + interaction.reply("Oops! There's been an error, click the ✅ to report this!"); + addComplaintButton(bot, interaction); return; } - if (doc.game == null) { return message.reply("You're not even in a game and you're trying to quit! Sad..."); } + if (doc.game == null) { return interaction.reply("You're not even in a game and you're trying to quit! Sad..."); } var addbal; //If this function was called from "winGame", return @@ -25,10 +25,13 @@ function loseGame(user_dbo, xp_collection, message, bot = null) { if (doc.balance > 5) { user_dbo.updateOne(doc, { $set: { balance: doc.balance - addbal}}); } - } else { message.channel.delete(); } + } else { + //Check if the channel is a thread + interaction.channel.delete(); + } //Update the player's xp - addxp(message, user_dbo, Math.ceil((BASE.XP * doc.rank)/2),xp_collection) + addxp(interaction, user_dbo, Math.ceil((BASE.XP * doc.rank)/2),xp_collection) user_dbo.updateOne({"game": {$exists: true}}, { $set: { game: null, opponent: null, state: STATE.IDLE, 'hpmp.hp': doc.hpmp.maxhp, 'hpmp.mp': doc.hpmp.maxmp }}); resolve(addbal); @@ -38,14 +41,14 @@ function loseGame(user_dbo, xp_collection, message, bot = null) { } -function winGame(client, bot, db, user_dbo, xp_collection, message, singlePlayer = false) { +function winGame(client, bot, db, user_dbo, xp_collection, interaction, singlePlayer = false) { user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){ const doc = docs[0]; //Check for an opponent if (doc.opponent != null) { let other = db.collection(doc.opponent); - let promise_temp = loseGame(other, xp_collection, message); + let promise_temp = loseGame(other, xp_collection, interaction); promise_temp.then(function(result) { var amt_taken = result; @@ -55,7 +58,7 @@ function winGame(client, bot, db, user_dbo, xp_collection, message, singlePlayer //Delete the bot's record of the game if (!singlePlayer) { - client.db('B|S' + bot.user.id).collection(message.guild.id).drop(); + client.db('B|S' + bot.user.id).collection(interaction.guildId).drop(); } @@ -63,16 +66,16 @@ function winGame(client, bot, db, user_dbo, xp_collection, message, singlePlayer user_dbo.updateOne({"game": {$exists: true}}, { $set: { game: null, opponent: null, state: STATE.IDLE, xp: doc.xp + (BASE.XP * doc.rank), 'hpmp.hp': doc.hpmp.maxhp, 'hpmp.mp': doc.hpmp.maxmp }}); if (!singlePlayer) { - const channel = bot.channels.cache.get(message.channel.parentId); + const channel = bot.channels.cache.get(interaction.channel.parentId); channel.send(`<@${user_dbo.s.namespace.collection}> just won a game of "${docs[0].game}"!`); } - message.channel.delete(); + interaction.channel.delete(); }); } -function equipItem(client, bot, db, dbo, message) { - +function equipItem(client, bot, db, dbo, interaction) { + return interaction.reply("This command is not implemented yet!"); if (!bot.inDebugMode) { return; } let items = [ { name: 'HP Potion', cost: 20, icon: 'CUSTOM|healing_potion', sect: 'HP', num: 2 }, diff --git a/commands/games/game.js b/commands/games/game.js index 01b17a9..20282bd 100644 --- a/commands/games/game.js +++ b/commands/games/game.js @@ -1,7 +1,7 @@ // // @ts-check //Disabled // Maybe have the interaction type be "user" https://canary.discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-types - +const { MessageActionRow, MessageButton, Message } = require('discord.js'); const { MongoClient, ServerApiVersion } = require('mongodb'); let ecoimport = require("../db/econ.js"); @@ -71,18 +71,18 @@ async function Initialize(bot, user_dbo, command, message, first, second, other_ //#endregion //replies to the message with current game specifics -function getGame(message, args, db) { +function getGame(interaction, args, db) { let id; var temp; if (args.length == 1 && String(args[0]).startsWith('<')) { id = args[0].substr(2, args[0].length - 3)} - else { id = message.author.id; } - var user_dbo = db.collection(message.author.id); + else { id = interaction.user.id; } + var user_dbo = db.collection(interaction.user.id); user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){ const doc = docs[0]; if (doc.game == null) { - return message.reply(`<@${id}> is not currently playing a game!`); + return interaction.reply(`<@${id}> is not currently playing a game!`); } temp = `<@${id}> is currently playing "${doc.game}"`; @@ -91,58 +91,64 @@ function getGame(message, args, db) { temp += ` with <@${doc.opponent}>` } - message.reply(temp); + interaction.reply(temp); }); } -function acceptIsValid(bot, other_discord, message, msg, tag_len) { +function acceptIsValid(bot, other_discord, interaction, invUserId, message) { if (other_discord == undefined) { - message.reply("This is not a valid invite!"); + interaction.reply("This is not a valid invite!"); return false; } //Make sure the bot was the one creating the invite - let check0 = msg.author.bot; + let check0 = message.author.bot; //Author - let tag = msg.content.substr(2, tag_len); - let check1 = Number(tag) == Number(message.author.id); + let check1 = Number(other_discord.id) == Number(invUserId); //Time (within the last 5 min) - let prev = snowflake.convertSnowflakeToDate(msg.id); - let now = snowflake.convertSnowflakeToDate(message.id); + let prev = snowflake.convertSnowflakeToDate(message.id); + let now = snowflake.convertSnowflakeToDate(interaction.id); // @ts-ignore let diff = now - prev; var minutes = Math.floor((diff/1000)/60); let check2 = minutes <= 5 || bot.inDebugMode; - if (!check0) { message.reply("really?"); } - else if (!check1 && check2) { message.reply("_INVALID USER_"); } - else if (check1 && !check2) { message.reply("_THIS INVITE EXPIRED!_"); } - else if (!check1 && !check2) { message.reply("_THIS MESSAGE HAS AN INVALID USER AND HAS EXPIRED_")} + if (!check0) { interaction.reply("really?"); } + else if (!check1 && check2) { interaction.reply("_INVALID USER_"); } + else if (check1 && !check2) { interaction.reply("_THIS INVITE EXPIRED!_"); } + else if (!check1 && !check2) { interaction.reply("_THIS MESSAGE HAS AN INVALID USER AND HAS EXPIRED_")} return (check0 && check1 && check2); } -function hpmp(message, command, dbo) { +function hpmp(interaction, command, dbo) { // throw 'THIS HAS NOT BEEN UPDATED WITH THE MOST RECENT VERSION OF THE MONGODB STRUCTURE!'; + + dbo.find({"hpmp": {$exists: true}}).toArray(function(err, doc) { + interaction.reply(`You have ${String(doc[0].hpmp.hp)} hp and ${String(doc[0].hpmp.mp)} mp left!`); + }); + + /* if (command == 'hp') { dbo.find({"hpmp": {$exists: true}}).toArray(function(err, doc) { - return message.reply(`You have ${String(doc[0].hpmp.hp)} hp left!`); + return interaction.reply(`You have ${String(doc[0].hpmp.hp)} hp left!`); }); } else if (command == 'mp') { dbo.find({"hpmp": {$exists: true}}).toArray(function(err, doc) { - return message.reply(`You have ${String(doc[0].hpmp.hp)} mp left!`); + return interaction.reply(`You have ${String(doc[0].hpmp.MP)} mp left!`); }); } + */ } -function equip(message, args, command, dbo, bot, shop) { - const inp = args[1]; - if (!inp) { return message.reply("Please provide input (either a weapon for main or shield for secondary)")} +function equip(interaction, inp, command, dbo, bot, shop) { + // const inp = args[1]; + if (!inp) { return interaction.reply("Please provide input (either a weapon for main or shield for secondary)"); } //Check if the user is already in a game dbo.find({'game': {$exists: true}}).toArray(function(err, docs) { @@ -151,7 +157,7 @@ function equip(message, args, command, dbo, bot, shop) { if (doc.game != null) { ret = true; // console.log(doc.game); - return message.reply('You can\'t equip while in a game!'); + return interaction.reply('You can\'t equip while in a game!'); } //If the thing is a shield, add it to secondary @@ -160,7 +166,7 @@ function equip(message, args, command, dbo, bot, shop) { if (docs[0] != undefined) { dbo.updateOne({}, {$set: {'equipped.weapons.secondary': docs[0]}}); } else { - message.reply("You don't own a shield!"); + interaction.reply("You don't own a shield!"); } }); @@ -172,7 +178,7 @@ function equip(message, args, command, dbo, bot, shop) { //Equip the weapon dbo.updateOne({}, {$set: {'equipped.weapons.main': docs[0]}}); } else { - message.reply(`You don't own any ${inp}s!`); + interaction.reply(`You don't own any ${inp}s!`); } }); } @@ -200,7 +206,7 @@ function in_game_redirector(bot, interaction, threadname, doc, client, mongouri, dbo.find({'game': {$exists: true}}).toArray(function (err, docs) { const game = docs[0].game - + switch (game) { case 'battle': battle.handle(client, dbo, other, bot, thread, interaction.customId.toLowerCase(), mongouri, items, interaction, xp_collection); break; @@ -215,12 +221,11 @@ function in_game_redirector(bot, interaction, threadname, doc, client, mongouri, module.exports ={ name: "game", description: "Play a game using Selmer Bot!", - async execute(bot, message, args, command, Discord, mongouri, items, xp_collection) { - + async execute(bot, interaction, command, Discord, mongouri, items, xp_collection) { //#region Setup - const id = message.author.id; - const server = message.guild.id; + const id = interaction.user.id; + const server = interaction.guildId; // // @ts-ignore // const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 }); @@ -237,12 +242,12 @@ module.exports ={ const serverinbotdb = botdb.collection(server); //Initialize if necessary - ecoimport.CreateNewCollection(message, client, server, id); - command = args[0]; + ecoimport.CreateNewCollection(interaction, client, server, id); + var commandName = command.name; //Check for a second person and create a second database entry if neccessary - if (message.mentions.users.first() != undefined) { - ecoimport.CreateNewCollection(message, client, server, message.mentions.users.first().id); + if (command.options && command.options.length > 0 && command.options[0].type == "USER") { + ecoimport.CreateNewCollection(interaction, client, server, command.options[0].value); } //#endregion @@ -260,41 +265,30 @@ module.exports ={ //#region non-game-specific commands //For TWO+ PLAYER games only!!! - if (command == 'accept') { - //Handle the messages - if (message.reference == null) { return message.reply("Please reply to a valid battle request message!"); } - let mid = message.reference.messageId; - let msg = await message.channel.messages.fetch(mid); - - //Check if the person actually challenged you - //Get the length of any user tag - let mentioned = msg.mentions.users.keys(); - - let tag_len = String(mentioned.next().value).length; - - //<@tage_len>, <@ --2+tag_len+2+3 = 7+tag_len - let other_tag = msg.content.substr(7+tag_len, tag_len); - - const other_discord = msg.mentions.users.get(other_tag); + if (commandName == 'accept') { + const args = interaction.customId.split('|'); + // console.log(interaction.message.interaction); + // console.log(interaction.user); + // return console.log(args); //Should also check if the player is already playing a game!!! - if (!acceptIsValid(bot, other_discord, message, msg, tag_len)) { return; } + if (!acceptIsValid(bot, interaction.user, interaction, args[1], interaction.message)) { return; } //Get the opponent - const other = db.collection(other_discord.id); - let startPos = msg.content.indexOf('"') + 1; - let newCommand = msg.content.substr(startPos, msg.content.lastIndexOf('"') - startPos); - - + const other_id = interaction.message.interaction.user.id; + const other = db.collection(other_id); + // return console.log(args, interaction.message.interaction); + let newCommand = interaction.message.interaction.commandName.split(" ")[1]; + //#region BOT SECTION //Store both IDs in the database (for turns) let name_first = await bot.users.cache.get(id); - let name_second = await bot.users.cache.get(other_discord.id); + let name_second = await bot.users.cache.get(other_id); // message.reply(`${first} [${name_first}], ${second} [${name_second}]`); throw 'ERR'; const threadname = `${name_first.username} VS ${name_second.username} [${newCommand.toUpperCase()}]`; - var newObj = {0: id, 1: other_discord.id, turn: 0, thread: threadname}; + var newObj = {0: id, 1: other_id, turn: 0, thread: threadname}; if (newCommand.replaceAll(" ", "").toLowerCase() == 'tictactoe') { newCommand = 'Tic Tac Toe'; } @@ -318,90 +312,110 @@ module.exports ={ //#endregion - + const remAccptBtn = (msgToDel) => { + try { + msgToDel.edit({components: []}); + } catch(err) { + console.error(err); + } + } //Need this for all 2 player games - const result = Initialize(bot, dbo, newCommand, msg, id, other_discord.id, other); + const result = Initialize(bot, dbo, newCommand, interaction.message, id, other_id, other); if (newCommand == 'battle') { result.then(function (thread) { battle.handle(client, dbo, other, bot, thread, 'initalize', mongouri, items, null, xp_collection); + remAccptBtn(interaction.message); }); } else if (newCommand == 'Tic Tac Toe') { result.then(function (thread) { ttt.handle(client, db, dbo, other, bot, thread, 'initalize', mongouri, null, xp_collection); + remAccptBtn(interaction.message); }); } - } else if (command == 'quit') { + } else if (commandName == 'quit') { + + const channel = bot.channels.cache.get(interaction.channel.parentId); - const channel = bot.channels.cache.get(message.channel.parentId); //Remove the turn counter from the bot's database serverinbotdb.deleteOne({0: id} || {1: id}); if (doc.opponent != null) { // let other = message.guild.members.cache.get(doc.opponent); let other = db.collection(doc.opponent); - channel.send(`<@${message.author.id}> has quit a game of "${game}" with <@${doc.opponent}>!`); - winGame(client, bot, db, other, xp_collection, message); + channel.send(`<@${interaction.user.id}> has quit a game of "${game}" with <@${doc.opponent}>!`); + winGame(client, bot, db, other, xp_collection, interaction); } else { - loseGame(dbo, xp_collection, message, bot); - channel.send(`<@${message.author.id}> has quit a game of "${game}"!`); + loseGame(dbo, xp_collection, interaction, bot); + channel.send(`<@${interaction.user.id}> has quit a game of "${game}"!`); } } - else if (command == 'status') { - getGame(message, args, db); - } else if (command == 'hp' || command == 'mp') { - hpmp(message, command, dbo); + else if (commandName == 'status') { + getGame(interaction, args, db); + } else if (commandName == 'hpmp') { + hpmp(interaction, commandName, dbo); } else if (command == 'equip') { // equipItem(client, bot, db, dbo, message); - equip(message, args, command, dbo, bot, items); + // This does not work + equip(interaction, args, command, dbo, bot, items); } else if (command == 'classes') { + // This does not work presentClasses(message, args[1]); } //#endregion //#region game-specific commands else { - if (command == undefined) { return message.reply("Please specify a game or use _!game help_"); } + if (commandName == undefined) { return interaction.reply("Please specify a game or use _!game help_"); } //Make change to new name if necessary - if (command.replaceAll(" ", "").toLowerCase() == 'tictactoe') { command = 'Tic Tac Toe'; } + if (commandName.replaceAll(" ", "").toLowerCase() == 'tictactoe') { commandName = 'Tic Tac Toe'; } - if (game == 'battle' || command == 'battle') { - if (!bot.inDebugMode) { return message.reply("This command is currently in development!"); } + //RETURN TO THIS LATER + if (game == 'battle' || commandName == 'battle') { + if (!bot.inDebugMode) { return interaction.reply("This command is currently in development!"); } - //Handle sending the request and making sure the user exists here - let other_discord = message.mentions.users.first(); - if (other_discord == undefined) { - return message.reply(`"${args[1]}" is not a valid user (use _!game battle @user_)`); - } - - message.channel.send(`${other_discord}, <@${message.author.id}> has invited you to play _"battle"_. To accept, please reply to this message with _!game accept_`); - } else if (game == 'Tic Tac Toe' || command == 'Tic Tac Toe') { - let other_discord = message.mentions.users.first(); - if (other_discord == undefined) { - return message.reply(`"${args[1]}" is not a valid user (use _!game tictactoe @user_)`); - } - - message.channel.send(`${other_discord}, <@${message.author.id}> has invited you to play _"Tic Tac Toe"_. To accept, please reply to this message with _!game accept_`); - } else if (game == 'trivia' || command == 'trivia') { - trivia.execute(message, args, Discord, client, bot); - } else if (game == "minesweeper" || command == 'minesweeper') { - if (game == "minesweeper" && command == 'minesweeper') { + const row = new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId(`gameaccept|${command.options[0].value}|${interaction.user.id}`) + .setLabel('Accept Invite') + .setStyle('SUCCESS') + ); + + const content = {content: `${command.options[0].user}, ${interaction.user} has invited you to play _"Tic Tac Toe"_. Click the button to accept the invitation!`, components: [row]}; + interaction.reply(content).catch((err) => interaction.channel.send(content)); + + } else if (game == 'Tic Tac Toe' || commandName == 'Tic Tac Toe') { + const row = new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId(`gameaccept|${command.options[0].value}|${interaction.user.id}`) + .setLabel('Accept Invite') + .setStyle('SUCCESS') + ); + + const content = {content: `${command.options[0].user}, ${interaction.user} has invited you to play _"Tic Tac Toe"_. Click the button to accept the invitation!`, components: [row]}; + interaction.reply(content).catch((err) => interaction.channel.send(content)); + } else if (game == 'trivia' || commandName == 'trivia') { + trivia.execute(interaction, Discord, client, bot); + } else if (game == "minesweeper" || commandName == 'minesweeper') { + if (game == "minesweeper" && commandName == 'minesweeper') { return message.reply("You're already in a game!"); } - const threadname = `${message.author.username} has started a solo game of Minesweeper`; - const thread = await message.channel.threads.create({ + const threadname = `${interaction.user.username} is playing Minesweeper`; + const thread = await interaction.channel.threads.create({ name: threadname, // type: 'GUILD_PRIVATE_THREAD', autoArchiveDuration: 60, reason: `N/A`, }); - mnswpr.handle(bot, null, thread, message, args); + mnswpr.handle(bot, interaction, thread); } //Catch statement (invalid command) else { - message.reply(`'${bot.prefix}game ${command}' is not a command!`); + interaction.reply(`'/game ${commandName}' is not a command!`); } } //#endregion diff --git a/commands/games/gameCommandOptions.js b/commands/games/gameCommandOptions.js new file mode 100644 index 0000000..488a1ee --- /dev/null +++ b/commands/games/gameCommandOptions.js @@ -0,0 +1,61 @@ +const { Constants } = require('discord.js'); +const { trivia_categories } = require('./trivia_categories.json'); + +module.exports = [ + { + name: "trivia", + description: 'Start a game of Trivia', + type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND, + options: [ + {name: 'difficulty', description: 'The question difficulty OR "help"', type: Constants.ApplicationCommandOptionTypes.STRING, required: true, choices: [{name: 'easy', value: 'easy'}, {name: 'medium', value: 'medium'}, {name: 'hard', value: 'hard'}]}, + {name: 'category', description: 'The trivia Category', type: Constants.ApplicationCommandOptionTypes.INTEGER, required: false, choices: trivia_categories}, + {name: 'time', description: 'Set the round length (in seconds)', type: Constants.ApplicationCommandOptionTypes.INTEGER, required: false}, + ]}, + + { + name: "battle", + description: 'Start a game of Batte', + type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND, + options: [ + {name: 'opponent', description: 'Who do you want to battle against?', type: Constants.ApplicationCommandOptionTypes.USER, required: true}, + ]}, + + { + name: "minesweeper", + description: "Start a game of Minesweeper", + type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND, + options: [ + {name: 'difficulty', description: 'Set the diffficulty', type: Constants.ApplicationCommandOptionTypes.STRING, required: true, choices: [{name: 'easy', value: 'easy'}, {name: 'medium', value: 'medium'}, {name: 'hard', value: 'hard'}]}, + // {name: 'opponent', description: 'Play a game against someone else', type: Constants.ApplicationCommandOptionTypes.USER, required: false} + ] + }, + + { + name: "tictactoe", + description: 'Start a game of TicTacToe', + type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND, + options: [ + {name: 'opponent', description: 'Who do you want to play against?', type: Constants.ApplicationCommandOptionTypes.USER, required: true}, + ]}, + + { + name: "quit", + description: "Quit your current game", + type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND, + options: [] + }, + + { + name: "status", + description: "Check your current game status", + type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND, + options: [] + }, + + { + name: "hpmp", + description: "Check your current game status", + type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND, + options: [] + }, +] \ No newline at end of file diff --git a/commands/games/minesweeper.js b/commands/games/minesweeper.js index 090a427..60bbcd9 100644 --- a/commands/games/minesweeper.js +++ b/commands/games/minesweeper.js @@ -3,23 +3,24 @@ const { winGame, loseGame, equipItem } = require('./external_game_functions.js') const wait = require('node:timers/promises').setTimeout; const { STATE } = require('../db/econ.js') -function startGame(bot, channel, message, args) { +function startGame(bot, channel, interaction) { + const args = interaction.options.data; let componentlist = []; var diff; - if (args.length < 1 || args[0] == 'easy') { + if (args.length < 1 || args[0].value == 'easy') { diff = 0; - } else if (args[0] == 'medium') { + } else if (args[0].value == 'medium') { diff = 0.1; - } else if (args[0] == 'hard') { + } else if (args[0].value == 'hard') { diff = 0.2; } else { diff = 0; } let user = ''; - if (args.length < 2 || args[1] == 'solo') { - user = message.author.id; + if (args.length < 2) { + user = interaction.user.id; } for (let i = 0; i < 5; i ++) { @@ -45,6 +46,7 @@ function startGame(bot, channel, message, args) { componentlist.push(row); } + interaction.reply(`${interaction.user} has started a solo game of Minesweeper!`); channel.send({ content: `SCORE: \`0\`\nTILES LEFT: \`25\``, components: componentlist }); } @@ -90,7 +92,7 @@ async function changeBoard(bot, interaction, xp_collection) { const user = id[4]; if (user && user != '') { if (interaction.user.id != user) { - interaction.user.send(`Message from a Minesweeper game in <#${interaction.channel.id}>: ***It's not your turn!***`); + interaction.user.send(`Message from a Minesweeper game in <#${interaction.channel.id}>: ***This is a solo game!***`); return; // interaction.reply({ content: "It's not your turn!", ephemeral: true }); //Can only reply once } } @@ -103,7 +105,7 @@ async function changeBoard(bot, interaction, xp_collection) { bot.mongoconnection.then((client) => { client.db(interaction.guildId).collection(interaction.user.id).updateOne({ game: {$exists: true} }, { $set: { game: null } }); }); const channel = bot.channels.cache.get(interaction.message.channel.parentId); channel.send(`${interaction.user} found a bomb in Minesweeper!`); - interaction.channel.send(`\`Thread closing\` `); + interaction.channel.send(`\`Thread closing\` `); await wait(7000); interaction.channel.delete(); @@ -140,29 +142,34 @@ async function changeBoard(bot, interaction, xp_collection) { } -function checkAndStartGame(bot, message, channel, args) { +function checkAndStartGame(bot, interaction, channel) { bot.mongoconnection.then(client => { - const db = client.db(message.guild.id); - const dbo = db.collection(message.author.id); + const db = client.db(interaction.guildId); + const dbo = db.collection(interaction.user.id); dbo.findOne({game: {$exists: true}}).then((doc) => { try { - if (doc.game != null) { return message.reply("You're already in a game!"); } + if (doc.game != null) { + console.log(doc); + return interaction.reply("You're already in a game!").catch((err) => { + interaction.channel.send("You're already in a game!"); + }); + } dbo.updateOne({ "game": {$exists: true} }, { $set: { game: "minesweeper", state: STATE.FIGHTING }}); - startGame(bot, channel, message, args); + startGame(bot, channel, interaction); } catch (err) { console.log(err); const { addComplaintButton } = require('../dev only/submitcomplaint.js'); - addComplaintButton(bot, message); + addComplaintButton(bot, interaction.message); } }); }); } -function handle(bot, interaction, channel = null, message = null, args = null, xp_collection = null) { - if (channel != null && args != null) { - checkAndStartGame(bot, message, channel, args); +function handle(bot, interaction, channel = null, isStart = true, xp_collection = null) { + if (isStart) { + checkAndStartGame(bot, interaction, channel); } else { //Maybe add player checking later? changeBoard(bot, interaction, xp_collection); diff --git a/commands/games/tictactoe.js b/commands/games/tictactoe.js index 276bfb3..0782117 100644 --- a/commands/games/tictactoe.js +++ b/commands/games/tictactoe.js @@ -124,7 +124,6 @@ async function handle(client, db, dbo, other, bot, thread, command, doc, interac let board = ["", "", "", "", "", "", "", "", ""]; postActionBar(thread, dbo, board, false,true); } else { - //Change the board let square = Number(interaction.customId.split('|')[1]); let symbol = doc.symbols[doc.turn]; @@ -143,6 +142,8 @@ async function handle(client, db, dbo, other, bot, thread, command, doc, interac changeTurn(client, bot, interaction); } else { postActionBar(interaction, dbo, board, won); + + //Maybe add a "close board" button instead of this await wait(7000); winGame(client, bot, db, dbo, xp_collection, interaction.message); } diff --git a/commands/games/trivia.js b/commands/games/trivia.js index edef3f5..300fa1f 100644 --- a/commands/games/trivia.js +++ b/commands/games/trivia.js @@ -3,11 +3,12 @@ const fetch = require('node-fetch'); const categoriesJSON = require('./trivia_categories.json').trivia_categories; const { decode } = require('html-entities'); const { MongoClient, ServerApiVersion } = require('mongodb'); +const { Interaction } = require('discord.js'); const categories = new Map(); for (i in categoriesJSON) { - categories.set(categoriesJSON[i].name, categoriesJSON[i].id); + categories.set(categoriesJSON[i].name, categoriesJSON[i].value); } // const { jsonToMapRecursive, mapToTableRecursive } = require('../utils/jsonFormatters.js'); @@ -41,11 +42,11 @@ function changeDB(bot, message, m) { /** - * @param {*} message + * @param {Interaction} interaction * @param {Map} m * @param {int} time */ -function startTrivia(message, m, time, bot) { +function startTrivia(interaction, m, time, bot) { var iter = m.values().next(); var obj = iter.value; @@ -63,8 +64,10 @@ function startTrivia(message, m, time, bot) { return (response.content.toLowerCase() == answer.toLowerCase()); }; - message.reply({ content: `${question}\n(Type your answers below!)`, fetchReply: true }) - .then(() => { + interaction.channel.send({ content: `${question}\n(Type your answers below!)`, fetchReply: true }) + .then((message) => { + interaction.reply({content: `Trivia started by ${interaction.user}`}); + const timeList = ['🔟', '9️⃣', '8️⃣', '7️⃣', '6️⃣', '5️⃣', '4️⃣', '3️⃣', '2️⃣', '1️⃣', '0️⃣' ]; var i = 0; const intId = setInterval(() => { if (i < timeList.length) { message.react(timeList[i]); i++ } }, Math.round(time/11)); @@ -72,9 +75,9 @@ function startTrivia(message, m, time, bot) { message.channel.awaitMessages({ filter, max: 10, time: time }) // , errors: ['time'] .then((collected) => { if (collected.size > 0) { - message.reply(`${collected.first().author} got the correct answer (${answer})!`); + message.reply(`${collected.first().author} got the correct answer (||${answer}||) first!`); } else { - message.reply('Tsk Tsk, looks like nobody got the answer this time.'); + message.reply(`Tsk Tsk, looks like nobody got the answer (||${answer}||) this time.`); } // changeDB(bot, message, null); @@ -82,7 +85,7 @@ function startTrivia(message, m, time, bot) { }) .catch((collected) => { console.log(collected); - message.reply('Tsk Tsk, looks like nobody got the answer this time.'); + message.reply(`Tsk Tsk, looks like nobody got the answer (||${answer}||) this time.`); // changeDB(bot, message, null); clearInterval(intId); }); @@ -94,25 +97,31 @@ function startTrivia(message, m, time, bot) { module.exports = { name: 'trivia', - async execute(message, args, Discord, Client, bot) { - const difficult = ['easy', 'medium', 'hard']; + async execute(interaction, Discord, Client, bot) { + const opts = interaction.options.data[0].options; + const args = []; + args[0] = opts.filter((o) => { return (o.name == 'difficulty'); })[0]; + args[1] = opts.filter((o) => { return (o.name == 'category'); })[0]; + args[2] = opts.filter((o) => { return (o.name == 'time'); })[0]; + + const difficult = ['hard', 'medium', 'easy']; let inputs = ['easy', '']; - if (args[0] && difficult.includes(args[0].toLowerCase())) { - inputs[0] = args[0].toLowerCase(); - } else if (args[0] == 'help') { - let temp = `Use ${bot.prefix}trivia [difficulty (easy, medium, hard)] [topic] [time]\n`; + if (args[0] && difficult.includes(args[0].value.toLowerCase())) { + inputs[0] = args[0].value.toLowerCase(); + } else if (args[0].value == 'help') { + let temp = `Use /trivia [difficulty (easy, medium, hard)] [category] [time]\n`; temp += '**__Trivia Categories__**\n'; categories.forEach((val, key) => { temp += `_${key}_\n`; - }) + }); temp += '_Please copy and paste the FULL NAME if you want to use a category'; - return message.reply(temp); + return interaction.reply(temp); } - if (args[1] && Array.from(categories.keys()).includes(args[1])) { - inputs[1] = categories.get(args[1]); + if (args[1] && Array.from(categories.keys()).includes(args[1].value)) { + inputs[1] = categories.get(args[1].value); } // Get all categories mapped to their ids @@ -142,9 +151,11 @@ module.exports = { // console.log(decode(query)); query = decode(query); - //Get the answer (may have "" in it) - const question = query.substring(query.indexOf('question":') + 10, query.indexOf('","correct_answer')); - // console.log(`Q: ${question}\n\nActual: ${query}\n---------------------------------------`); + if (bot.inDebugMode) { + //Get the answer (may have "" in it) + // const question = query.substring(query.indexOf('question":') + 10, query.indexOf('","correct_answer')); + // console.log(`Q: ${question}\n\nActual: ${query}\n---------------------------------------`); + } let q = query.split('","'); // queries[ind] = q; @@ -156,11 +167,11 @@ module.exports = { i ++; }); - const time = args[2] || (difficult.indexOf(inputs[0]) + 1) * 10000; + const time = (args[2]) ? args[2].value : (difficult.indexOf(inputs[0]) + 1) * 10000; // console.log(m, time); // changeDB(bot, message, m); - startTrivia(message, m, time, bot); + startTrivia(interaction, m, time, bot); } }); } diff --git a/commands/games/trivia_categories.json b/commands/games/trivia_categories.json index c2895d0..4e40242 100644 --- a/commands/games/trivia_categories.json +++ b/commands/games/trivia_categories.json @@ -1,28 +1,28 @@ { "trivia_categories": [ - { "id": 9, "name": "General Knowledge" }, - { "id": 10, "name": "Entertainment: Books" }, - { "id": 11, "name": "Entertainment: Film" }, - { "id": 12, "name": "Entertainment: Music" }, - { "id": 13, "name": "Entertainment: Musicals & Theatres" }, - { "id": 14, "name": "Entertainment: Television" }, - { "id": 15, "name": "Entertainment: Video Games" }, - { "id": 16, "name": "Entertainment: Board Games" }, - { "id": 17, "name": "Science & Nature" }, - { "id": 18, "name": "Science: Computers" }, - { "id": 19, "name": "Science: Mathematics" }, - { "id": 20, "name": "Mythology" }, - { "id": 21, "name": "Sports" }, - { "id": 22, "name": "Geography" }, - { "id": 23, "name": "History" }, - { "id": 24, "name": "Politics" }, - { "id": 25, "name": "Art" }, - { "id": 26, "name": "Celebrities" }, - { "id": 27, "name": "Animals" }, - { "id": 28, "name": "Vehicles" }, - { "id": 29, "name": "Entertainment: Comics" }, - { "id": 30, "name": "Science: Gadgets" }, - { "id": 31, "name": "Entertainment: Japanese Anime & Manga" }, - { "id": 32, "name": "Entertainment: Cartoon & Animations" } + { "value": 9, "name": "General Knowledge" }, + { "value": 10, "name": "Entertainment: Books" }, + { "value": 11, "name": "Entertainment: Film" }, + { "value": 12, "name": "Entertainment: Music" }, + { "value": 13, "name": "Entertainment: Musicals & Theatres" }, + { "value": 14, "name": "Entertainment: Television" }, + { "value": 15, "name": "Entertainment: Video Games" }, + { "value": 16, "name": "Entertainment: Board Games" }, + { "value": 17, "name": "Science & Nature" }, + { "value": 18, "name": "Science: Computers" }, + { "value": 19, "name": "Science: Mathematics" }, + { "value": 20, "name": "Mythology" }, + { "value": 21, "name": "Sports" }, + { "value": 22, "name": "Geography" }, + { "value": 23, "name": "History" }, + { "value": 24, "name": "Politics" }, + { "value": 25, "name": "Art" }, + { "value": 26, "name": "Celebrities" }, + { "value": 27, "name": "Animals" }, + { "value": 28, "name": "Vehicles" }, + { "value": 29, "name": "Entertainment: Comics" }, + { "value": 30, "name": "Science: Gadgets" }, + { "value": 31, "name": "Entertainment: Japanese Anime & Manga" }, + { "value": 32, "name": "Entertainment: Cartoon & Animations" } ] } \ No newline at end of file diff --git a/commands/interactionhandler.js b/commands/interactionhandler.js index b20e089..847f4a6 100644 --- a/commands/interactionhandler.js +++ b/commands/interactionhandler.js @@ -1,4 +1,3 @@ -const { MongoClient, ServerApiVersion } = require('mongodb'); const { createSubscriptionManual } = require('./premium/stripe.js'); const { pause_start_stop, playNext, showQueue } = require('./audio/audioMain.js'); const { resolveComplaint } = require('./dev only/submitcomplaint.js'); @@ -6,8 +5,11 @@ const { RSSInteractionHandler } = require('../side projects/RSSHandlers/rssFeed. const reminders = require('./premium/reminders.js'); const tuto = require('./Selmer Specific/tuto'); const mswpr = require('./games/minesweeper.js'); +const giveaway = require('./misc/giveaway.js'); +const setup = require('./admin/easySetup.js'); // const { RSSInteractionHandler } = require('./premium/rssFeed.js'); -const { Interaction } = require('discord.js') +const { Interaction, Client } = require('discord.js'); +const Discord = require('discord.js'); /** * @@ -88,10 +90,14 @@ async function handle_interaction(interaction, mongouri, turnManager, bot, STATE const page = Number(interaction.customId.split('|')[1]); tuto.postEmbd(bot, interaction, page, true); } else if (interaction.customId.indexOf("mswpr|") != -1) { - mswpr.handle(bot, interaction, interaction.channel, interaction.message, null, xp_collection); + mswpr.handle(bot, interaction, interaction.channel, false, xp_collection); } else if (interaction.customId.indexOf("sbtutorial") != -1) { interaction.deferUpdate(); tuto.execute(interaction, null, null, bot); + } else if (interaction.customId.indexOf("gameaccept") != -1) { + bot.commands.get('game').execute(bot, interaction, {name: 'accept'}, Discord, mongouri, items, xp_collection); + } else if (interaction.customId.indexOf("setupBtn") != -1) { + setup.handle(bot, interaction); } //Button else ifs here }); } @@ -157,12 +163,24 @@ async function handle_interaction(interaction, mongouri, turnManager, bot, STATE //Forms else if (interaction.isModalSubmit()) { - reminders.modalHandle(bot, interaction); + if (interaction.customId.indexOf('newEventModal') != -1) { + reminders.modalHandle(bot, interaction); + } else if (interaction.customId.indexOf('giveawayModal') != -1) { + giveaway.processForm(interaction, bot); + } } //other selection types here } +/** + * @param {Client} bot + * @param {Interaction} interaction + */ +async function handleContext(bot, interaction) { + const { targetId, commandName, user } = interaction; + console.log(interaction); +} -module.exports = { handle_interaction } +module.exports = { handle_interaction, handleContext } //values: [ 'price_1LI5pzFtuywsbrwdlY1gWMkV' ] //values: [ 'price_1LIpROFtuywsbrwdmxOb8Baj' ] \ No newline at end of file diff --git a/main.js b/main.js index 2e8ce30..4d96214 100644 --- a/main.js +++ b/main.js @@ -245,9 +245,12 @@ bot.on('interactionCreate', async interaction => { } else if (econList.includes(commandName)) { bot.commands.get('econ').execute(bot, interaction, Discord, mongouri, items, xp_collection); } else if (commandName == 'game') { - return interaction.reply("This command is still in development, use normal text\nEx: _!game tictactoe @opponent_") + if (!bot.inDebugMode) { interaction.reply("This command is still in development, use normal text\nEx: _!game tictactoe @opponent_"); } const command = interaction.options.data[0]; bot.commands.get('game').execute(bot, interaction, command, Discord, mongouri, items, xp_collection); + } else if (commandName == 'setup_embed') { + const {generateMsg} = require('./commands/admin/easySetup.js') + generateMsg(bot, interaction); } else if (bot.commands.has(commandName)) { bot.commands.get(commandName).execute(interaction, Discord, Client, bot); } else { @@ -388,10 +391,12 @@ bot.on('messageCreate', (message) => { if (!bot.inDebugMode && message.guild.id == bot.home_server) { return; } //Check if the prefix exists - if (!message.content.startsWith(prefix) || message.author.bot) { + if (message.author.bot) { return } + else if (!message.content.startsWith(prefix)) { //Use for the leveling-by-interaction system return; } else { + //Game section (too complicated to move to Slash Commands) //Note: Slash commands do not register as valid replies const args = message.content.slice(prefix.length).split(' '); diff --git a/registerCommands.js b/registerCommands.js index c351d55..622181f 100644 --- a/registerCommands.js +++ b/registerCommands.js @@ -112,7 +112,7 @@ function registerCommands(bot) { }, ] }); -return resolve(true); + //Takes much longer, so it'll be the benchmark for when the Promise resolves //#region GAMES const gameOpts = require('./commands/games/gameCommandOptions.js'); @@ -120,18 +120,26 @@ return resolve(true); name: 'game', description: 'Play one of Selmer Bot\'s games!', //NOT APPLICABLE USING SUB COMMAND GROUPS??? // type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND_GROUP, - options: gameOpts - }).then(() => { resolve(true); }).catch((err) => { reject(err); }); - //#endregion + options: gameOpts, + dm_permission: false + }).then(() => { + if (!bot.inDebugMode) { return resolve(true); } - - //#endregion + commands.create({ + name: 'setup_embed', + description: 'Create a row of buttons for easier setup', + options: [] + }); - //#region Context Menus - commands.create({ - name: "Temp", - type: 'USER' - }); + //#region Context Menus + commands.create({ + name: "Temp", + type: 'USER' + }); + //#endregion + }).catch((err) => { reject(err); }); + + //#endregion //#endregion }); }