diff --git a/package.json b/package.json index 866c32280..d6566550c 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "common-tags": "^1.8.2", "connect-mongo": "^5.0.0", "country-emoji-languages": "^1.0.0", + "discord-gamecord": "^4.1.0", "discord-giveaways": "^6.0.1", "discord-together": "^1.3.31", "discord.js": "^14.11.0", diff --git a/src/commands/fun/hangman.js b/src/commands/fun/hangman.js new file mode 100644 index 000000000..104b3502e --- /dev/null +++ b/src/commands/fun/hangman.js @@ -0,0 +1,98 @@ +const { ApplicationCommandOptionType, EmbedBuilder } = require("discord.js"); +const { Hangman } = require("discord-gamecord"); +const choices = ["nature", "sport", "color", "camp", "fruit", "discord", "winter", "pokemon"]; + +module.exports = { + name: "hangman", + description: "Play hangman in discord", + cooldown: 15, + category: "FUN", + botPermissions: ["SendMessages", "EmbedLinks", "AddReactions", "ReadMessageHistory", "ManageMessages"], + command: { + enabled: true, + }, + slashCommand: { + enabled: true, + ephermal: true, + options: [ + { + name: "theme", + description: "Select a theme", + type: ApplicationCommandOptionType.String, + required: true, + choices: choices.map((choice) => { + return { + name: choice, + value: choice, + }; + }), + }, + ], + }, + + async messageRun(message, args) { + const choice = args[0]; + + if (!choice) { + const embed = new EmbedBuilder(); + embed.setTitle("Hangman"); + embed.setColor("#5865F2"); + embed.setDescription( + `Please select a theme from the list below:\n\n${choices.map((choice) => `\`${choice}\``).join(", ")}` + ); + return message.reply({ embeds: [embed] }); + } + + if (!choices.includes(choice)) { + const embed = new EmbedBuilder(); + embed.setTitle("Hangman"); + embed.setColor("#5865F2"); + embed.setDescription( + `Please select a theme from the list below:\n\n${choices.map((choice) => `\`${choice}\``).join(", ")}` + ); + return message.reply({ embeds: [embed] }); + } + const Game = new Hangman({ + message: message, + isSlashGame: false, + embed: { + title: "Hangman", + color: "#5865F2", + }, + hangman: { hat: "🎩", head: "😟", shirt: "👕", pants: "🩳", boots: "👞👞" }, + timeoutTime: 60000, + theme: choice, + winMessage: "You won! The word was **{word}**.", + loseMessage: "You lost! The word was **{word}**.", + playerOnlyMessage: "Only {player} can use these buttons.", + }); + + Game.startGame(); + Game.on("gameOver", (result) => { + console.log(result); // => { result... } + }); + }, + + async interactionRun(interaction) { + const choice = interaction.options.getString("theme"); + const Game = new Hangman({ + message: interaction, + isSlashGame: true, + embed: { + title: "Hangman", + color: "#5865F2", + }, + hangman: { hat: "🎩", head: "😟", shirt: "👕", pants: "🩳", boots: "👞👞" }, + timeoutTime: 60000, + theme: choice, + winMessage: "You won! The word was **{word}**.", + loseMessage: "You lost! The word was **{word}**.", + playerOnlyMessage: "Only {player} can use these buttons.", + }); + + Game.startGame(); + Game.on("gameOver", (result) => { + console.log(result); // => { result... } + }); + }, +}; diff --git a/src/commands/fun/love.js b/src/commands/fun/love.js new file mode 100644 index 000000000..0b96d4f77 --- /dev/null +++ b/src/commands/fun/love.js @@ -0,0 +1,97 @@ +const { EmbedBuilder, ApplicationCommandOptionType } = require("discord.js"); + +/** + * @type {import("@structures/Command")} + */ + +module.exports = { + name: "love", + description: "Get the love percentage of two users.", + cooldown: 10, + category: "FUN", + botPermissions: ["EmbedLinks"], + command: { + enabled: true, + aliases: [], + usage: "love ", + minArgsCount: 1, + }, + slashCommand: { + enabled: true, + options: [ + { + name: "user1", + description: "The first user", + type: ApplicationCommandOptionType.User, + required: true, + }, + + { + name: "user2", + description: "The second user", + type: ApplicationCommandOptionType.User, + required: true, + }, + ], + }, + + async messageRun(message, args) { + const user1 = args[0]; + const user2 = args[1]; + const response = await getUserLove(user1, user2, message.author); + await message.safeReply(response); + }, + + async interactionRun(interaction) { + const user1 = interaction.options.getUser("user1"); + const user2 = interaction.options.getUser("user2"); + const response = await getUserLove(user1, user2, interaction.user); + await interaction.followUp(response); + }, +}; + +async function getUserLove(user1, user2, mauthor) { + // Calculate random love percentage + const result = Math.ceil(Math.random() * 100); + + // Determine love status based on percentage + let loveStatus; + if (result <= 20) { + loveStatus = ":broken_heart: Not a good match :broken_heart:"; + } else if (result <= 50) { + loveStatus = ":yellow_heart: Could be better :yellow_heart:"; + } else if (result <= 80) { + loveStatus = ":heartpulse: Pretty good match :heartpulse:"; + } else { + loveStatus = ":heart_eyes: Perfect match :heart_eyes:"; + } + + // Determine love image based on percentage + const loveImage = result >= 51 ? "https://media1.giphy.com/media/TmngSmlDjzJfO/giphy.gif?cid=ecf05e47brm0fzk1kan0ni753jmvvik6h27sp13fkn8a9kih&rid=giphy.gif&ct=g" : "https://media4.giphy.com/media/SIPIe590rx6iA/giphy.gif?cid=ecf05e476u1ciogyg7rjw1aaoh29s912axi5r7b5r46fczx6&rid=giphy.gif&ct=g"; + + // Create embed + const embed = new EmbedBuilder() + .setTitle("Love Meter") + .setDescription("See how much you match with someone! :heart:") + .addFields({ + name: "Result", + value: `**${user1}** and **${user2}** match **${result}%**!`, + inline: false, + }) + .addFields({ + name: "Love Status", + value: loveStatus, + inline: false, + }) + .setColor("LuminousVividPink") + .setFooter({ + text: `Requested by ${mauthor.tag}`, + }) + .setImage(loveImage) + .setTimestamp() + .setThumbnail("https://www.wownow.net.in/assets/images/love.gif") + .setFooter({ text: `Requested by ${mauthor.tag}` }); + + return { embeds: [embed] }; +} + diff --git a/src/commands/fun/tictactoe.js b/src/commands/fun/tictactoe.js new file mode 100644 index 000000000..f93cc3c15 --- /dev/null +++ b/src/commands/fun/tictactoe.js @@ -0,0 +1,80 @@ +const { TicTacToe } = require("discord-gamecord"); +const { ApplicationCommandOptionType, EmbedBuilder} = require("discord.js"); + +/** + * @type {import("@structures/Command")} + */ + +module.exports = { + name: "tictactoe", + description: "Play Tic Tac Toe with your friends", + cooldown: 15, + category: "FUN", + botPermissions: ["SendMessages", "EmbedLinks", "AddReactions", "ReadMessageHistory", "ManageMessages"], + command: { + enabled: false, + }, + slashCommand: { + enabled: true, + ephermal: true, + options: [ + { + name: "user", + description: "Select a user to play", + type: ApplicationCommandOptionType.User, + required: true, + }, + ], + }, + + async interactionRun(interaction) { + const Game = new TicTacToe({ + message: interaction, + isSlashGame: true, + opponent: interaction.options.getUser("user"), + embed: { + title: "Tic Tac Toe", + color: "#5865F2", + statusTitle: "Status", + overTitle: "Game Over", + }, + emojis: { + xButton: "❌", + oButton: "🔵", + blankButton: "➖", + }, + mentionUser: true, + timeoutTime: 60000, + xButtonStyle: "DANGER", + oButtonStyle: "PRIMARY", + turnMessage: "{emoji} | Its turn of player **{player}**.", + winMessage: "{emoji} | **{player}** won the TicTacToe Game.", + tieMessage: "The Game tied! No one won the Game!", + timeoutMessage: "The Game went unfinished! No one won the Game!", + playerOnlyMessage: "Only {player} and {opponent} can use these buttons.", + }); + + Game.startGame(); + Game.on("gameOver", (result) => { + console.log(result); // => { result... } + const winners = result.winner; + const winner = `<@${winners}>`; + if (result.result === "tie") { + const embed = new EmbedBuilder() + .setTitle("Tic Tac Toe") + .setDescription("The Game tied! No one won the Game!") + .setColor("Red") + .setTimestamp(); + interaction.followUp({ embeds: [embed] }); + } else if (result.result === "win") { + const embed = new EmbedBuilder() + .setTitle("Tic Tac Toe") + .setDescription(`${winner} won the TicTacToe Game.`) + .setColor("Green") + .setTimestamp(); + + interaction.followUp({ embeds: [embed] }); + } + }); + }, +}; diff --git a/src/commands/owner/reload.js b/src/commands/owner/reload.js new file mode 100644 index 000000000..45d3bead5 --- /dev/null +++ b/src/commands/owner/reload.js @@ -0,0 +1,64 @@ +const { EmbedBuilder } = require("discord.js"); +const { BotClient } = require("@src/structures"); +/** + * @type {import("@structures/Command")} + */ + +module.exports = { + name: "reload", + description: "Reloads a command that's been modified", + category: "OWNER", + botPermissions: [], + command: { + enabled: true, + aliases: [], + usage: "[reload]", + }, + slashCommand: { + enabled: false, + }, + async messageRun(message, args) { + const client = new BotClient(); + + try { + switch (args[0]?.toLowerCase()) { + case "commands": + { + client.loadCommands("src/commands"); + } + break; + case "events": + { + client.loadEvents("src/events"); + } + break; + case "contexts": + { + client.loadContexts("src/contexts"); + } + break; + case "all": + { + client.loadCommands("src/commands"); + client.loadContexts("src/contexts"); + client.loadEvents("src/events"); + } + break; + default: + const embed = new EmbedBuilder(); + embed.setTitle("error"); + embed.setDescription(`command not selected`); + embed.setColor("Red"); + message.reply({ embeds: [embed] }); + return; + } + } catch (e) { + console.log(e); + } + const embed = new EmbedBuilder(); + embed.setTitle("Reloaded"); + embed.setDescription(`Reloaded ${args[0]}`); + embed.setColor("Green"); + message.reply({ embeds: [embed] }); + }, +}; diff --git a/src/commands/utility/epicgames.js b/src/commands/utility/epicgames.js new file mode 100644 index 000000000..0265c9fbd --- /dev/null +++ b/src/commands/utility/epicgames.js @@ -0,0 +1,63 @@ +const { EmbedBuilder} = require("discord.js"); +const { getJson } = require("@helpers/HttpUtils"); + +/** + * @type {import("@structures/Command")} + */ +module.exports = { + name: "epicgames", + description: "search for free games in epic games store last week", + cooldown: 10, + category: "UTILITY", + botPermissions: ["EmbedLinks"], + command: { + enabled: true, + aliases: ["egs"], + usage: "epicgames", + minArgsCount: 1, + }, + slashCommand: { + enabled: true, + options: [], + }, + + async messageRun(message, args) { + const response = await searchGame(message.author); + await message.safeReply(response); + }, + + async interactionRun(interaction) { + const response = await searchGame(interaction.user); + await interaction.followUp(response); + }, +}; + +async function searchGame(author) { + //busca los juegos gratis en epic games store + const response = await getJson("https://store-site-backend-static.ak.epicgames.com/freeGamesPromotions?locale=en-US&country=US&allowCountries=US"); + + const gamess = response.data.data.Catalog.searchStore.elements; + const matchingGames = gamess.filter((game) => game.title.toLowerCase()); + + if (matchingGames.length === 0) { + const embed = new EmbedBuilder(); + embed.setColor("Random"); + embed.setTitle("Games not found"); + embed.setTimestamp(); + return { embeds: [embed] }; + } + + + + const embed = new EmbedBuilder(); + embed.setColor("Random"); + embed.setTitle("Free Games in Epic Games Store Last Week"); + embed.addFields(matchingGames.map((game) => ({ name: game.title, value: game.description, inline: false }))); + + embed.setThumbnail(matchingGames[0].keyImages[0].url); + + + embed.setTimestamp(); + return { embeds: [embed] }; + +} diff --git a/src/commands/utility/npm.js b/src/commands/utility/npm.js new file mode 100644 index 000000000..0f32aa799 --- /dev/null +++ b/src/commands/utility/npm.js @@ -0,0 +1,122 @@ +const { EmbedBuilder, ApplicationCommandOptionType } = require("discord.js"); +const { MESSAGES } = require("@root/config.js"); +const { getJson } = require("@helpers/HttpUtils"); +const { stripIndent } = require("common-tags"); + +/** + * @type {import("@structures/Command")} + */ +module.exports = { + name: "npm", + description: "Shows the information of a npm package.", + cooldown: 10, + category: "UTILITY", + botPermissions: ["EmbedLinks"], + command: { + enabled: true, + aliases: ["npmpackage"], + usage: "npm ", + minArgsCount: 1, + }, + slashCommand: { + enabled: true, + options: [ + { + name: "package", + description: "The name of the package", + type: ApplicationCommandOptionType.String, + required: true, + }, + ], + }, + + async messageRun(message, args) { + const username = args.join(" "); + const response = await getnpmpackage(username, message.author); + await message.safeReply(response); + }, + + async interactionRun(interaction) { + const username = interaction.options.getString("package"); + const response = await getnpmpackage(username, interaction.user); + await interaction.followUp(response); + }, +}; + +async function getnpmpackage(target, mauthor) { + const response = await getJson(`https://registry.npmjs.org/${target}`); + + if (response.status === 404) return "```css\n[!] package not found```"; + if (!response.success) return MESSAGES.API_ERROR; + + const json = response.data; + const { name, description, author, license, repository, homepage, keywords, dependencies, devDependencies, time } = + json; + + const version = json.versions[json["dist-tags"].latest]; + + let deps = version.dependencies ? Object.keys(version.dependencies) : null; + + if(deps && deps.length > 10) { + const len = deps.length - 10; + deps = deps.slice(0, 10); + deps.push(`...${len} more.`); + } + + const embed = new EmbedBuilder() + + .setAuthor({ + name: `${name} | NPM`, + url: `https://www.npmjs.com/package/${target}`, + avatarUrl: "https://www.npmjs.com/static/images/touch-icons/favicon-32x32.png", + }) + .setDescription(description ? description : "No description provided") + .addFields( + { + name: "Links", + value: stripIndent` + [NPM](https://www.npmjs.com/package/${name}) + [GitHub](${repository.url})`, + inline: true, + }, + { + name: "Dist-tags", + value: json["dist-tags"].latest, + inline: true, + }, + { + name: "Dependencies", + value: `${deps && deps.length ? deps.join(", ") : "None"}`, + inline: true, + }, + { + name: "Modified:", + value: new Date(json.time.modified).toLocaleString(), + inline: true, + }, + { + name: "Created:", + value: new Date(json.time.created).toLocaleString(), + inline: true, + }, + { + name: "Author", + value: author ? author.name : "Unknown", + inline: true, + }, + { + name: "License", + value: license ? license : "No license provided", + inline: true, + } + ) + + .setThumbnail( + "https://media.discordapp.net/attachments/987792443833462804/1052332405643550790/npm_1.png" + ) + .setColor("Red") + .setTimestamp() + .setFooter({ text: `Requested by ${mauthor.tag}`}); + + return { embeds: [embed] }; +} diff --git a/src/commands/utility/qrcode.js b/src/commands/utility/qrcode.js new file mode 100644 index 000000000..8757a8806 --- /dev/null +++ b/src/commands/utility/qrcode.js @@ -0,0 +1,58 @@ +const { ApplicationCommandOptionType, EmbedBuilder } = require("discord.js"); + +/** + * @type {import("@structures/Command")} + */ + +module.exports = { + name: "qrcode", + description: "Generate a QR code with the url that is provided", + category: "ADMIN", + botPermissions: ["ManageGuild"], + command: { + enabled: false, + }, + slashCommand: { + enabled: true, + ephemeral: true, + options: [ + { + name: "url", + description: "URL to generate QR code for", + type: ApplicationCommandOptionType.String, + required: true, + }, + ], + }, + async interactionRun(interaction) { + const {user, guild } = interaction; + const text = interaction.options.getString("url"); + const baseURL = "http://api.qrserver.com/v1"; + const regex = /[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/; + + if (!text.match(regex)) { + const embed = new EmbedBuilder() + .setColor("RED") + .setTitle(`Invalid URL`) + .setDescription(`Please provide a valid URL.`) + .setFooter({ text: guild.name }) + .setTimestamp(); + + return; + } + + const encodedURL = `${baseURL}/create-qr-code/?size=150x150&data=` + encodeURIComponent(text); + + const embedqr = new EmbedBuilder() + .setAuthor({ name: user.tag, iconURL: user.displayAvatarURL({ dynamic: true}) }) + .setColor("Green") + .setTitle(`QR Code`) + .setDescription(`Here is your QR code for the URL: [click here](${text})`) + .setImage(encodedURL) + .setThumbnail("https://img.freepik.com/vector-premium/personaje-dibujos-animados-codigo-qr-buscando-lupa-diseno-lindo_152558-13614.jpg?w=826") + .setFooter({ text: guild.name }) + .setTimestamp(); + + interaction.channel.send({ embeds: [embedqr] }); + }, +}; diff --git a/src/database/mongoose.js b/src/database/mongoose.js index 9b9160db0..28463c4f8 100644 --- a/src/database/mongoose.js +++ b/src/database/mongoose.js @@ -29,4 +29,4 @@ module.exports = { User: require("./schemas/User"), Suggestions: require("./schemas/Suggestions").model, }, -}; +}; \ No newline at end of file