diff --git a/assets/Command_Nuts/animation_box.png b/assets/Command_Nuts/nuts_box.png similarity index 100% rename from assets/Command_Nuts/animation_box.png rename to assets/Command_Nuts/nuts_box.png diff --git a/assets/Command_Nuts/nuts_explosion.gif b/assets/Command_Nuts/nuts_explosion.gif new file mode 100644 index 0000000..015c4f3 Binary files /dev/null and b/assets/Command_Nuts/nuts_explosion.gif differ diff --git a/assets/Command_Nuts/nuts_high.jpg b/assets/Command_Nuts/nuts_high.jpg new file mode 100644 index 0000000..a7efb2d Binary files /dev/null and b/assets/Command_Nuts/nuts_high.jpg differ diff --git a/assets/Command_Nuts/nuts_low.jpg b/assets/Command_Nuts/nuts_low.jpg new file mode 100644 index 0000000..dc5bfb0 Binary files /dev/null and b/assets/Command_Nuts/nuts_low.jpg differ diff --git a/assets/Command_Nuts/nuts_main.png b/assets/Command_Nuts/nuts_main.png new file mode 100644 index 0000000..0426ce8 Binary files /dev/null and b/assets/Command_Nuts/nuts_main.png differ diff --git a/assets/Command_Nuts/nuts_none.avif b/assets/Command_Nuts/nuts_none.avif new file mode 100644 index 0000000..7a0af74 Binary files /dev/null and b/assets/Command_Nuts/nuts_none.avif differ diff --git a/assets/Command_Nuts/nuts_normal.jpg b/assets/Command_Nuts/nuts_normal.jpg new file mode 100644 index 0000000..c75061c Binary files /dev/null and b/assets/Command_Nuts/nuts_normal.jpg differ diff --git a/assets/Command_Nuts/nuts_onCD.avif b/assets/Command_Nuts/nuts_onCD.avif new file mode 100644 index 0000000..3e50392 Binary files /dev/null and b/assets/Command_Nuts/nuts_onCD.avif differ diff --git a/commands/slash/applications/nuts.js b/commands/slash/applications/nuts.js index c36344e..a09ffd4 100644 --- a/commands/slash/applications/nuts.js +++ b/commands/slash/applications/nuts.js @@ -1,7 +1,11 @@ -const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags } = require('discord.js') +const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags, AttachmentBuilder } = require('discord.js') const { mClient } = require('../../../index') require('dotenv').config() + function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } + +const ASSETS = './assets/Command_Nuts/' + async function nutsGive(interaction) { async function tradeWindow(buttonID1, buttonID2) { const embed = new EmbedBuilder() @@ -14,7 +18,8 @@ async function nutsGive(interaction) { { name: `Their Current Balance`, value: `${theirBalance.nuts} (**+${amount}**)`, inline: true }, { name: `Their New Balance`, value: `${theirBalance.nuts + amount}`, inline: true } ) - .setThumbnail(to.displayAvatarURL()) + .setThumbnail('attachment://nuts_main.png') + const row = new ActionRowBuilder() .addComponents( new ButtonBuilder() @@ -28,12 +33,14 @@ async function nutsGive(interaction) { .setCustomId(buttonID2) .setStyle(ButtonStyle.Danger) ) + await interaction.reply({ embeds: [embed], components: [row], flags: MessageFlags.Ephemeral }) } + const from = interaction.user const to = await interaction.options.getUser('target') var amount = await interaction.options.getNumber('amount') @@ -42,21 +49,26 @@ async function nutsGive(interaction) { const nutsColl = db.collection('items_nuts') const yourBalance = await nutsColl.findOne({ userID: from.id }) const theirBalance = await nutsColl.findOne({ userID: to.id }) + if (amount <= 0) { amount = yourBalance.nuts return tradeWindow('nuts_give_fake', 'abort') } + if (yourBalance.nuts < amount) { return await interaction.reply({ content: 'Du kannst nicht mehr geben als du hast!', flags: MessageFlags.Ephemeral }) } + return tradeWindow('nuts_give_confirm', 'abort') } + async function nutsCheck(interaction) { let target = interaction.options.getUser('target') let addressing + if (!target) { target = interaction.user addressing = `Du hast` @@ -81,6 +93,7 @@ async function nutsCheck(interaction) { let title = 'Zähle Nüsse' const embed = new EmbedBuilder() + for (let i = 0; i < 4; i++) { embed.setTitle(title) await interaction.editReply({ @@ -89,14 +102,17 @@ async function nutsCheck(interaction) { title = title + ' .' await delay(500); } + embed .setTitle(content) - .setThumbnail('https://cdn-icons-png.flaticon.com/512/628/628206.png') + .setThumbnail('attachment://nuts_main.png') await interaction.editReply({ - embeds: [embed] + embeds: [embed], + files: [`${ASSETS}nuts_main.png`] }) } + async function nutsLeaderboard(interaction) { const row = new ActionRowBuilder() .addComponents( @@ -117,35 +133,42 @@ async function nutsLeaderboard(interaction) { .setStyle(ButtonStyle.Primary) .setCustomId('nuts_leaderboard_right') ) + const db = mClient.db(process.env.M_DB) const nutsColl = db.collection('items_nuts') let skip = 0 + const nutsData = await nutsColl.find({ nuts: { $gt: 0 } }).sort({ nuts: -1 }).skip(skip).limit(5).toArray() + let fields let placements = skip + 1 + nutsData.forEach((data) => { fields = (fields ? fields : '') + (`${placements}. <@${data.userID}> : ${data.nuts} Nuts\r\n`) + placements++ }) + const embed = new EmbedBuilder() .setTitle('Nuts Leaderboard') - .setThumbnail(interaction.guild.iconURL({ dynamic: true })) + .setThumbnail('attachment://nuts_main.png') .setDescription(fields.toString()) - .setColor('#5865F2') // Discord's blurple color - .setFooter({ text: 'Use ◄ ► to navigate' }); + .setColor('#5865F2') + .setFooter({ text: 'Use ◄ ► to navigate' }) + await interaction.editReply({ embeds: [embed], - components: [row] + components: [row], + files: [`${ASSETS}nuts_main.png`] }) } + async function nutsStats(interaction) { const db = mClient.db(process.env.M_DB); const nStatsColl = db.collection('stats_nuts'); - // fetch user stats const statsDoc = await nStatsColl.findOne({ userID: interaction.user.id }); - const stat = statsDoc?.stat || {}; // fallback to empty object + const stat = statsDoc?.stat || {}; - // compute totals const totalCount = Object.values(stat).reduce((a, b) => a + b, 0); const totalNuts = Object.entries(stat).reduce( (sum, [num, count]) => sum + Number(num) * count, @@ -158,18 +181,15 @@ async function nutsStats(interaction) { let nutMax = { number: 0, count: 0 }; if (rolledNumbers.length > 0) { - // initialize to first rolled number nutMin = nutMax = { number: Number(rolledNumbers[0][0]), count: rolledNumbers[0][1] }; for (const [numStr, count] of rolledNumbers) { const num = Number(numStr); - // best nut: prefer higher number if counts tie if (count > nutMax.count || (count === nutMax.count && num > nutMax.number)) { nutMax = { number: num, count }; } - // worst nut: prefer lower number if counts tie if (count < nutMin.count || (count === nutMin.count && num < nutMin.number)) { nutMin = { number: num, count }; } @@ -178,7 +198,6 @@ async function nutsStats(interaction) { const nutAvg = totalCount ? totalNuts / totalCount : 0; - // dynamically create fields for numbers 0-9 const fields = Array.from({ length: 10 }, (_, i) => ({ name: `[${i}]`, value: `x${stat[i] ?? 0}`, @@ -197,9 +216,12 @@ async function nutsStats(interaction) { .addFields(fields) .setColor(0x51267) .setTimestamp() - .setThumbnail(interaction.guild.iconURL()); + .setThumbnail('attachment://nuts_main.png') - await interaction.editReply({ embeds: [embed] }); + await interaction.editReply({ + embeds: [embed], + files: [`${ASSETS}nuts_main.png`] + }); } async function nutsCooldown(interaction) { @@ -208,13 +230,15 @@ async function nutsCooldown(interaction) { const cooldown = await nutsColl.findOne({ userID: interaction.user.id }) let content = `Du kannst wieder nussen! :)` - let thumbnail = 'https://cdn-icons-png.flaticon.com/512/7451/7451659.png' + let thumbnail = 'attachment://nuts_main.png' + let file = `${ASSETS}nuts_main.png` let title = 'Go Nuts!' let date = (Date.now() / 1000) if (cooldown.cooldown > date) { content = ` kannst du wieder nussen! ;)` - thumbnail = 'https://img.freepik.com/free-vector/no-nut-november-cartoon-illustration-premium-cartoon-vector-icon-illustration-food-object-isolated_138676-6549.jpg' + thumbnail = 'attachment://nuts_onCD.avif' + file = `${ASSETS}nuts_onCD.avif` title = 'To Nut or Not to Nut...' } @@ -224,9 +248,11 @@ async function nutsCooldown(interaction) { .setDescription(content) await interaction.editReply({ - embeds: [embed] + embeds: [embed], + files: [file] }) } + async function nutsNut(interaction, quickMode) { const db = mClient.db(process.env.M_DB) const nutsColl = db.collection('items_nuts') @@ -235,97 +261,72 @@ async function nutsNut(interaction, quickMode) { const cdData = await cdColl.findOne({ userID: interaction.user.id }) const embed = new EmbedBuilder() - .setImage('https://e7.pngegg.com/pngimages/1011/894/png-clipart-gift-christmas-box-mystery-gift-box-holidays-box-thumbnail.png') - let content const images = { - "high": "https://as2.ftcdn.net/v2/jpg/02/24/65/39/1000_F_224653943_r3xltiwJsK6am0mGZE5DTWk1yocUwHLd.jpg", - "normal": 'https://c8.alamy.com/comp/PPPBXK/surprised-pecan-nuts-pile-on-plate-cartoon-PPPBXK.jpg', - "low": 'https://as2.ftcdn.net/v2/jpg/02/24/65/37/1000_F_224653769_ceJk0tq9UT1hSu5FIVUi7BeaN4ucSZGv.jpg', - "none": 'https://cdn4.vectorstock.com/i/1000x1000/87/08/afraid-pecan-nuts-pile-on-plate-cartoon-vector-22028708.jpg', - "onCD": 'https://img.freepik.com/free-vector/no-nut-november-cartoon-illustration-premium-cartoon-vector-icon-illustration-food-object-isolated_138676-6549.jpg' + high: 'attachment://nuts_high.jpg', + normal: 'attachment://nuts_normal.jpg', + low: 'attachment://nuts_low.jpg', + none: 'attachment://nuts_none.avif', + onCD: 'attachment://nuts_onCD.avif' } - let image - if (!cdData || cdData.cooldown < (Date.now() / 1000)) { - let cd = Math.floor((Date.now() + 3600000) / 1000) - await cdColl.findOneAndUpdate({ - userID: interaction.user.id - }, { - $set: { cooldown: cd } - }, { - upsert: true - }) + // Helper for singular/plural + const formatNut = (amount) => `${amount} ${amount === 1 ? 'Nuss' : 'Nüsse'}` + + // check cooldown + if (!cdData || cdData.cooldown < Date.now() / 1000) { + // set 1 hour cooldown + const cd = Math.floor((Date.now() + 3600000) / 1000) + await cdColl.findOneAndUpdate( + { userID: interaction.user.id }, + { $set: { cooldown: cd } }, + { upsert: true } + ) + + // generate nut amount const amount = Math.floor(Math.random() * 10) - await nutsColl.findOneAndUpdate({ - userID: interaction.user.id - }, { - $inc: { nuts: amount } - }, { - upsert: true - }) + // update nuts and stats + await nutsColl.findOneAndUpdate( + { userID: interaction.user.id }, + { $inc: { nuts: amount } }, + { upsert: true } + ) - await nutsStatsColl.findOneAndUpdate({ - userID: interaction.user.id - }, { - $inc: { [`stat.${amount}`]: 1 } - }, { - upsert: true - } - ); + await nutsStatsColl.findOneAndUpdate( + { userID: interaction.user.id }, + { $inc: { [`stat.${amount}`]: 1 } }, + { upsert: true } + ) - if (amount) { - content = `Du hast **${amount}** Nüsse bekommen!` - if (amount > 8) { - image = images["high"] - } else if (amount > 4) { - image = images["normal"] - } else { - image = images["low"] - } - } else { - content = `Du hast leider keine Nüsse bekommen :(` - image = images["none"] - } + let imageFile + if (amount === 0) imageFile = images.none + else if (amount > 8) imageFile = images.high + else if (amount > 4) imageFile = images.normal + else imageFile = images.low + + embed.setTitle(`Du hast ${formatNut(amount)} bekommen!`) + embed.setThumbnail(imageFile) if (quickMode) { - return interaction.editReply({ - content: `Du hast ${amount} Nüsse bekommen! :chestnut:`, - }) + return interaction.editReply({ content: `Du hast ${formatNut(amount)} bekommen! :chestnut:` }) } + return interaction.editReply({ + embeds: [embed], + files: [`${ASSETS}${imageFile.split('://')[1]}`] + }) } else { - content = `Du kannst erst wieder nussen :(` - image = images["onCD"] - await delay(1000) - embed.setDescription(content) - embed.setThumbnail(image) - embed.setImage(null) - return await interaction.editReply({ - embeds: [embed] + // on cooldown + embed.setTitle('To Nut or Not to Nut...') + embed.setDescription(` kannst du wieder nussen! ;)`) + embed.setThumbnail(images.onCD) + + return interaction.editReply({ + embeds: [embed], + files: [`${ASSETS}nuts_onCD.avif`] }) } - - - - await interaction.editReply({ - embeds: [embed] - }) - await delay(1000) - embed.setImage('https://i.pinimg.com/originals/9d/58/37/9d5837c6f0cb8b18be6ddd1e2742472a.gif') - await interaction.editReply({ - embeds: [embed] - }) - - await delay(1000) - embed.setDescription(content) - embed.setImage(image) - await interaction.editReply({ - embeds: [embed] - }) - - } module.exports = { data: new SlashCommandBuilder()