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 asset_path = './assets/Command_Nuts/' async function nutsGive(interaction) { async function tradeWindow(buttonID1, buttonID2) { const embed = new EmbedBuilder() .setTitle('Gib Nuss!') .setDescription(`Willst du wirklich **${amount}** Nüsse an <@${to.id}> senden?`) .addFields( { name: `Your Current Balance`, value: `${yourBalance.nuts} (**-${amount}**)`, inline: true }, { name: `Your New Balance`, value: `${yourBalance.nuts - amount}`, inline: true }, { name: '\u200B', value: '\u200B' }, { name: `Their Current Balance`, value: `${theirBalance.nuts} (**+${amount}**)`, inline: true }, { name: `Their New Balance`, value: `${theirBalance.nuts + amount}`, inline: true } ) .setThumbnail('attachment://nuts_main.png') const row = new ActionRowBuilder() .addComponents( new ButtonBuilder() .setLabel('✔') .setCustomId(buttonID1) .setStyle(ButtonStyle.Success) ) .addComponents( new ButtonBuilder() .setLabel('✖') .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') const db = mClient.db(process.env.M_DB) 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` } if (!target.globalName) { addressing = `${target.username} hat` } else { addressing = `${target.globalName} hat` } const db = mClient.db(process.env.M_DB) const nutsColl = db.collection('items_nuts') const nutsData = await nutsColl.findOne({ userID: target.id }) let content if (!nutsData) { content = `${addressing} noch keine Nüsse gesammelt :(` } else { content = `${addressing} bereits **${nutsData.nuts}** Nüsse gesammelt!` } let title = 'Zähle Nüsse' const embed = new EmbedBuilder() for (let i = 0; i < 4; i++) { embed.setTitle(title) await interaction.editReply({ embeds: [embed] }) title = title + ' .' await delay(500); } embed .setTitle(content) .setThumbnail('attachment://nuts_main.png') await interaction.editReply({ embeds: [embed], files: [`${asset_path}nuts_main.png`] }) } async function nutsLeaderboard(interaction) { const row = new ActionRowBuilder() .addComponents( new ButtonBuilder() .setLabel('◄') .setStyle(ButtonStyle.Primary) .setCustomId('nuts_leaderboard_left') ) .addComponents( new ButtonBuilder() .setLabel('🧑') .setStyle(ButtonStyle.Primary) .setCustomId('nuts_leaderboard_self') ) .addComponents( new ButtonBuilder() .setLabel('►') .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('attachment://nuts_main.png') .setDescription(fields.toString()) .setColor('#5865F2') .setFooter({ text: 'Use ◄ ► to navigate' }) await interaction.editReply({ embeds: [embed], components: [row], files: [`${asset_path}nuts_main.png`] }) } async function nutsStats(interaction) { const db = mClient.db(process.env.M_DB); const nStatsColl = db.collection('stats_nuts'); var type = interaction?.options?.getString('type') || 'lookup' var target = interaction?.options?.getUser('lookup') || {} if (type == 'global') { target.id = '__global' } else if (!target?.id) { target = interaction.user } console.log(target) const statsDoc = await nStatsColl.findOne({ userID: target.id }); const stat = statsDoc?.stat || {}; const totalCount = Object.values(stat).reduce((a, b) => a + b, 0); const totalNuts = Object.entries(stat).reduce( (sum, [num, count]) => sum + Number(num) * count, 0 ); const rolledNumbers = Object.entries(stat).filter(([_, count]) => count > 0); let nutMin = { number: 0, count: 0 }; let nutMax = { number: 0, count: 0 }; if (rolledNumbers.length > 0) { nutMin = nutMax = { number: Number(rolledNumbers[0][0]), count: rolledNumbers[0][1] }; for (const [numStr, count] of rolledNumbers) { const num = Number(numStr); if (count > nutMax.count || (count === nutMax.count && num > nutMax.number)) { nutMax = { number: num, count }; } if (count < nutMin.count || (count === nutMin.count && num < nutMin.number)) { nutMin = { number: num, count }; } } } const nutAvg = totalCount ? totalNuts / totalCount : 0; const fields = Array.from({ length: 11 }, (_, i) => ({ name: `[${i}]`, value: `x${stat[i] ?? 0}`, inline: true })); const embed = new EmbedBuilder() .setTitle("Nut Statistic") .setDescription( `Total Nut Actions: **${totalCount}**\r\n` + `Total Nuts nutted: **${totalNuts}**\r\n` + `Nut Average: **${nutAvg.toFixed(3)}**\r\n` + `Most Common Nut: **${nutMax.number} (x${nutMax.count})**\r\n` + `Least Common Nut: **${nutMin.number} (x${nutMin.count})**` ) .addFields(fields) .setColor(0x51267) .setTimestamp() .setThumbnail('attachment://nuts_main.png') await interaction.editReply({ embeds: [embed], files: [`${asset_path}nuts_main.png`] }); } async function nutsCooldown(interaction) { const db = mClient.db(process.env.M_DB) const nutsColl = db.collection('items_cooldowns') const cooldown = await nutsColl.findOne({ userID: interaction.user.id }) let content = `Du kannst wieder nussen! :)` let thumbnail = 'attachment://nuts_main.png' let file = `${asset_path}nuts_main.png` let title = 'Go Nuts!' let date = (Date.now() / 1000) if (cooldown.cooldown > date) { content = ` kannst du wieder nussen! ;)` thumbnail = 'attachment://nuts_onCD.avif' file = `${asset_path}nuts_onCD.avif` title = 'To Nut or Not to Nut...' } const embed = new EmbedBuilder() .setThumbnail(thumbnail) .setTitle(title) .setDescription(content) await interaction.editReply({ embeds: [embed], files: [file] }) } async function nutsNut(interaction, quickMode) { const db = mClient.db(process.env.M_DB) const nutsColl = db.collection('items_nuts') const cdColl = db.collection('items_cooldowns') const nutsStatsColl = db.collection('stats_nuts') const cdData = await cdColl.findOne({ userID: interaction.user.id }) const embed = new EmbedBuilder() const assets = { 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', box: 'attachment://nuts_box.png', explosion: 'attachment://nuts_explosion.gif' } // Helper for singular/plural const formatNut = (amount) => `${amount} ${amount === 1 ? 'Nuss' : 'Nüsse'}` // check cooldown if (cdData?.cooldown > Date.now() / 1000) { // on cooldown embed.setTitle('To Nut or Not to Nut...') embed.setDescription(` kannst du wieder nussen! ;)`) embed.setThumbnail(assets.onCD) return interaction.editReply({ embeds: [embed], files: [`${asset_path}nuts_onCD.avif`] }) } // set 1 hour cooldown const cd = Math.floor((Date.now() + 3600000) / 1000) await cdColl.findOneAndUpdate({ userID: interaction.user.id }, { $set: { cooldown: cd, application: 'nuts' } }, { upsert: true }) // generate nut amount const amount = Math.floor(Math.random() * 10) // 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: "__global" }, { $inc: { [`stat.${amount}`]: 1 } }, { upsert: true } ) if (quickMode) { return interaction.editReply({ content: `Du hast ${formatNut(amount)} bekommen! :chestnut:` }) } // pseudo animation embed.setImage(assets.box) await interaction.editReply({ embeds: [embed], files: [`${asset_path}nuts_box.png`] }) await delay(1337) embed.setImage(assets.explosion) await interaction.editReply({ embeds: [embed], files: [`${asset_path}nuts_explosion.gif`] }) await delay(1337) let assetFile if (amount === 0) assetFile = assets.none else if (amount > 8) assetFile = assets.high else if (amount > 4) assetFile = assets.normal else assetFile = assets.low embed.setTitle(`Du hast ${formatNut(amount)} bekommen!`) embed.setThumbnail(assetFile) embed.setImage(null) return interaction.editReply({ embeds: [embed], files: [`${asset_path}${assetFile.split('://')[1]}`] }) } module.exports = { data: new SlashCommandBuilder() .setName('nuts') .setDescription('rund um die nuss') .addSubcommand(s => s .setName('give') .setDescription('gib nuss!!') .addUserOption(o => o.setName('target').setDescription('wer bekommt da nuts?').setRequired(true)) .addNumberOption(o => o.setName('amount').setDescription('wie viele?').setRequired(true))) .addSubcommand(s => s .setName('check') .setDescription('check out deez nuts') .addUserOption(o => o.setName('target').setDescription('check out those nuts!'))) .addSubcommand(s => s .setName('leaderboard') .setDescription('wer hat die dicksten Nüsse?')) .addSubcommand(s => s .setName('stats') .setDescription('wie viele Nüsse wurden genusst, Genosse?') .addStringOption(o => o.setName('type') .setDescription('set type to global or user') .addChoices( { name: 'global', value: 'global' }, { name: 'user', value: 'user' } ),) .addUserOption(o => o.setName('lookup') .setDescription('look up specific user nut statistic') ) ) .addSubcommand(s => s .setName('cooldown') .setDescription('wie lange bis ich nussen kann?')) .addSubcommand(s => s .setName('nut') .setDescription('willst du nuss?')) .addSubcommand(s => s.setName('quick') .setDescription('A quick nut, mlord?') ), async execute(interaction) { switch (interaction.options._subcommand) { case 'give': nutsGive(interaction) break; case 'check': await interaction.deferReply() nutsCheck(interaction) break; case 'leaderboard': await interaction.deferReply() nutsLeaderboard(interaction) break; case 'stats': await interaction.deferReply() nutsStats(interaction) break; case 'cooldown': await interaction.deferReply() nutsCooldown(interaction) break; case 'nut': await interaction.deferReply() nutsNut(interaction, false) break; case 'quick': await interaction.deferReply() nutsNut(interaction, true) break; default: break; } } }