From c76680293e0d5cb8efc7f1ceb0f37062e33be842 Mon Sep 17 00:00:00 2001 From: DeSqBlocki Date: Fri, 14 Aug 2026 22:54:03 +0200 Subject: [PATCH] rai if you are reading this im getting you a monster --- clearCommands.js | 40 + commands/applications/cookies.js | 844 ++++++++++++++++++++ commands/cookies.js | 312 -------- commands/cookies.js.10082025.old | 448 ----------- commands/cookies.js.1008202502.old | 262 ------- commands/cookies.js.1008202503.old | 307 -------- commands/cookies.js.save | 383 --------- commands/dontclickthis.js | 31 - commands/random.js | 209 ----- commands/sus.js | 10 - commands/template.txt | 29 - commands/waa.js | 26 - duties/araids.json | 15 - duties/dungeons.json | 88 --- duties/extreme.json | 37 - duties/guildhests.json | 16 - duties/nraids.json | 59 -- duties/pvp.json | 13 - duties/roulettes.json | 13 - duties/savage.json | 50 -- duties/trials.json | 48 -- duties/ultimates.json | 6 - events/ClientReady.js | 20 + events/InteractionCreate.js | 98 +++ handlers/buttons.js | 20 + handlers/commands.js | 41 + handlers/events.js | 18 + handlers/selectMenus.js | 20 + index.js | 104 +-- package-lock.json | 1178 ++++++++-------------------- package.json | 14 +- schemas/classSchema.js | 18 - schemas/cookieSchema.js | 19 - schemas/cooldownSchema.js | 20 - 34 files changed, 1478 insertions(+), 3338 deletions(-) create mode 100644 clearCommands.js create mode 100644 commands/applications/cookies.js delete mode 100644 commands/cookies.js delete mode 100644 commands/cookies.js.10082025.old delete mode 100644 commands/cookies.js.1008202502.old delete mode 100644 commands/cookies.js.1008202503.old delete mode 100644 commands/cookies.js.save delete mode 100644 commands/dontclickthis.js delete mode 100644 commands/random.js delete mode 100644 commands/sus.js delete mode 100644 commands/template.txt delete mode 100644 commands/waa.js delete mode 100644 duties/araids.json delete mode 100644 duties/dungeons.json delete mode 100644 duties/extreme.json delete mode 100644 duties/guildhests.json delete mode 100644 duties/nraids.json delete mode 100644 duties/pvp.json delete mode 100644 duties/roulettes.json delete mode 100644 duties/savage.json delete mode 100644 duties/trials.json delete mode 100644 duties/ultimates.json create mode 100644 events/ClientReady.js create mode 100644 events/InteractionCreate.js create mode 100644 handlers/buttons.js create mode 100644 handlers/commands.js create mode 100644 handlers/events.js create mode 100644 handlers/selectMenus.js delete mode 100644 schemas/classSchema.js delete mode 100644 schemas/cookieSchema.js delete mode 100644 schemas/cooldownSchema.js diff --git a/clearCommands.js b/clearCommands.js new file mode 100644 index 0000000..98b3c17 --- /dev/null +++ b/clearCommands.js @@ -0,0 +1,40 @@ +require("dotenv").config(); + +const { REST, Routes } = require("discord.js"); + +const rest = new REST({ version: "10" }) + .setToken(process.env.D_TOKEN); + +async function clearCommands() { + try { + if (!process.env.D_TOKEN) + throw new Error("Missing D_TOKEN environment variable."); + + if (!process.env.D_ID) + throw new Error("Missing D_ID environment variable."); + + if (!process.env.D_GID) + throw new Error("Missing G_GID environment variable."); + + console.log("Clearing guild application commands..."); + + await rest.put( + Routes.applicationGuildCommands( + process.env.D_ID, + process.env.D_GID + ), + { + body: [] + } + ); + + console.log("Successfully cleared all guild application commands."); + } catch (error) { + console.error("Failed to clear application commands:"); + console.error(error); + + process.exitCode = 1; + } +} + +clearCommands(); \ No newline at end of file diff --git a/commands/applications/cookies.js b/commands/applications/cookies.js new file mode 100644 index 0000000..543fe13 --- /dev/null +++ b/commands/applications/cookies.js @@ -0,0 +1,844 @@ +const { + SlashCommandBuilder, + EmbedBuilder +} = require("discord.js"); + +const { mClient } = require("../.."); + + +const DATABASE = "neo-db"; + +const COOKIE_COLLECTION = "items_cookies"; +const COOLDOWN_COLLECTION = "cooldowns_cookies"; + +const COLLECT_COOLDOWN = 60 * 60; // 1 hour +const STEAL_COOLDOWN = 15 * 60; // 15 minutes + +const STEAL_SUCCESS_CHANCE = 0.50; + +const ABRA_ID = "378135175059603457"; +const ABRA_MULTIPLIER = 1.5; + + +module.exports = { + data: new SlashCommandBuilder() + .setName("cookies") + .setDescription("The ShaiBot cookie economy.") + + .addSubcommand(subcommand => + subcommand + .setName("collect") + .setDescription("Collect a fresh batch of cookies.") + ) + + .addSubcommand(subcommand => + subcommand + .setName("steal") + .setDescription("Attempt to steal another user's cookies.") + .addUserOption(option => + option + .setName("target") + .setDescription("The unfortunate victim.") + .setRequired(true) + ) + ) + + .addSubcommand(subcommand => + subcommand + .setName("check") + .setDescription("Check a cookie balance.") + .addUserOption(option => + option + .setName("target") + .setDescription("The user whose cookies you want to check.") + ) + ) + + .addSubcommand(subcommand => + subcommand + .setName("give") + .setDescription("Give some of your cookies to another user.") + .addUserOption(option => + option + .setName("target") + .setDescription("The recipient.") + .setRequired(true) + ) + .addIntegerOption(option => + option + .setName("amount") + .setDescription("How many cookies to give.") + .setRequired(true) + .setMinValue(1) + ) + ) + + .addSubcommand(subcommand => + subcommand + .setName("leaderboard") + .setDescription("Show the richest cookie collectors.") + ), + + async execute(interaction) { + switch (interaction.options.getSubcommand()) { + case "collect": + return collect(interaction); + + case "steal": + return steal(interaction); + + case "check": + return check(interaction); + + case "give": + return give(interaction); + + case "leaderboard": + return leaderboard(interaction); + + default: + return interaction.reply({ + content: "Unknown subcommand.", + ephemeral: true + }); + } + } +}; + + +/* + * DATABASE + */ + +function getCollections() { + const db = mClient.db(DATABASE); + + return { + cookies: db.collection(COOKIE_COLLECTION), + cooldowns: db.collection(COOLDOWN_COLLECTION) + }; +} + + +/* + * COOKIE HELPERS + */ + +async function getCookieBalance(userId) { + const { cookies } = getCollections(); + + const result = await cookies.findOne( + { + userId + }, + { + projection: { + _id: 0, + cookies: 1 + } + } + ); + + return result?.cookies ?? 0; +} + + +async function changeCookies(userId, amount, session = undefined) { + const { cookies } = getCollections(); + + return cookies.updateOne( + { + userId + }, + { + $inc: { + cookies: amount + }, + $setOnInsert: { + userId + } + }, + { + upsert: true, + session + } + ); +} + + +/* + * COOKIE TRANSFER + * + * This uses a transaction so both balances update together. + * + * MongoDB transactions require Atlas or a replica set. + */ + +async function transferCookies(fromUserId, toUserId, amount) { + const { cookies } = getCollections(); + + const session = mClient.startSession(); + + try { + await session.withTransaction(async () => { + + /* + * Only debit if the sender still has enough cookies. + * + * This protects against two commands being executed + * at almost the same time. + */ + const debit = await cookies.updateOne( + { + userId: fromUserId, + cookies: { + $gte: amount + } + }, + { + $inc: { + cookies: -amount + } + }, + { + session + } + ); + + + if (debit.modifiedCount !== 1) { + throw new Error("INSUFFICIENT_COOKIES"); + } + + + await cookies.updateOne( + { + userId: toUserId + }, + { + $inc: { + cookies: amount + }, + $setOnInsert: { + userId: toUserId + } + }, + { + upsert: true, + session + } + ); + }); + + } finally { + await session.endSession(); + } +} + + +/* + * COOLDOWN HELPERS + * + * cooldowns_cookies: + * + * { + * userId: "...", + * guildId: "...", + * collect: 1786741200, + * steal: 1786738500 + * } + */ + +async function getCooldown(userId, guildId, type) { + const { cooldowns } = getCollections(); + + const result = await cooldowns.findOne( + { + userId, + guildId + }, + { + projection: { + _id: 0, + [type]: 1 + } + } + ); + + return result?.[type] ?? 0; +} + + +async function setCooldown(userId, guildId, type, duration) { + const { cooldowns } = getCollections(); + + const now = getUnixTime(); + const next = now + duration; + + await cooldowns.updateOne( + { + userId, + guildId + }, + { + $set: { + [type]: next + }, + $setOnInsert: { + userId, + guildId + } + }, + { + upsert: true + } + ); + + return next; +} + + +/* + * /cookies collect + */ + +async function collect(interaction) { + const userId = interaction.user.id; + const guildId = interaction.guildId; + + const now = getUnixTime(); + + const cooldown = await getCooldown( + userId, + guildId, + "collect" + ); + + + if (cooldown > now) { + return interaction.reply({ + content: + `The batch is still cooking. Come back πŸͺ`, + ephemeral: true + }); + } + + + let amount = randomInteger(1, 20); + + + /* + * Legacy Abra bonus. + */ + if (userId === ABRA_ID) { + amount = Math.ceil( + amount * ABRA_MULTIPLIER + ); + } + + + await changeCookies( + userId, + amount + ); + + + await setCooldown( + userId, + guildId, + "collect", + COLLECT_COOLDOWN + ); + + + return interaction.reply({ + content: randomCollectResponse( + amount, + interaction.user + ) + }); +} + + +/* + * /cookies steal + */ + +async function steal(interaction) { + const user = interaction.user; + + const target = interaction.options.getUser( + "target", + true + ); + + + /* + * Can't rob yourself. + */ + if (target.id === user.id) { + return interaction.reply({ + content: + "C'mon, don't embarrass yourself. You can't steal from yourself.", + ephemeral: true + }); + } + + + /* + * Don't let people farm bot accounts. + */ + if (target.bot) { + return interaction.reply({ + content: + "Bots have highly sophisticated cookie security systems.", + ephemeral: true + }); + } + + + const now = getUnixTime(); + + + /* + * Check steal cooldown before doing anything expensive. + */ + const cooldown = await getCooldown( + user.id, + interaction.guildId, + "steal" + ); + + + if (cooldown > now) { + return interaction.reply({ + content: + `Lay low for a while. You can steal again .`, + ephemeral: true + }); + } + + + /* + * Fetch both balances concurrently. + */ + const [ + yourCookies, + theirCookies + ] = await Promise.all([ + getCookieBalance(user.id), + getCookieBalance(target.id) + ]); + + + if (yourCookies < 1) { + return interaction.reply({ + content: + "You need at least **1 Cookie** to attempt a robbery.", + ephemeral: true + }); + } + + + if (theirCookies < 1) { + return interaction.reply({ + content: + `Shame on you! ${target} doesn't have any Cookies. D:`, + ephemeral: true + }); + } + + + /* + * Chaos mode: + * fixed 50% steal chance. + */ + const success = + Math.random() < STEAL_SUCCESS_CHANCE; + + + /* + * Successful robbery. + */ + if (success) { + const maxSteal = Math.max( + 1, + Math.ceil(theirCookies / 4) + ); + + const amount = Math.min( + theirCookies, + randomInteger( + 1, + maxSteal + ) + ); + + + try { + await transferCookies( + target.id, + user.id, + amount + ); + } catch (error) { + if (error.message === "INSUFFICIENT_COOKIES") { + return interaction.reply({ + content: + `${target}'s Cookie balance changed before you could finish the robbery.`, + ephemeral: true + }); + } + + throw error; + } + + + const nextSteal = await setCooldown( + user.id, + interaction.guildId, + "steal", + STEAL_COOLDOWN + ); + + + return interaction.reply({ + content: + `${randomStealSuccessResponse(amount, target)}\n` + + `**Success Chance:** ${formatPercentage(STEAL_SUCCESS_CHANCE)} β€’ ` + + `Next robbery ` + }); + } + + + /* + * Failed robbery. + * + * Lose between 1 and roughly 1/6 of your balance. + */ + const maxPenalty = Math.max( + 1, + Math.ceil(yourCookies / 6) + ); + + const penalty = Math.min( + yourCookies, + randomInteger( + 1, + maxPenalty + ) + ); + + + try { + await transferCookies( + user.id, + target.id, + penalty + ); + } catch (error) { + if (error.message === "INSUFFICIENT_COOKIES") { + return interaction.reply({ + content: + "Your Cookie balance changed before the robbery could finish.", + ephemeral: true + }); + } + + throw error; + } + + + const nextSteal = await setCooldown( + user.id, + interaction.guildId, + "steal", + STEAL_COOLDOWN + ); + + + return interaction.reply({ + content: + `${randomStealFailResponse(penalty, target)}\n` + + `**Success Chance:** ${formatPercentage(STEAL_SUCCESS_CHANCE)} β€’ ` + + `Next robbery ` + }); +} + + +/* + * /cookies check + */ + +async function check(interaction) { + const target = + interaction.options.getUser("target") + ?? interaction.user; + + + const balance = + await getCookieBalance(target.id); + + + const mood = + balance === 0 + ? "πŸ˜”" + : "πŸͺ"; + + + return interaction.reply({ + content: + `${target} has **${balance.toLocaleString()} Cookie${balance === 1 ? "" : "s"}**! ${mood}` + }); +} + + +/* + * /cookies give + */ + +async function give(interaction) { + const user = interaction.user; + + const target = interaction.options.getUser( + "target", + true + ); + + const amount = interaction.options.getInteger( + "amount", + true + ); + + + if (target.id === user.id) { + return interaction.reply({ + content: + "You cannot give Cookies to yourself.", + ephemeral: true + }); + } + + + if (target.bot) { + return interaction.reply({ + content: + "Bots don't need Cookies. Allegedly.", + ephemeral: true + }); + } + + + try { + await transferCookies( + user.id, + target.id, + amount + ); + } catch (error) { + if (error.message === "INSUFFICIENT_COOKIES") { + return interaction.reply({ + content: + "We don't run a charity here. You don't have enough Cookies!", + ephemeral: true + }); + } + + throw error; + } + + + return interaction.reply({ + content: + `${user} shared **${amount.toLocaleString()} Cookie${amount === 1 ? "" : "s"}** with ${target} πŸͺ` + }); +} + + +/* + * /cookies leaderboard + */ + +async function leaderboard(interaction) { + const { cookies } = getCollections(); + + + const results = await cookies + .find({ + cookies: { + $gt: 0 + } + }) + .sort({ + cookies: -1 + }) + .limit(10) + .toArray(); + + + const description = results.length + ? results + .map((record, index) => { + const medal = getLeaderboardMedal(index); + + return ( + `${medal} <@${record.userId}> β€” ` + + `**${record.cookies.toLocaleString()}** πŸͺ` + ); + }) + .join("\n") + : "Nobody has collected any Cookies yet."; + + + const embed = new EmbedBuilder() + .setTitle("πŸͺ Cookie Leaderboard") + .setDescription(description) + .setTimestamp(); + + + if (interaction.guild?.iconURL()) { + embed.setThumbnail( + interaction.guild.iconURL({ + size: 256 + }) + ); + } + + + return interaction.reply({ + embeds: [embed] + }); +} + + +/* + * COLLECT RESPONSES + */ + +function randomCollectResponse(amount, user) { + const cookies = + `**${amount.toLocaleString()} Cookie${amount === 1 ? "" : "s"}**`; + + + const responses = [ + `${user}, I made you ${cookies} πŸͺ`, + `${user}, here's your ${cookies} πŸͺ I ate the rest, sorry >.<`, + `Only ${cookies} πŸͺ for you today ${user}... Abra stole the rest :c`, + `${user}, would you like a glass of milk with your ${cookies}? πŸ₯›`, + `${cookies} πŸͺ Careful, ${user}! They're still warm :3`, + `${cookies} πŸͺ Best batch yet!`, + `${user}, these ${cookies} I bequeath unto thine own self upon this day.`, + `${user}, your ${cookies} are fresh out of the oven. Try not to burn your tongue!`, + `${user}, I bribed the Cookie Monster to spare these ${cookies} just for you.`, + `${user}, Santa came early! You got ${cookies}. Milk not included.`, + `${user}, your ${cookies} are artisanal, gluten-free, and slightly cursed.`, + `A wild baker appeared! They hand ${user} ${cookies} πŸͺ`, + `${user}, Abra said these ${cookies} are "totally not stolen"... πŸ€”`, + `${user}, here's your ${cookies} β€” watch out, they may be booby-trapped.` + ]; + + + return randomItem(responses); +} + + +/* + * STEAL SUCCESS RESPONSES + */ + +function randomStealSuccessResponse(amount, target) { + const cookies = + `**${amount.toLocaleString()} Cookie${amount === 1 ? "" : "s"}**`; + + + const responses = [ + `You've successfully stolen ${cookies} from ${target}!`, + `Ninja mode activated. You snatched ${cookies} from ${target} without leaving a crumb behind.`, + `Abra taught you well β€” ${cookies} from ${target} are now yours!`, + `Like a phantom in the night, you took ${cookies} from ${target}.`, + `You just pulled the sweetest heist: ${cookies} from ${target}!`, + `Mission complete. ${target} is ${cookies} poorer.`, + `You distracted ${target} with a dance and swiped ${cookies}.`, + `Clean getaway! ${target} won't notice the missing ${cookies} until it's too late.`, + `The Cookie Vault has been breached. ${cookies} taken from ${target}.`, + `You emerged from the shadows carrying ${cookies} from ${target}.` + ]; + + + return randomItem(responses); +} + + +/* + * STEAL FAILURE RESPONSES + */ + +function randomStealFailResponse(amount, target) { + const cookies = + `**${amount.toLocaleString()} Cookie${amount === 1 ? "" : "s"}**`; + + + const responses = [ + `You were caught red-handed by ${target} and lost ${cookies} as a penalty!`, + `Fail! ${target} caught you mid-bite β€” you dropped ${cookies}.`, + `Not your best moment... You lost ${cookies} to ${target} in the struggle.`, + `Stealth level: 0. You handed ${cookies} to ${target} as an apology.`, + `The Cookie jar was booby-trapped! You gave ${cookies} to ${target} while running away.`, + `Ouch. The guard dog barked, and now ${target} has your ${cookies}.`, + `You tripped over your own shoelace β€” ${target} picked up ${cookies}.`, + `Caught by the Cookie Police! ${cookies} confiscated and given to ${target}.`, + `Your pockets had holes... ${target} found the ${cookies} you dropped.` + ]; + + + return randomItem(responses); +} + + +/* + * GENERIC HELPERS + */ + +function getUnixTime() { + return Math.floor( + Date.now() / 1000 + ); +} + + +function randomInteger(min, max) { + return Math.floor( + Math.random() * (max - min + 1) + ) + min; +} + + +function randomItem(items) { + return items[ + Math.floor( + Math.random() * items.length + ) + ]; +} + + +function formatPercentage(value) { + return `${Math.round(value * 100)}%`; +} + + +function getLeaderboardMedal(index) { + switch (index) { + case 0: + return "πŸ₯‡"; + + case 1: + return "πŸ₯ˆ"; + + case 2: + return "πŸ₯‰"; + + default: + return `**${index + 1}.**`; + } +} \ No newline at end of file diff --git a/commands/cookies.js b/commands/cookies.js deleted file mode 100644 index 33428bf..0000000 --- a/commands/cookies.js +++ /dev/null @@ -1,312 +0,0 @@ -// cookies.js β€” rewritten & rebalanced -const { MongoClient, ServerApiVersion } = require('mongodb'); -require('dotenv').config(); - -const cookieSchema = require("../schemas/cookieSchema"); // expected to support findOne, findOneAndUpdate, updateOne, find -const cooldownSchema = require("../schemas/cooldownSchema"); // expected to support findOne, findOneAndUpdate -const Discord = require('discord.js'); - -const URI = process.env.URI; -if (!URI) throw new Error("Missing process.env.URI for MongoDB"); - -// single client reused -const client = new MongoClient(URI, { - useNewUrlParser: true, - useUnifiedTopology: true, - serverApi: ServerApiVersion.v1 -}); -client.connect().catch(err => { - console.error("Mongo connect error:", err); -}); - -// util -const msToTime = (duration) => { - const ms = Math.floor((duration % 1000) / 100); - const s = Math.floor((duration / 1000) % 60); - const m = Math.floor((duration / (1000 * 60)) % 60); - const h = Math.floor((duration / (1000 * 60 * 60)) % 24); - const pad = n => (n < 10 ? "0" + n : "" + n); - return `${pad(h)}:${pad(m)}:${pad(s)}`; -}; - -const delay = ms => new Promise(r => setTimeout(r, ms)); - -// --- Helpers --- -async function getCookies(userId) { - const rec = await cookieSchema.findOne({ _id: userId }); - return rec && typeof rec.cookies === 'number' ? rec.cookies : 0; -} - -async function changeCookies(userId, delta, username = null) { - // upsert and set username if provided - const update = { $inc: { cookies: delta } }; - if (username) update.$set = { user: username }; - return cookieSchema.findOneAndUpdate( - { _id: userId }, - update, - { upsert: true, returnDocument: 'after' } - ); -} - -async function getCooldown(uniqueId) { - const rec = await cooldownSchema.findOne({ _id: uniqueId }); - return rec && rec.cooldown ? rec.cooldown : 0; -} - -async function setCooldown(uniqueId, command, subcommand, msTimestamp) { - await cooldownSchema.findOneAndUpdate( - { _id: uniqueId }, - { _id: uniqueId, command, subcommand, cooldown: msTimestamp }, - { upsert: true } - ); -} - -function cooldownId(guildId, userId, command, subcommand) { - return `${guildId}-${userId}-${command}-${subcommand}`; -} - -// --- Game logic & rebalances --- -// Notes about balancing: -// - Collect: 1..20 cookies (consistent reward); Abra (special user id) gets 1.5x. -// - Steal: -// * successChance = attacker / (attacker + defender), clamped to [0.10, 0.90] -// * steal amount: random 1..ceil(defender/4) -// * failure penalty: attacker loses random 1..ceil(attacker/6) (transferred to defender) -// - Cooldowns: collect = 1 hour, steal = 15 minutes - -const ABRA_ID = "378135175059603457"; // kept from original for bonus - -async function collect(interaction, user) { - const sub = interaction.options._subcommand; - const id = cooldownId(interaction.guildId, interaction.user.id, interaction.commandName, sub); - const now = Date.now(); - const existing = await getCooldown(id); - if (existing > now) { - return interaction.reply({ - content: `The batch is still cooking, come back in **${msToTime(existing - now)}**`, - ephemeral: true - }); - } - - // set cooldown (1 hour) - const cooldownUntil = now + 60 * 60 * 1000; - await setCooldown(id, interaction.commandName, sub, cooldownUntil); - - // balanced collect amount: 1..20 - let amount = Math.floor(Math.random() * 20) + 1; - if (user.id === ABRA_ID) amount = Math.ceil(amount * 1.5); - - // update DB - await changeCookies(user.id, amount, user.username); - - // playful responses (kept / adapted) - const collectResponses = (amount, user) => { - const s = amount === 1 ? 'Cookie' : 'Cookies'; - return [ - `${user}, I made you **${amount}** ${s} πŸͺ`, - `${user}, here's your **${amount}** ${s} πŸͺ I ate the rest, sorry >.<`, - `Only **${amount}** ${s} πŸͺ for you today ${user}... Abra stole the rest :c`, - `${user}, would you like a Glass of Milk with your **${amount}** ${s}? πŸͺ`, - `**${amount}** ${s} πŸͺ Careful, ${user}! They're still warm :3`, - `**${amount}** ${s} πŸͺ Best Batch yet!`, - `**${amount}** ${s} πŸͺ These, I bequeath unto thine own self upon this day. Thou must guard them safely.`, - `${user}, your **${amount}** ${s} πŸͺ are fresh out of the oven... try not to burn your tongue!`, - `${user}, I bribed the Cookie Monster to spare these **${amount}** ${s} πŸͺ just for you.`, - `${user}, Santa came early! You got **${amount}** ${s} πŸͺ (milk not included).`, - `${user}, your **${amount}** ${s} πŸͺ are artisanal, gluten-free, and slightly cursed.`, - `A wild baker appeared! They hand you **${amount}** ${s} πŸͺ`, - `${user}, Abra said these **${amount}** ${s} πŸͺ are "totally not stolen"... πŸ€”`, - `${user}, here’s your **${amount}** ${s} πŸͺ β€” watch out, they may be booby-trapped.` - ]; - }; - - - const responses = collectResponses(amount, user); - const i = Math.floor(Math.random() * responses.length); - return interaction.reply({ content: responses[i] }); - -} - -async function steal(interaction, user) { - const target = interaction.options.getUser('target'); - if (!target) { - return interaction.reply({ content: `Pick someone to steal from.`, ephemeral: true }); - } - if (target.id === user.id) { - return interaction.reply({ - content: `C'mon, don't embarrass yourself! We all know you couldn't do that, even if you tried.`, - ephemeral: true - }); - } - - // pull balances - const your = await getCookies(user.id); - const their = await getCookies(target.id); - - if (your <= 0) { - return interaction.reply({ content: `You need at least 1 Cookie to attempt a Robbery`, ephemeral: true }); - } - if (their <= 0) { - return interaction.reply({ content: `Shame on you! ${target.username} doesn't have any Cookies D:`, ephemeral: true }); - } - - // steal cooldown (15 minutes) - const sub = interaction.options._subcommand; - const id = cooldownId(interaction.guildId, interaction.user.id, interaction.commandName, sub); - const now = Date.now(); - const existing = await getCooldown(id); - const chaos = true // 50% Stela Chance Mode - - if (existing > now) { - return interaction.reply({ - content: `Hold up β€” try stealing again in **${msToTime(existing - now)}**`, - ephemeral: true - }); - } - await setCooldown(id, interaction.commandName, sub, now + 15 * 60 * 1000); - - // success chance and clamping - let successChance = your / (your + their); - if (isNaN(successChance) || !isFinite(successChance)) successChance = 0.2; - if (chaos) { - successChance = 0.5 - } else { - successChance = Math.max(0.10, Math.min(0.90, successChance)); - } - const success = Math.random() < successChance; - - if (success) { - const stealSuccessResponses = (amount, target) => { - const s = amount === 1 ? 'Cookie' : 'Cookies'; - return [ - `You've successfully stolen **${amount}** ${s} from **${target.username}**!`, - `Ninja mode: activated. You snatched **${amount}** ${s} from **${target.username}** without a crumb left behind.`, - `Abra taught you well β€” **${amount}** ${s} from **${target.username}** are now yours!`, - `Like a phantom in the night, you took **${amount}** ${s} from **${target.username}**.`, - `You just pulled the sweetest heist: **${amount}** ${s} from **${target.username}**!`, - `Mission complete. **${target.username}** is **${amount}** ${s} poorer, you are richer.`, - `You distracted **${target.username}** with a dance and swiped **${amount}** ${s}.`, - `Clean getaway! **${target.username}** won’t know about the missing **${amount}** ${s} until it’s too late.`, - `The Cookie Vault has been breached. **${amount}** ${s} taken from **${target.username}**.`, - `You emerged from the shadows with **${amount}** ${s} from **${target.username}**.` - ]; - }; - - const maxSteal = Math.max(1, Math.ceil(their / 4)); // steal up to ~25% of victim - let amount = Math.floor(Math.random() * maxSteal) + 1; - amount = Math.min(amount, their); - - // transfer - await Promise.all([ - changeCookies(user.id, amount, user.username), - changeCookies(target.id, -amount, target.username) - ]); - - const responses = stealSuccessResponses(amount, target); - const i = Math.floor(Math.random() * responses.length); - return interaction.reply({ content: `${responses[i]} (Chance: ${Math.round(successChance * 100, 2)}%)` }); - - } else { - const stealFailResponses = (penalty, target) => { - const s = penalty === 1 ? 'Cookie' : 'Cookies'; - return [ - `You were caught red-handed by **${target.username}** and lost **${penalty}** ${s} as a penalty!`, - `Fail! **${target.username}** caught you mid-bite β€” you dropped **${penalty}** ${s}.`, - `Not your best moment... You lost **${penalty}** ${s} to **${target.username}** in the struggle.`, - `Stealth level: 0. You handed **${penalty}** ${s} to **${target.username}** as an apology.`, - `The cookie jar was booby-trapped! You gave **${penalty}** ${s} to **${target.username}** while running away.`, - `Ouch. The guard dog barked, and now **${target.username}** has your **${penalty}** ${s}.`, - `You tripped over your own shoelace β€” **${target.username}** reclaimed **${penalty}** ${s}.`, - `Caught by the Cookie Police! **${penalty}** ${s} confiscated and given to **${target.username}**.`, - `Your pockets had holes... **${target.username}** picked up **${penalty}** ${s} you dropped.` - ]; - }; - - - // failure penalty: attacker loses a little (1..ceil(your/6)) to the victim - const maxPenalty = Math.max(1, Math.ceil(your / 6)); - const penalty = Math.min(your, Math.floor(Math.random() * maxPenalty) + 1); - - await Promise.all([ - changeCookies(user.id, -penalty, user.username), - changeCookies(target.id, +penalty, target.username) - ]); - - const responses = stealFailResponses(penalty, target); - const i = Math.floor(Math.random() * responses.length); - return interaction.reply({ content: `${responses[i]} (Chance: ${Math.round(successChance * 100, 2)}%)` }); - - } -} - -async function check(interaction, user) { - let target = interaction.options.getUser('target'); - if (!target) target = user; - - const cookies = await getCookies(target.id); - const mood = cookies === 0 ? 'πŸ˜”' : '😲'; - return interaction.reply({ content: `**${target.username}** has **${cookies}** Cookies! ${mood}` }); -} - -async function give(interaction, user) { - const target = interaction.options.getUser('target'); - const amount = interaction.options.getInteger('amount'); - - if (!target) return interaction.reply({ content: `You need to specify a target.`, ephemeral: true }); - if (target.id === user.id) return interaction.reply({ content: 'You cannot give yourself Cookies ._."', ephemeral: true }); - if (!Number.isInteger(amount) || amount < 1) { - return interaction.reply({ content: `**${user}** shared *checks notes* **${amount}** Cookie(s) with ${target}....wait a minute!!`, ephemeral: true }); - } - - const your = await getCookies(user.id); - if (your < amount) return interaction.reply({ content: `We don't run a charity here, get more Cookies!`, ephemeral: true }); - - await Promise.all([ - changeCookies(user.id, -amount, user.username), - changeCookies(target.id, +amount, target.username) - ]); - - // small delay to mimic previous behavior - await delay(200); - return interaction.reply({ content: `**${user}** shared **${amount}** Cookie(s) with ${target}` }); -} - -async function leader(interaction) { - const results = await cookieSchema.find().sort({ cookies: -1 }).limit(10); - let cookieSorted = ''; - results.forEach((r, i) => { - cookieSorted += `[${i + 1}] <@${r._id}> (${r.cookies})\n`; - }); - - const embed = new Discord.MessageEmbed() - .setColor(0x0099FF) - .setThumbnail(interaction.guild.iconURL()) - .setTimestamp() - .addFields({ name: `-Cookie Leaderboard-`, value: cookieSorted || 'No cookie data yet.' }); - - return interaction.reply({ embeds: [embed] }); -} - -module.exports = { - slash: true, - description: 'collect a cookie', - category: 'Misc', - options: [ - { name: "collect", description: "want some?", type: 1 }, - { name: "steal", description: "try your luck at a lala robbery!", type: 1, options: [{ name: "target", description: "someone", required: true, type: 6 }] }, - { name: "check", description: "check your cookie stash", type: 1, options: [{ name: "target", description: "someone", type: 6 }] }, - { name: "give", description: "share your cookies with someone", type: 1, options: [{ name: "target", description: "someone", required: true, type: 6 }, { name: "amount", description: "cookies", required: true, type: 4 }] }, - { name: "leader", description: "show Top 10 Cookie Clickers", type: 1 } - ], - callback: ({ interaction, user }) => { - const sub = interaction.options._subcommand; - switch (sub) { - case "collect": return collect(interaction, user); - case "steal": return steal(interaction, user); - case "check": return check(interaction, user); - case "give": return give(interaction, user); - case "leader": return leader(interaction); - default: return interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); - } - } -}; diff --git a/commands/cookies.js.10082025.old b/commands/cookies.js.10082025.old deleted file mode 100644 index 81e093c..0000000 --- a/commands/cookies.js.10082025.old +++ /dev/null @@ -1,448 +0,0 @@ -const { MongoClient, ServerApiVersion } = require('mongodb'); -require('dotenv').config(); -const uri = process.env.URI -const cookieSchema = require("../schemas/cookieSchema") -const cooldownSchema = require("../schemas/cooldownSchema") -const delay = ms => new Promise(resolve => setTimeout(resolve, ms)) -const Discord = require('discord.js') -const client = new MongoClient(uri, { - useNewUrlParser: true, - useUnifiedTopology: true, - serverApi: ServerApiVersion.v1 -}); -function msToTime(duration) { - var milliseconds = parseInt((duration % 1000) / 100), - seconds = Math.floor((duration / 1000) % 60), - minutes = Math.floor((duration / (1000 * 60)) % 60), - hours = Math.floor((duration / (1000 * 60 * 60)) % 24); - - hours = (hours < 10) ? "0" + hours : hours; - minutes = (minutes < 10) ? "0" + minutes : minutes; - seconds = (seconds < 10) ? "0" + seconds : seconds; - - return hours + ":" + minutes + ":" + seconds; -} -async function collect(interaction, user) { - client.connect(async (err, db) => { - var dbo = db.db('test') - let id = `${interaction.guildId}-${interaction.user.id}-${interaction.commandName}-${interaction.options._subcommand}` - dbo.collection('cooldowns').findOne({ - _id: id - }, async function (err, results) { - let now = Date.now() - let time = now + 3600000 // plus one hour in ms - if (results) { - if (results.cooldown > now) { - time = new Date(results.cooldown).toUTCString() - return interaction.reply({ - content: `The batch is still cooking, come back in **${msToTime(results.cooldown - now)}**`, - ephemeral: true - }) - } - } - addCooldown(interaction.user.id, interaction.guildId, interaction.commandName, interaction.options._subcommand, time) - - - var amount = Math.floor(Math.random() * 30) - //random amount between 1 and 29 - if (user.id == "378135175059603457") { - //Abra Bonus - amount = Math.ceil(amount * 1.5) - } - - var responses = [ - `${user}, I made you **${amount}** ${amount == 1?`Cookie`: `Cookies`} πŸͺ `, - `${user}, Here's your **${amount}** ${amount == 1?`Cookie`: `Cookies`} πŸͺ I ate the rest, sorry >.<`, - `Only **${amount}** ${amount == 1?`Cookie`: `Cookies`} πŸͺ for you today ${user}... Abra stole the rest :c`, - `${user}, would you like a Glass of Milk with your **${amount}** ${amount == 1?`Cookie`: `Cookies`}? πŸͺ `, - `**${amount}** ${amount == 1?`Cookie`: `Cookies`} πŸͺ Careful, ${user}! They're still warm :3`, - `**${amount}** ${amount == 1?`Cookie`: `Cookies`} πŸͺ Best Batch yet!`, - `**${amount}** ${amount == 1?`Cookie`: `Cookies`} πŸͺ These, I bequeath unto thine own self upon this day. Thou must guard them safely.`, - ] - - await cookieSchema.findOneAndUpdate({ - _id: user.id - }, { - _id: user.id, - user: user.username, - $inc: { cookies: +amount } - }, { - upsert: true - }) - - if(amount === 0){ - interaction.reply({ - content: `${user}, someone ate all your Cookies already D:` - }) - } else { - var i = Math.floor(Math.random() * responses.length) - interaction.reply({ - content: responses[i] - }) - } - // choose response - }) - }) -} -/* -function steal(interaction, user) { - client.connect(async (err, db) => { - if (err) throw err; - let target = interaction.options.getUser('target') - let dbo = db.db("test") - - if (target.id == user.id) { - return interaction.reply({ - content: `C'mon, don't embarass yourself! We all know you couldn't do that, even if you tried.`, - ephemeral: true, - }) - } - - // get your amount of cookies - let your = await dbo.collection('cookies').findOne({ - _id: user.id - }) - // get their amount of cookies - let their = await dbo.collection('cookies').findOne({ - _id: target.id - }) - try { - if (!your.cookies) { - return interaction.reply({ - content: `You need at least 1 Cookie to attempt a Robbery`, - ephemeral: true, - }) - } - if (!their.cookies) { - return interaction.reply({ - content: `Shame on you! They don't even have any Cookies D:`, - ephemeral: true, - }) - } - } catch (error) { - return interaction.reply({ - content: `How awkward...I don't know some of you!`, - ephemeral: true, - }) - } - let difficulty = [] - for (var i = 0; i < their.cookies; i++) { - if (i < your.cookies) { - difficulty.push(true) - } else { - difficulty.push(false) - } - } - let result = Math.floor(Math.random() * their.cookies) + 1 - let response - if (!difficulty[result]) { - // author lost - response = `You were unsuccessful at robbing **${target.username}** and lost your chance at **${result}** ${result == 1?`Cookie`: `Cookies`}! ` - if (your.cookies - result <= 0) { - result = your.cookies - response += `That's all your Cookies gone.` - } - result *= -1 - - } else { - //author won - response = `You've successfully stolen **${result { - cookieSorted += `[${i + 1}] <@${result._id}> (${result.cookies})\n` - i++; - }) - - var embed = new Discord.MessageEmbed() - .setColor(0x0099FF) - .setThumbnail(interaction.guild.iconURL()) - .setTimestamp() - .addFields({ name: `-Cookie Leaderboard-`, value: cookieSorted }) - - interaction.reply({ - embeds: [embed] - }) -} -module.exports = { - slash: true, - description: 'collect a cookie', - category: 'Misc', - options: [ - //collect - { - name: "collect", - description: "want some?", - type: 1 // SubCommand Type - }, - //steal - { - name: "steal", - description: "try your luck at a lala robbery!", - type: 1, // SubCommand Type - options: [ - { - name: "target", - description: "someone", - required: true, - type: 6 // User Type - } - ] - }, - //check - { - name: "check", - description: "check your cookie stash", - required: false, - type: 1, // SubCommand Type - options: [ - { - name: "target", - description: "someone", - type: 6 // User Type - } - ] - }, - //give - { - name: "give", - description: "share your cookies with someone", - required: false, - type: 1, // SubCommand Type - options: [ - { - name: "target", - description: "someone", - required: true, - type: 6 // User Type - }, { - name: "amount", - description: "cookies", - required: true, - type: 4 // Integer Type - } - ] - }, - //leader - { - name: "leader", - description: "show Top 10 Cookie Clickers", - type: 1, // SubCommand Type - }, - ], - callback: ({ interaction, user }) => { - switch (interaction.options._subcommand) { - case "collect": - collect(interaction, user) - break; - case "steal": - steal(interaction, user) - break; - case "check": - check(interaction, user) - break; - case "give": - give(interaction, user) - break; - case "leader": - leader(interaction) - break; - default: - break; - } - } -} diff --git a/commands/cookies.js.1008202502.old b/commands/cookies.js.1008202502.old deleted file mode 100644 index adfc6df..0000000 --- a/commands/cookies.js.1008202502.old +++ /dev/null @@ -1,262 +0,0 @@ -// cookies.js β€” rewritten & rebalanced -const { MongoClient, ServerApiVersion } = require('mongodb'); -require('dotenv').config(); - -const cookieSchema = require("../schemas/cookieSchema"); // expected to support findOne, findOneAndUpdate, updateOne, find -const cooldownSchema = require("../schemas/cooldownSchema"); // expected to support findOne, findOneAndUpdate -const Discord = require('discord.js'); - -const URI = process.env.URI; -if (!URI) throw new Error("Missing process.env.URI for MongoDB"); - -// single client reused -const client = new MongoClient(URI, { - useNewUrlParser: true, - useUnifiedTopology: true, - serverApi: ServerApiVersion.v1 -}); -client.connect().catch(err => { - console.error("Mongo connect error:", err); -}); - -// util -const msToTime = (duration) => { - const ms = Math.floor((duration % 1000) / 100); - const s = Math.floor((duration / 1000) % 60); - const m = Math.floor((duration / (1000 * 60)) % 60); - const h = Math.floor((duration / (1000 * 60 * 60)) % 24); - const pad = n => (n < 10 ? "0" + n : "" + n); - return `${pad(h)}:${pad(m)}:${pad(s)}`; -}; - -const delay = ms => new Promise(r => setTimeout(r, ms)); - -// --- Helpers --- -async function getCookies(userId) { - const rec = await cookieSchema.findOne({ _id: userId }); - return rec && typeof rec.cookies === 'number' ? rec.cookies : 0; -} - -async function changeCookies(userId, delta, username = null) { - // upsert and set username if provided - const update = { $inc: { cookies: delta } }; - if (username) update.$set = { user: username }; - return cookieSchema.findOneAndUpdate( - { _id: userId }, - update, - { upsert: true, returnDocument: 'after' } - ); -} - -async function getCooldown(uniqueId) { - const rec = await cooldownSchema.findOne({ _id: uniqueId }); - return rec && rec.cooldown ? rec.cooldown : 0; -} - -async function setCooldown(uniqueId, command, subcommand, msTimestamp) { - await cooldownSchema.findOneAndUpdate( - { _id: uniqueId }, - { _id: uniqueId, command, subcommand, cooldown: msTimestamp }, - { upsert: true } - ); -} - -function cooldownId(guildId, userId, command, subcommand) { - return `${guildId}-${userId}-${command}-${subcommand}`; -} - -// --- Game logic & rebalances --- -// Notes about balancing: -// - Collect: 1..20 cookies (consistent reward); Abra (special user id) gets 1.5x. -// - Steal: -// * successChance = attacker / (attacker + defender), clamped to [0.10, 0.90] -// * steal amount: random 1..ceil(defender/4) -// * failure penalty: attacker loses random 1..ceil(attacker/6) (transferred to defender) -// - Cooldowns: collect = 1 hour, steal = 15 minutes - -const ABRA_ID = "378135175059603457"; // kept from original for bonus - -async function collect(interaction, user) { - const sub = interaction.options._subcommand; - const id = cooldownId(interaction.guildId, interaction.user.id, interaction.commandName, sub); - const now = Date.now(); - const existing = await getCooldown(id); - if (existing > now) { - return interaction.reply({ - content: `The batch is still cooking, come back in **${msToTime(existing - now)}**`, - ephemeral: true - }); - } - - // set cooldown (1 hour) - const cooldownUntil = now + 60 * 60 * 1000; - await setCooldown(id, interaction.commandName, sub, cooldownUntil); - - // balanced collect amount: 1..20 - let amount = Math.floor(Math.random() * 20) + 1; - if (user.id === ABRA_ID) amount = Math.ceil(amount * 1.5); - - // update DB - await changeCookies(user.id, amount, user.username); - - // playful responses (kept / adapted) - const responses = [ - `${user}, I made you **${amount}** ${amount === 1 ? 'Cookie' : 'Cookies'} πŸͺ`, - `${user}, here's your **${amount}** ${amount === 1 ? 'Cookie' : 'Cookies'} πŸͺ I ate the rest, sorry >.<`, - `Only **${amount}** ${amount === 1 ? 'Cookie' : 'Cookies'} πŸͺ for you today ${user}... Abra stole the rest :c`, - `${user}, would you like a Glass of Milk with your **${amount}** ${amount === 1 ? 'Cookie' : 'Cookies'}? πŸͺ`, - `**${amount}** ${amount === 1 ? 'Cookie' : 'Cookies'} πŸͺ Careful, ${user}! They're still warm :3`, - `**${amount}** ${amount === 1 ? 'Cookie' : 'Cookies'} πŸͺ Best Batch yet!`, - `**${amount}** ${amount === 1 ? 'Cookie' : 'Cookies'} πŸͺ These, I bequeath unto thine own self upon this day. Thou must guard them safely.` - ]; - - const i = Math.floor(Math.random() * responses.length); - return interaction.reply({ content: responses[i] }); -} - -async function steal(interaction, user) { - const target = interaction.options.getUser('target'); - if (!target) { - return interaction.reply({ content: `Pick someone to steal from.`, ephemeral: true }); - } - if (target.id === user.id) { - return interaction.reply({ - content: `C'mon, don't embarrass yourself! We all know you couldn't do that, even if you tried.`, - ephemeral: true - }); - } - - // steal cooldown (15 minutes) - const sub = interaction.options._subcommand; - const id = cooldownId(interaction.guildId, interaction.user.id, interaction.commandName, sub); - const now = Date.now(); - const existing = await getCooldown(id); - if (existing > now) { - return interaction.reply({ - content: `Hold up β€” try stealing again in **${msToTime(existing - now)}**`, - ephemeral: true - }); - } - await setCooldown(id, interaction.commandName, sub, now + 15 * 60 * 1000); - - // pull balances - const your = await getCookies(user.id); - const their = await getCookies(target.id); - - if (your <= 0) { - return interaction.reply({ content: `You need at least 1 Cookie to attempt a Robbery`, ephemeral: true }); - } - if (their <= 0) { - return interaction.reply({ content: `Shame on you! ${target.username} doesn't have any Cookies D:`, ephemeral: true }); - } - - // success chance and clamping - let successChance = your / (your + their); - if (isNaN(successChance) || !isFinite(successChance)) successChance = 0.2; - successChance = Math.max(0.50, Math.min(0.90, successChance)); // made it 50% for chaos - - const success = Math.random() < successChance; - - if (success) { - const maxSteal = Math.max(1, Math.ceil(their / 4)); // steal up to ~25% of victim - let amount = Math.floor(Math.random() * maxSteal) + 1; - amount = Math.min(amount, their); - - // transfer - await Promise.all([ - changeCookies(user.id, amount, user.username), - changeCookies(target.id, -amount, target.username) - ]); - - const s = amount === 1 ? 'Cookie' : 'Cookies'; - return interaction.reply({ - content: `You've successfully stolen **${amount}** ${s} from **${target.username}**!` - }); - } else { - // failure penalty: attacker loses a little (1..ceil(your/6)) to the victim - const maxPenalty = Math.max(1, Math.ceil(your / 6)); - const penalty = Math.min(your, Math.floor(Math.random() * maxPenalty) + 1); - - await Promise.all([ - changeCookies(user.id, -penalty, user.username), - changeCookies(target.id, +penalty, target.username) - ]); - - const s = penalty === 1 ? 'Cookie' : 'Cookies'; - return interaction.reply({ - content: `You were unsuccessful at robbing **${target.username}** and lost **${penalty}** ${s} as a penalty!` - }); - } -} - -async function check(interaction, user) { - let target = interaction.options.getUser('target'); - if (!target) target = user; - - const cookies = await getCookies(target.id); - const mood = cookies === 0 ? 'πŸ˜”' : '😲'; - return interaction.reply({ content: `**${target.username}** has **${cookies}** Cookies! ${mood}` }); -} - -async function give(interaction, user) { - const target = interaction.options.getUser('target'); - const amount = interaction.options.getInteger('amount'); - - if (!target) return interaction.reply({ content: `You need to specify a target.`, ephemeral: true }); - if (target.id === user.id) return interaction.reply({ content: 'You cannot give yourself Cookies ._."', ephemeral: true }); - if (!Number.isInteger(amount) || amount < 1) { - return interaction.reply({ content: `**${user}** shared *checks notes* **${amount}** Cookie(s) with ${target}....wait a minute!!`, ephemeral: true }); - } - - const your = await getCookies(user.id); - if (your < amount) return interaction.reply({ content: `We don't run a charity here, get more Cookies!`, ephemeral: true }); - - await Promise.all([ - changeCookies(user.id, -amount, user.username), - changeCookies(target.id, +amount, target.username) - ]); - - // small delay to mimic previous behavior - await delay(200); - return interaction.reply({ content: `**${user}** shared **${amount}** Cookie(s) with ${target}` }); -} - -async function leader(interaction) { - const results = await cookieSchema.find().sort({ cookies: -1 }).limit(10); - let cookieSorted = ''; - results.forEach((r, i) => { - cookieSorted += `[${i + 1}] <@${r._id}> (${r.cookies})\n`; - }); - - const embed = new Discord.MessageEmbed() - .setColor(0x0099FF) - .setThumbnail(interaction.guild.iconURL()) - .setTimestamp() - .addFields({ name: `-Cookie Leaderboard-`, value: cookieSorted || 'No cookie data yet.' }); - - return interaction.reply({ embeds: [embed] }); -} - -module.exports = { - slash: true, - description: 'collect a cookie', - category: 'Misc', - options: [ - { name: "collect", description: "want some?", type: 1 }, - { name: "steal", description: "try your luck at a lala robbery!", type: 1, options: [{ name: "target", description: "someone", required: true, type: 6 }] }, - { name: "check", description: "check your cookie stash", type: 1, options: [{ name: "target", description: "someone", type: 6 }] }, - { name: "give", description: "share your cookies with someone", type: 1, options: [{ name: "target", description: "someone", required: true, type: 6 }, { name: "amount", description: "cookies", required: true, type: 4 }] }, - { name: "leader", description: "show Top 10 Cookie Clickers", type: 1 } - ], - callback: ({ interaction, user }) => { - const sub = interaction.options._subcommand; - switch (sub) { - case "collect": return collect(interaction, user); - case "steal": return steal(interaction, user); - case "check": return check(interaction, user); - case "give": return give(interaction, user); - case "leader": return leader(interaction); - default: return interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); - } - } -}; diff --git a/commands/cookies.js.1008202503.old b/commands/cookies.js.1008202503.old deleted file mode 100644 index c47e6d9..0000000 --- a/commands/cookies.js.1008202503.old +++ /dev/null @@ -1,307 +0,0 @@ -// cookies.js β€” rewritten & rebalanced -const { MongoClient, ServerApiVersion } = require('mongodb'); -require('dotenv').config(); - -const cookieSchema = require("../schemas/cookieSchema"); // expected to support findOne, findOneAndUpdate, updateOne, find -const cooldownSchema = require("../schemas/cooldownSchema"); // expected to support findOne, findOneAndUpdate -const Discord = require('discord.js'); - -const URI = process.env.URI; -if (!URI) throw new Error("Missing process.env.URI for MongoDB"); - -// single client reused -const client = new MongoClient(URI, { - useNewUrlParser: true, - useUnifiedTopology: true, - serverApi: ServerApiVersion.v1 -}); -client.connect().catch(err => { - console.error("Mongo connect error:", err); -}); - -// util -const msToTime = (duration) => { - const ms = Math.floor((duration % 1000) / 100); - const s = Math.floor((duration / 1000) % 60); - const m = Math.floor((duration / (1000 * 60)) % 60); - const h = Math.floor((duration / (1000 * 60 * 60)) % 24); - const pad = n => (n < 10 ? "0" + n : "" + n); - return `${pad(h)}:${pad(m)}:${pad(s)}`; -}; - -const delay = ms => new Promise(r => setTimeout(r, ms)); - -// --- Helpers --- -async function getCookies(userId) { - const rec = await cookieSchema.findOne({ _id: userId }); - return rec && typeof rec.cookies === 'number' ? rec.cookies : 0; -} - -async function changeCookies(userId, delta, username = null) { - // upsert and set username if provided - const update = { $inc: { cookies: delta } }; - if (username) update.$set = { user: username }; - return cookieSchema.findOneAndUpdate( - { _id: userId }, - update, - { upsert: true, returnDocument: 'after' } - ); -} - -async function getCooldown(uniqueId) { - const rec = await cooldownSchema.findOne({ _id: uniqueId }); - return rec && rec.cooldown ? rec.cooldown : 0; -} - -async function setCooldown(uniqueId, command, subcommand, msTimestamp) { - await cooldownSchema.findOneAndUpdate( - { _id: uniqueId }, - { _id: uniqueId, command, subcommand, cooldown: msTimestamp }, - { upsert: true } - ); -} - -function cooldownId(guildId, userId, command, subcommand) { - return `${guildId}-${userId}-${command}-${subcommand}`; -} - -// --- Game logic & rebalances --- -// Notes about balancing: -// - Collect: 1..20 cookies (consistent reward); Abra (special user id) gets 1.5x. -// - Steal: -// * successChance = attacker / (attacker + defender), clamped to [0.10, 0.90] -// * steal amount: random 1..ceil(defender/4) -// * failure penalty: attacker loses random 1..ceil(attacker/6) (transferred to defender) -// - Cooldowns: collect = 1 hour, steal = 15 minutes - -const ABRA_ID = "378135175059603457"; // kept from original for bonus - -async function collect(interaction, user) { - const sub = interaction.options._subcommand; - const id = cooldownId(interaction.guildId, interaction.user.id, interaction.commandName, sub); - const now = Date.now(); - const existing = await getCooldown(id); - if (existing > now) { - return interaction.reply({ - content: `The batch is still cooking, come back in **${msToTime(existing - now)}**`, - ephemeral: true - }); - } - - // set cooldown (1 hour) - const cooldownUntil = now + 60 * 60 * 1000; - await setCooldown(id, interaction.commandName, sub, cooldownUntil); - - // balanced collect amount: 1..20 - let amount = Math.floor(Math.random() * 20) + 1; - if (user.id === ABRA_ID) amount = Math.ceil(amount * 1.5); - - // update DB - await changeCookies(user.id, amount, user.username); - - // playful responses (kept / adapted) - const collectResponses = (amount, user) => { - const s = amount === 1 ? 'Cookie' : 'Cookies'; - return [ - `${user}, I made you **${amount}** ${s} πŸͺ`, - `${user}, here's your **${amount}** ${s} πŸͺ I ate the rest, sorry >.<`, - `Only **${amount}** ${s} πŸͺ for you today ${user}... Abra stole the rest :c`, - `${user}, would you like a Glass of Milk with your **${amount}** ${s}? πŸͺ`, - `**${amount}** ${s} πŸͺ Careful, ${user}! They're still warm :3`, - `**${amount}** ${s} πŸͺ Best Batch yet!`, - `**${amount}** ${s} πŸͺ These, I bequeath unto thine own self upon this day. Thou must guard them safely.`, - `${user}, your **${amount}** ${s} πŸͺ are fresh out of the oven... try not to burn your tongue!`, - `${user}, I bribed the Cookie Monster to spare these **${amount}** ${s} πŸͺ just for you.`, - `${user}, Santa came early! You got **${amount}** ${s} πŸͺ (milk not included).`, - `${user}, your **${amount}** ${s} πŸͺ are artisanal, gluten-free, and slightly cursed.`, - `A wild baker appeared! They hand you **${amount}** ${s} πŸͺ`, - `${user}, Abra said these **${amount}** ${s} πŸͺ are "totally not stolen"... πŸ€”`, - `${user}, here’s your **${amount}** ${s} πŸͺ β€” watch out, they may be booby-trapped.` - ]; - }; - - - const responses = collectResponses(amount, user); - const i = Math.floor(Math.random() * responses.length); - return interaction.reply({ content: responses[i] }); - -} - -async function steal(interaction, user) { - const target = interaction.options.getUser('target'); - if (!target) { - return interaction.reply({ content: `Pick someone to steal from.`, ephemeral: true }); - } - if (target.id === user.id) { - return interaction.reply({ - content: `C'mon, don't embarrass yourself! We all know you couldn't do that, even if you tried.`, - ephemeral: true - }); - } - - // steal cooldown (15 minutes) - const sub = interaction.options._subcommand; - const id = cooldownId(interaction.guildId, interaction.user.id, interaction.commandName, sub); - const now = Date.now(); - const existing = await getCooldown(id); - if (existing > now) { - return interaction.reply({ - content: `Hold up β€” try stealing again in **${msToTime(existing - now)}**`, - ephemeral: true - }); - } - await setCooldown(id, interaction.commandName, sub, now + 15 * 60 * 1000); - - // pull balances - const your = await getCookies(user.id); - const their = await getCookies(target.id); - - if (your <= 0) { - return interaction.reply({ content: `You need at least 1 Cookie to attempt a Robbery`, ephemeral: true }); - } - if (their <= 0) { - return interaction.reply({ content: `Shame on you! ${target.username} doesn't have any Cookies D:`, ephemeral: true }); - } - - // success chance and clamping - let successChance = your / (your + their); - if (isNaN(successChance) || !isFinite(successChance)) successChance = 0.2; - successChance = Math.max(0.10, Math.min(0.90, successChance)); - - const success = Math.random() < successChance; - - if (success) { - const stealSuccessResponses = (amount, target) => { - const s = amount === 1 ? 'Cookie' : 'Cookies'; - return [ - `You've successfully stolen **${amount}** ${s} from **${target.username}**!`, - `Ninja mode: activated. You snatched **${amount}** ${s} from **${target.username}** without a crumb left behind.`, - `Abra taught you well β€” **${amount}** ${s} from **${target.username}** are now yours!`, - `Like a phantom in the night, you took **${amount}** ${s} from **${target.username}**.`, - `You just pulled the sweetest heist: **${amount}** ${s} from **${target.username}**!`, - `Mission complete. **${target.username}** is **${amount}** ${s} poorer, you are richer.`, - `You distracted **${target.username}** with a dance and swiped **${amount}** ${s}.`, - `Clean getaway! **${target.username}** won’t know about the missing **${amount}** ${s} until it’s too late.`, - `The Cookie Vault has been breached. **${amount}** ${s} taken from **${target.username}**.`, - `You emerged from the shadows with **${amount}** ${s} from **${target.username}**.` - ]; - }; - - const maxSteal = Math.max(1, Math.ceil(their / 4)); // steal up to ~25% of victim - let amount = Math.floor(Math.random() * maxSteal) + 1; - amount = Math.min(amount, their); - - // transfer - await Promise.all([ - changeCookies(user.id, amount, user.username), - changeCookies(target.id, -amount, target.username) - ]); - - const responses = stealSuccessResponses(amount, target); - const i = Math.floor(Math.random() * responses.length); - return interaction.reply({ content: responses[i] }); - - } else { - const stealFailResponses = (penalty, target) => { - const s = penalty === 1 ? 'Cookie' : 'Cookies'; - return [ - `You were caught red-handed by **${target.username}** and lost **${penalty}** ${s} as a penalty!`, - `Fail! **${target.username}** caught you mid-bite β€” you dropped **${penalty}** ${s}.`, - `Not your best moment... You lost **${penalty}** ${s} to **${target.username}** in the struggle.`, - `Stealth level: 0. You handed **${penalty}** ${s} to **${target.username}** as an apology.`, - `The cookie jar was booby-trapped! You gave **${penalty}** ${s} to **${target.username}** while running away.`, - `Ouch. The guard dog barked, and now **${target.username}** has your **${penalty}** ${s}.`, - `You tripped over your own shoelace β€” **${target.username}** reclaimed **${penalty}** ${s}.`, - `Caught by the Cookie Police! **${penalty}** ${s} confiscated and given to **${target.username}**.`, - `Your pockets had holes... **${target.username}** picked up **${penalty}** ${s} you dropped.` - ]; - }; - - - // failure penalty: attacker loses a little (1..ceil(your/6)) to the victim - const maxPenalty = Math.max(1, Math.ceil(your / 6)); - const penalty = Math.min(your, Math.floor(Math.random() * maxPenalty) + 1); - - await Promise.all([ - changeCookies(user.id, -penalty, user.username), - changeCookies(target.id, +penalty, target.username) - ]); - - const responses = stealFailResponses(penalty, target); - const i = Math.floor(Math.random() * responses.length); - return interaction.reply({ content: responses[i] }); - - } -} - -async function check(interaction, user) { - let target = interaction.options.getUser('target'); - if (!target) target = user; - - const cookies = await getCookies(target.id); - const mood = cookies === 0 ? 'πŸ˜”' : '😲'; - return interaction.reply({ content: `**${target.username}** has **${cookies}** Cookies! ${mood}` }); -} - -async function give(interaction, user) { - const target = interaction.options.getUser('target'); - const amount = interaction.options.getInteger('amount'); - - if (!target) return interaction.reply({ content: `You need to specify a target.`, ephemeral: true }); - if (target.id === user.id) return interaction.reply({ content: 'You cannot give yourself Cookies ._."', ephemeral: true }); - if (!Number.isInteger(amount) || amount < 1) { - return interaction.reply({ content: `**${user}** shared *checks notes* **${amount}** Cookie(s) with ${target}....wait a minute!!`, ephemeral: true }); - } - - const your = await getCookies(user.id); - if (your < amount) return interaction.reply({ content: `We don't run a charity here, get more Cookies!`, ephemeral: true }); - - await Promise.all([ - changeCookies(user.id, -amount, user.username), - changeCookies(target.id, +amount, target.username) - ]); - - // small delay to mimic previous behavior - await delay(200); - return interaction.reply({ content: `**${user}** shared **${amount}** Cookie(s) with ${target}` }); -} - -async function leader(interaction) { - const results = await cookieSchema.find().sort({ cookies: -1 }).limit(10); - let cookieSorted = ''; - results.forEach((r, i) => { - cookieSorted += `[${i + 1}] <@${r._id}> (${r.cookies})\n`; - }); - - const embed = new Discord.MessageEmbed() - .setColor(0x0099FF) - .setThumbnail(interaction.guild.iconURL()) - .setTimestamp() - .addFields({ name: `-Cookie Leaderboard-`, value: cookieSorted || 'No cookie data yet.' }); - - return interaction.reply({ embeds: [embed] }); -} - -module.exports = { - slash: true, - description: 'collect a cookie', - category: 'Misc', - options: [ - { name: "collect", description: "want some?", type: 1 }, - { name: "steal", description: "try your luck at a lala robbery!", type: 1, options: [{ name: "target", description: "someone", required: true, type: 6 }] }, - { name: "check", description: "check your cookie stash", type: 1, options: [{ name: "target", description: "someone", type: 6 }] }, - { name: "give", description: "share your cookies with someone", type: 1, options: [{ name: "target", description: "someone", required: true, type: 6 }, { name: "amount", description: "cookies", required: true, type: 4 }] }, - { name: "leader", description: "show Top 10 Cookie Clickers", type: 1 } - ], - callback: ({ interaction, user }) => { - const sub = interaction.options._subcommand; - switch (sub) { - case "collect": return collect(interaction, user); - case "steal": return steal(interaction, user); - case "check": return check(interaction, user); - case "give": return give(interaction, user); - case "leader": return leader(interaction); - default: return interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); - } - } -}; diff --git a/commands/cookies.js.save b/commands/cookies.js.save deleted file mode 100644 index 657c7eb..0000000 --- a/commands/cookies.js.save +++ /dev/null @@ -1,383 +0,0 @@ -const { MongoClient, ServerApiVersion } = require('mongodb'); -require('dotenv').config(); -const uri = process.env.URI -const cookieSchema = require("../schemas/cookieSchema") -const cooldownSchema = require("../schemas/cooldownSchema") -const delay = ms => new Promise(resolve => setTimeout(resolve, ms)) -const Discord = require('discord.js') - -const client = new MongoClient(uri, { - useNewUrlParser: true, - useUnifiedTopology: true, - serverApi: ServerApiVersion.v1 -}); -function msToTime(duration) { - var milliseconds = parseInt((duration % 1000) / 100), - seconds = Math.floor((duration / 1000) % 60), - minutes = Math.floor((duration / (1000 * 60)) % 60), - hours = Math.floor((duration / (1000 * 60 * 60)) % 24); - - hours = (hours < 10) ? "0" + hours : hours; - minutes = (minutes < 10) ? "0" + minutes : minutes; - seconds = (seconds < 10) ? "0" + seconds : seconds; - - return hours + ":" + minutes + ":" + seconds; -} -async function collect(interaction, user) { - client.connect(async (err, db) => { - var dbo = db.db('test') - let id = `${interaction.guildId}-${interaction.user.id}-${interaction.commandName}-${interaction.options._subcommand}` - dbo.collection('cooldowns').findOne({ - _id: id - }, async function (err, results) { - let now = Date.now() - let time = now + 3600000 // plus one hour in ms - if (results) { - if (results.cooldown > now) { - time = new Date(results.cooldown).toUTCString() - return interaction.reply({ - content: `The batch is still cooking, come back in **${msToTime(results.cooldown - now)}**`, - ephemeral: true - }) - } - } - addCooldown(interaction.user.id, interaction.guildId, interaction.commandName, interaction.options._subcommand, time) - - - var ftext = [ - "I ate the rest, sorry >.<", - "Blame Abra", - "Would you like some Milk with that?", - "Careful! They're still warm :3", - "Best Batch yet!", - "These, I bequeath unto thine own self upon this day. Thou must guard them safely.", - "" - ] - var i = Math.floor(Math.random() * ftext.length) - //funny text at the end - - var amount = Math.floor(Math.random() * 30) - //random amount between 1 and 29 - if (user.id == "378135175059603457") { - //Abra Bonus - amount *= 1.25 - } - - await cookieSchema.findOneAndUpdate({ - _id: user.id - }, { - _id: user.id, - user: user.username, - $inc: { cookies: +amount } - }, { - upsert: true - }) - - var response = `<@${user.id}>, πŸͺ you collected ${amou*nt} cookies!! πŸͺ ${ftext[i]}` - - interaction.reply({ - content: response - }) - }) - }) -} -function steal(interaction, user) { - client.connect(async (err, db) => { - if (err) throw err; - let target = interaction.options.getUser('target') - let dbo = db.db("test") - - if (target.id == user.id) { - return interaction.reply({ - content: `C'mon, don't embarass yourself! We all know you couldn't do that, even if you tried.`, - ephemeral: true, - }) - } - - // get your amount of cookies - let your = await dbo.collection('cookies').findOne({ - _id: user.id - }) - // get their amount of cookies - let their = await dbo.collection('cookies').findOne({ - _id: target.id - }) - try { - if (!your.cookies) { - return interaction.reply({ - content: `You need at least 1 Cookie to attempt a Robbery`, - ephemeral: true, - }) - } - if (!their.cookies) { - return interaction.reply({ - content: `Shame on you! They don't even have any Cookies D:`, - ephemeral: true, - }) - } - } catch (error) { - return interaction.reply({ - content: `How awkward...I don't know some of you!`, - ephemeral: true, - }) - } - let difficulty = [] - for (var i = 0; i < their.cookies; i++) { - if (i < your.cookies) { - difficulty.push(false) - } else { - difficulty.push(true) - } - } - let result = Math.floor(Math.random() * their.cookies) + 1 - let response - if (!difficulty[result]) { - // author lost - response = `You were unsuccessful at robbing **${target.username}** and lost **${result}** Cookie(s)! ` - if (your.cookies - result <= 0) { - result = your.cookies - response += `That's all your Cookies gone.` - } - result *= -1 - - } else { - //author won - response = `You've successfully stolen **${result}** Cookie(s) from **${target.username}**! ` - if (their.cookies - result <= 0) { - result = their.cookies - response += `They're completely dry now.` - } - } - interaction.reply({ - content: response - }) - - //update author's cookies - await cookieSchema.findOneAndUpdate({ - _id: user.id - }, { - _id: user.id, - user: user.username, - $inc: { cookies: +result } //will decrease if it's +negativeInteger - }, { - upsert: true - }) - - await cookieSchema.findOneAndUpdate({ - _id: target.id - }, { - _id: target.id, - user: target.username, - $inc: { cookies: -result } //will decrease if it's +negativeInteger - }, { - upsert: true - }) - }) - - - -} -function check(interaction, user) { - - client.connect(async function (err, db) { - let target = interaction.options.getUser('target') - - if (!target) { - target = user - } - let response = `**${target.username}** has ` - let dbo = db.db("test") - dbo.collection("cookies").findOne({ - _id: target.id - }, function (err, results) { - let cookies - if (!results) { - cookies = 0 - response += `**${cookies}** Cookies! πŸ˜”` - } else { - cookies = results.cookies - response += `**${cookies}** Cookies! 😲` - } - interaction.reply({ - content: response - }) - }) - }) -} -async function give(interaction, user) { - client.connect(async function (err, db) { - let target = interaction.options.getUser('target') - let amount = interaction.options.getInteger('amount') - let dbo = db.db('test') - - //check if you have enough cookies - let your = await dbo.collection('cookies').findOne({ - _id: user.id - }) - - if (target.id == user.id) { - return interaction.reply({ - content: 'You cannot give yourself Cookies ._."' - }) - } - if (your.cookies < amount) { - return interaction.reply({ - content: `We don't run a charity here, get more Cookies!` - }) - } - if (amount < 1) { - return interaction.reply({ - content: `**${user}** shared *checks notes* **${amount}** Cookie(s) with ${target}....wait a minute!!`, - }) - } - - //update user's cookies - await cookieSchema.findOneAndUpdate({ - _id: user.id - }, { - _id: user.id, - user: user.username, - $inc: { cookies: -amount } - }, { - upsert: true - }) - - //update target's cookies - await cookieSchema.findOneAndUpdate({ - _id: target.id - }, { - _id: target.id, - user: target.username, - $inc: { cookies: +amount } - }, { - upsert: true - }) - await delay(200) - interaction.reply({ - content: `**${user}** shared **${amount}** Cookie(s) with ${target}` - }) - - }) -} -async function addCooldown(userId, guildId, command, subcommand, ms) { - let id = `${guildId}-${userId}-${command}-${subcommand}` - await cooldownSchema.findOneAndUpdate({ - _id: id - }, { - _id: id, - command: command, - subcommand: subcommand, - cooldown: ms - }, { - upsert: true - }) -} -async function leader(interaction) { - const results = await cookieSchema.find().sort({ - cookies: -1 - }).limit(10) - let cookieSorted = '' - let i = 0 - results.forEach((result) => { - cookieSorted += `[${i + 1}] <@${result._id}> (${result.cookies})\n` - i++; - }) - - var embed = new Discord.MessageEmbed() - .setColor(0x0099FF) - .setThumbnail(interaction.guild.iconURL()) - .setTimestamp() - .addFields({ name: `-Cookie Leaderboard-`, value: cookieSorted }) - - interaction.reply({ - embeds: [embed] - }) -} -module.exports = { - slash: true, - description: 'collect a cookie', - category: 'Misc', - options: [ - //collect - { - name: "collect", - description: "want some?", - type: 1 // SubCommand Type - }, - //steal - { - name: "steal", - description: "try your luck at a lala robbery!", - type: 1, // SubCommand Type - options: [ - { - name: "target", - description: "someone", - required: true, - type: 6 // User Type - } - ] - }, - //check - { - name: "check", - description: "check your cookie stash", - required: false, - type: 1, // SubCommand Type - options: [ - { - name: "target", - description: "someone", - type: 6 // User Type - } - ] - }, - //give - { - name: "give", - description: "share your cookies with someone", - required: false, - type: 1, // SubCommand Type - options: [ - { - name: "target", - description: "someone", - required: true, - type: 6 // User Type - }, { - name: "amount", - description: "cookies", - required: true, - type: 4 // Integer Type - } - ] - }, - //leader - { - name: "leader", - description: "show Top 10 Cookie Clickers", - type: 1, // SubCommand Type - }, - ], - callback: ({ interaction, user }) => { - switch (interaction.options._subcommand) { - case "collect": - collect(interaction, user) - break; - case "steal": - steal(interaction, user) - break; - case "check": - check(interaction, user) - break; - case "give": - give(interaction, user) - break; - case "leader": - leader(interaction) - break; - default: - break; - } - } -} diff --git a/commands/dontclickthis.js b/commands/dontclickthis.js deleted file mode 100644 index 423085b..0000000 --- a/commands/dontclickthis.js +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = { - slash: true, - description: 'surprise!', - category: 'meme', - options: [ - { - name: 'pwned', - description: "Told you not to click on this", - required: true, - type: 3, - choices: [ - { "name": 'never', "value": "never" }, - { "name": 'gonna', "value": "gonna" }, - { "name": 'give', "value": "give" }, - { "name": 'you', "value": "you" }, - { "name": 'up', "value": "up" }, - { "name": 'never', "value": "never" }, - { "name": 'gonna', "value": "gonna" }, - { "name": 'let', "value": "let" }, - { "name": 'you', "value": "you" }, - { "name": 'down', "value": "down" }, - ], - }, - ], - callback: async ({ interaction }) => { - interaction.reply({ - content: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", - ephemeral: true, - }) - } -} \ No newline at end of file diff --git a/commands/random.js b/commands/random.js deleted file mode 100644 index 719f713..0000000 --- a/commands/random.js +++ /dev/null @@ -1,209 +0,0 @@ -const { MongoClient, ServerApiVersion } = require('mongodb'); -require('dotenv').config(); -const uri = process.env.URI -const delay = ms => new Promise(resolve => setTimeout(resolve, ms)) -const client = new MongoClient(uri, { - useNewUrlParser: true, - useUnifiedTopology: true, - serverApi: ServerApiVersion.v1 -}); -const expansions = new Map([ - ["ARR", { "min": 0, "max": 50 }], - ["HW", { "min": 51, "max": 60 }], - ["SB", { "min": 61, "max": 70 }], - ["ShB", { "min": 71, "max": 80 }], - ["EW", { "min": 81, "max": 90 }], - -]) - -async function getDutyData(interaction, database, user) { - var parameters = { - "type": interaction.options.getString('type'), - "min": interaction.options.getInteger('minlevel'), - "max": interaction.options.getInteger('maxlevel'), - "expansion": interaction.options.getString('expansion') - } - if (!parameters.type) { - //no type specified, randomizing... - database.listCollections().toArray(function (err, results) { - if (err) throw err; - let random = Math.floor(Math.random() * results.length) - parameters.type = results[random].name - }) - } - - if (parameters.expansion) { - //check if paramters are set correctly - if (!parameters.min) { - parameters.min = expansions.get(parameters.expansion).min - } - if (parameters.min < expansions.get(parameters.expansion).min) { - return console.log("mismatch min level and expansion") - } - - if (!parameters.max) { - parameters.max = expansions.get(parameters.expansion).max - } - if (parameters.max > expansions.get(parameters.expansion).max) { - return console.log("mismatch max level and expansion") - } - } else { - if (!parameters.min) { parameters.min = 0 } - if (!parameters.max) { parameters.max = 90 } - } - - if (parameters.type == 'pvp') { - parameters.expansion = 'ARR' - parameters.min = expansions.get(parameters.expansion).min - parameters.max = expansions.get(parameters.expansion).max - } - - await delay(500) //wait for updates - database.collection(parameters.type).find({ - level: { '$gte': parameters.min, '$lte': parameters.max } - }).toArray(async function (err, results2) { - let random = Math.floor(Math.random() * results2.length) - try { - let duty = results2[random] - let reply = `<@${user.id}>, Thou shalt playeth...${duty.name} [Level: ${duty.level}, Type: ${parameters.type}` - if (duty.expansion) { - reply += `, Expansion: ${duty.expansion}]` - } else { - reply += ']' - } - - interaction.reply({ - content: reply - }) - } catch (error) { - interaction.reply({ - content: `WAA!! (Impossible Combination found)` - }) - } - }) -} -async function getClassData(interaction, database, user) { - var collection = interaction.options.getString('type') - if (!collection) { - //no type specified - database.listCollections().toArray(function (err, cResults) { - let rdm = Math.floor(Math.random() * cResults.length) - collection = cResults[rdm].name - }) - } - - await delay(200) //wait for database.listCollections() - - database.collection(collection).find({}).toArray(async function (err, results) { - if (err) throw err; - var response - try { - let rdm = Math.floor(Math.random() * results.length) - response = `<@${user.id}>, Thou shalt playeth...${results[rdm].job}` - } catch (error) { - response = 'Invalid Type specified!' - } - interaction.reply({ - content: response, - }) - }) -} -module.exports = { - category: 'Random', - description: 'randomized helper', // Required for slash commands - slash: true, // Create both a slash and legacy command - options: [ - { - name: "duty", - type: 1, - description: "random duty", - options: [ - { - name: 'type', - description: 'what kind of duty would you like?', - required: false, - type: 3, - choices: [ - { "name": 'Dungeons', "value": "dungeons" }, - { "name": 'Guildhests', "value": "guildhests" }, - { "name": 'PvP', "value": "pvp" }, - { "name": 'Normal Raids', "value": "nraids" }, - { "name": 'Alliance Raids', "value": "araids" }, - { "name": 'Trials', "value": "trials" }, - { "name": 'Extreme', "value": "extreme" }, - { "name": 'Savage', "value": "savage" }, - { "name": 'Ultimates', "value": "ultimates" }, - { "name": 'Roulettes', "value": "roulettes" }, - ], - }, - { - name: 'minlevel', - description: 'Start of Level Range, assuming 0 if not specified', - required: false, - type: 4, - }, - { - name: 'maxlevel', - description: 'End of Level Range, assuming 90 if not specified', - required: false, - type: 4, - }, - { - name: 'expansion', - description: 'which expansion would you like?', - required: false, - type: 3, - choices: [ - { "name": 'A Realm Reborn', "value": "ARR" }, - { "name": 'Heavensward', "value": "HW" }, - { "name": 'Stormblood', "value": "SB" }, - { "name": 'Shadowbringers', "value": "ShB" }, - { "name": 'Endwalker', "value": "EW" }, - ], - } - ], - }, - { - name: "class", - type: 1, - description: "random class", - options: [ - { - name: 'type', - description: 'specify class', - required: false, - type: 3, - choices: [ - { "name": 'Healer', "value": "healer" }, - { "name": 'Tank', "value": "tank" }, - { "name": 'Melee', "value": "melee" }, - { "name": 'Ranged', "value": "ranged" }, - { "name": 'Caster', "value": "caster" }, - ], - } - ] - } - - ], - callback: ({ interaction, user }) => { - switch (interaction.options._subcommand) { - case "duty": - client.connect(function (err, db) { - if (err) throw err; - - var dbDuties = db.db("Duties") - getDutyData(interaction, dbDuties, user) - }) - break; - case "class": - client.connect(async function (err, db) { - if (err) throw err; - - var dbClasses = db.db("Classes") - getClassData(interaction, dbClasses, user) - }) - default: - break; - } - }, -} \ No newline at end of file diff --git a/commands/sus.js b/commands/sus.js deleted file mode 100644 index 426138b..0000000 --- a/commands/sus.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - slash: true, - description: 'sussy baka', - category: 'meme', - callback: async ({ interaction }) => { - interaction.reply({ - content: "࢞" - }) - } -} diff --git a/commands/template.txt b/commands/template.txt deleted file mode 100644 index 7eed431..0000000 --- a/commands/template.txt +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = { - slash: true, - description: '', - category: '', - options: [ - { - name: 'victim', - description: 'pick anyone >:D', - required: true, - type: 9, - options: [ - { - name: 'type', - description: 'what kind of duty would you like?', - required: false, - type: 3, //String - choices: [ - { "name": 'choice', "value": "value" }, - ], - autocomplete: true - }, - ], - - }, - ], - callback: async ({ interaction }) => { - - } -} \ No newline at end of file diff --git a/commands/waa.js b/commands/waa.js deleted file mode 100644 index a24085e..0000000 --- a/commands/waa.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = { - slash: true, - description: 'waa! at someone', - category: 'Misc', - cooldown: '3h', - options: [ - { - name: 'victim', - description: 'pick anyone >:D', - required: true, - type: 9, - }, - ], - callback: async ({ interaction, args, client }) => { - var reply = 'waa!' - - const member = client.users.cache.get(args[0]); - if(args[0]){ - reply+= ` <@${member.id}>` - } - interaction.reply({ - content: reply, - tts: true - }) - } -} \ No newline at end of file diff --git a/duties/araids.json b/duties/araids.json deleted file mode 100644 index 50dc84f..0000000 --- a/duties/araids.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - {"name": "The Labyrinth of the Ancients", "level": 50, "expansion": "ARR"}, - {"name": "Syrcus Tower", "level": 50, "expansion": "ARR"}, - {"name": "The World of Darkness", "level": 50, "expansion": "ARR"}, - {"name": "The Void Ark", "level": 60, "expansion": "HW"}, - {"name": "The Weeping City of Mhach", "level": 60, "expansion": "HW"}, - {"name": "Dun Scaith", "level": 60, "expansion": "HW"}, - {"name": "The Royal City of Rabanastre", "level": 70, "expansion": "SB"}, - {"name": "The Ridorana Lighthouse", "level": 70, "expansion": "SB"}, - {"name": "The Orbonne Monastery", "level": 70, "expansion": "SB"}, - {"name": "The Copied Factory", "level": 80, "expansion": "ShB"}, - {"name": "The Puppets' Bunker", "level": 80, "expansion": "ShB"}, - {"name": "The Tower at Paradigm's Breach", "level": 80, "expansion": "ShB"}, - {"name": "Aglaia", "level": 90, "expansion": "EW"} -] \ No newline at end of file diff --git a/duties/dungeons.json b/duties/dungeons.json deleted file mode 100644 index 376fddc..0000000 --- a/duties/dungeons.json +++ /dev/null @@ -1,88 +0,0 @@ -[ - {"name": "Sastasha", "level": 15, "expansion": "ARR"}, - {"name": "The Tam-Tara Deepcroft", "level": 16, "expansion": "ARR"}, - {"name": "Copperbell Mines", "level": 17, "expansion": "ARR"}, - {"name": "Halatali", "level": 20, "expansion": "ARR"}, - {"name": "The Thousand Maws of Toto-Rak", "level": 24, "expansion": "ARR"}, - {"name": "Haukke Manor", "level": 28, "expansion": "ARR"}, - {"name": "Brayflox's Longstop", "level": 32, "expansion": "ARR"}, - {"name": "The Sunken Temple of Quarn", "level": 35, "expansion": "ARR"}, - {"name": "Cutter's Cry", "level": 41, "expansion": "ARR"}, - {"name": "The Stone Vigil", "level": 44, "expansion": "ARR"}, - {"name": "Dzemael Darkhold", "level": 47, "expansion": "ARR"}, - {"name": "The Aurum Vale", "level": 50, "expansion": "ARR"}, - {"name": "The Wanderer's Palace", "level": 50, "expansion": "ARR"}, - {"name": "Castrum Meridianum", "level": 50, "expansion": "ARR"}, - {"name": "The Praetorium", "level": 50, "expansion": "ARR"}, - {"name": "Amdapor Keep", "level": 50, "expansion": "ARR"}, - {"name": "Pharos Sirius", "level": 50, "expansion": "ARR"}, - {"name": "Copperbell Mines (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "Haukke Manor (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Lost City of Amdapor", "level": 50, "expansion": "ARR"}, - {"name": "Halatali (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "Brayflox's Longstop (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "Hullbreaker Isle", "level": 50, "expansion": "ARR"}, - {"name": "The Tam-Tara Deepcroft (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Stone Vigil (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "Snowcloak", "level": 50, "expansion": "ARR"}, - {"name": "Sastasha (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Sunken Temple of Quarn (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Keeper of the Lake", "level": 50, "expansion": "ARR"}, - {"name": "The Wanderer's Palace (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "Amdapor Keep (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Dusk Vigil", "level": 51, "expansion": "HW"}, - {"name": "Sohm Al", "level": 53, "expansion": "HW"}, - {"name": "The Aery", "level": 55, "expansion": "HW"}, - {"name": "The Vault", "level": 57, "expansion": "HW"}, - {"name": "The Great Gubal Library", "level": 59, "expansion": "HW"}, - {"name": "The Aetherochemical Research Facility", "level": 60, "expansion": "HW"}, - {"name": "Neverreap", "level": 60, "expansion": "HW"}, - {"name": "The Fractal Continuum", "level": 60, "expansion": "HW"}, - {"name": "Saint Mocianne's Arboretum", "level": 60, "expansion": "HW"}, - {"name": "Pharos Sirius (Hard)", "level": 60, "expansion": "HW"}, - {"name": "The Antitower", "level": 60, "expansion": "HW"}, - {"name": "The Lost City of Amdapor (Hard)", "level": 60, "expansion": "HW"}, - {"name": "Sohr Khai", "level": 60, "expansion": "HW"}, - {"name": "Hullbreaker Isle (Hard)", "level": 60, "expansion": "HW"}, - {"name": "Xelphatol", "level": 60, "expansion": "HW"}, - {"name": "The Great Gubal Library (Hard)", "level": 60, "expansion": "HW"}, - {"name": "Baelsar's Wall", "level": 60, "expansion": "HW"}, - {"name": "Sohm Al (Hard)", "level": 60, "expansion": "HW"}, - {"name": "The Sirensong Sea", "level": 61, "expansion": "SB"}, - {"name": "Shisui of the Violet Tides", "level": 63, "expansion": "SB"}, - {"name": "Bardam's Mettle", "level": 65, "expansion": "SB"}, - {"name": "Doma Castle", "level": 67, "expansion": "SB"}, - {"name": "Castrum Abania", "level": 69, "expansion": "SB"}, - {"name": "Ala Mhigo", "level": 70, "expansion": "SB"}, - {"name": "Kugane Castle", "level": 70, "expansion": "SB"}, - {"name": "The Temple of the Fist", "level": 70, "expansion": "SB"}, - {"name": "The Drowned City of Skalla", "level": 70, "expansion": "SB"}, - {"name": "Hell's Lid", "level": 70, "expansion": "SB"}, - {"name": "The Fractal Continuum (Hard)", "level": 70, "expansion": "SB"}, - {"name": "The Swallow's Compass", "level": 70, "expansion": "SB"}, - {"name": "The Burn", "level": 70, "expansion": "SB"}, - {"name": "Saint Mocianne's Arboretum (Hard)", "level": 70, "expansion": "SB"}, - {"name": "The Ghimlyt Dark", "level": 70, "expansion": "SB"}, - {"name": "Holminster", "level": 71, "expansion": "ShB"}, - {"name": "Dohn Mheg", "level": 73, "expansion": "ShB"}, - {"name": "The Qitana Ravel", "level": 75, "expansion": "ShB"}, - {"name": "Malikah's Well", "level": 77, "expansion": "ShB"}, - {"name": "Mt. Gulg", "level": 79, "expansion": "ShB"}, - {"name": "Amaurot", "level": 80, "expansion": "ShB"}, - {"name": "The Twinning", "level": 80, "expansion": "ShB"}, - {"name": "Akadaemia Anyder", "level": 80, "expansion": "ShB"}, - {"name": "The Grand Cosmos", "level": 80, "expansion": "ShB"}, - {"name": "The Heroes' Gauntlet", "level": 80, "expansion": "ShB"}, - {"name": "Matoya's Relict", "level": 80, "expansion": "ShB"}, - {"name": "Paglth'an", "level": 80, "expansion": "ShB"}, - {"name": "The Tower of Zot", "level": 81, "expansion": "EW"}, - {"name": "The Tower of Babel", "level": 83, "expansion": "EW"}, - {"name": "Vanaspati", "level": 85, "expansion": "EW"}, - {"name": "Ktisis Hyperboreia", "level": 87, "expansion": "EW"}, - {"name": "The Aitiascope", "level": 89, "expansion": "EW"}, - {"name": "The Dead Ends", "level": 90, "expansion": "EW"}, - {"name": "Smileton", "level": 90, "expansion": "EW"}, - {"name": "The Stigma Dreamscape", "level": 90, "expansion": "EW"}, - {"name": "Alzadaal's Legacy", "level": 90, "expansion": "EW"}, - {"name": "The Fell Court of Troia", "level": 90, "expansion": "EW"} -] \ No newline at end of file diff --git a/duties/extreme.json b/duties/extreme.json deleted file mode 100644 index 37844b7..0000000 --- a/duties/extreme.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - {"name": "The Howling Eye (Extreme)", "level": 50, "expansion": "ARR"}, - {"name": "The Navel (Extreme)", "level": 50, "expansion": "ARR"}, - {"name": "The Bowl of Embers (Extreme)", "level": 50, "expansion": "ARR"}, - {"name": "Thornmarch (Extreme)", "level": 50, "expansion": "ARR"}, - {"name": "The Whorleater (Extreme)", "level": 50, "expansion": "ARR"}, - {"name": "The Striking Tree (Extreme)", "level": 50, "expansion": "ARR"}, - {"name": "The Akh Afah Amphitheatre (Extreme)", "level": 50, "expansion": "ARR"}, - {"name": "The Limitless Blue (Extreme)", "level": 60, "expansion": "HW"}, - {"name": "Thok ast Thok (Extreme)", "level": 60, "expansion": "HW"}, - {"name": "The Minstrel's Ballad: Thordan's Reign", "level": 60, "expansion": "HW"}, - {"name": "The Minstrel's Ballad: Nidhogg's Rage", "level": 60, "expansion": "HW"}, - {"name": "Containment Bay S1T7 (Extreme)", "level": 60, "expansion": "HW"}, - {"name": "Containment Bay P1T6 (Extreme)", "level": 60, "expansion": "HW"}, - {"name": "Containment Bay Z1T9 (Extreme)", "level": 60, "expansion": "HW"}, - {"name": "The Pool of Tribute (Extreme)", "level": 70, "expansion": "SB"}, - {"name": "Emanation (Extreme)", "level": 70, "expansion": "SB"}, - {"name": "The Minstrel's Ballad: Shinryu's Domain", "level": 70, "expansion": "SB"}, - {"name": "The Minstrel's Ballad: Tsukuyomi's Pain", "level": 70, "expansion": "SB"}, - {"name": "The Great Hunt (Extreme)", "level": 70, "expansion": "SB"}, - {"name": "The Jade Stoa (Extreme)", "level": 70, "expansion": "SB"}, - {"name": "Hells' Kier (Extreme)", "level": 70, "expansion": "SB"}, - {"name": "The Wreath of Snakes (Extreme)", "level": 70, "expansion": "SB"}, - {"name": "The Dancing Plague (Extreme)", "level": 80, "expansion": "ShB"}, - {"name": "The Crown of the Immaculate (Extreme)", "level": 80, "expansion": "ShB"}, - {"name": "The Minstrel's Ballad: Hades's Elegy", "level": 80, "expansion": "ShB"}, - {"name": "Cinder Drift (Extreme)", "level": 80, "expansion": "ShB"}, - {"name": "Memoria Misera (Extreme)", "level": 80, "expansion": "ShB"}, - {"name": "The Seat of Sacrifice (Extreme)", "level": 80, "expansion": "ShB"}, - {"name": "Castrum Marinum (Extreme)", "level": 80, "expansion": "ShB"}, - {"name": "The Cloud Deck (Extreme)", "level": 80, "expansion": "ShB"}, - {"name": "The Minstrel's Ballad: Zodiark's Fall", "level": 90, "expansion": "EW"}, - {"name": "The Minstrel's Ballad: Hydaelyn's Call", "level": 90, "expansion": "EW"}, - {"name": "The Minstrel's Ballad: Endsinger's Aria", "level": 90, "expansion": "EW"}, - {"name": "Containment Bay S1T7 (Unreal)", "level": 90, "expansion": "EW"}, - {"name": "Storm's Crown (Extreme)", "level": 90, "expansion": "EW"} -] \ No newline at end of file diff --git a/duties/guildhests.json b/duties/guildhests.json deleted file mode 100644 index db473e8..0000000 --- a/duties/guildhests.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - {"name": "Basic Training: Enemy Parties", "level": 10, "expansion": "ARR"}, - {"name": "Under the Armor", "level": 10, "expansion": "ARR"}, - {"name": "Basic Training: Enemy Strongholds", "level": 15, "expansion": "ARR"}, - {"name": "Hero on the Half Shell", "level": 15, "expansion": "ARR"}, - {"name": "Pulling Poison Posies", "level": 20, "expansion": "ARR"}, - {"name": "Stinging Back", "level": 20, "expansion": "ARR"}, - {"name": "All's Well that Ends in the Well", "level": 25, "expansion": "ARR"}, - {"name": "Flicking Sticks and Taking Names", "level": 25, "expansion": "ARR"}, - {"name": "More than a Feeler", "level": 30, "expansion": "ARR"}, - {"name": "Annoy the Void", "level": 30, "expansion": "ARR"}, - {"name": "Shadow and Claw", "level": 35, "expansion": "ARR"}, - {"name": "Long Live the Queen", "level": 35, "expansion": "ARR"}, - {"name": "Ward Up", "level": 40, "expansion": "ARR"}, - {"name": "Solemn Trinity", "level": 40, "expansion": "ARR"} -] \ No newline at end of file diff --git a/duties/nraids.json b/duties/nraids.json deleted file mode 100644 index 98cdd3d..0000000 --- a/duties/nraids.json +++ /dev/null @@ -1,59 +0,0 @@ -[ - {"name": "The Binding Coil of Bahamut - Turn 1", "level": 50, "expansion": "ARR"}, - {"name": "The Binding Coil of Bahamut - Turn 2", "level": 50, "expansion": "ARR"}, - {"name": "The Binding Coil of Bahamut - Turn 3", "level": 50, "expansion": "ARR"}, - {"name": "The Binding Coil of Bahamut - Turn 4", "level": 50, "expansion": "ARR"}, - {"name": "The Binding Coil of Bahamut - Turn 5", "level": 50, "expansion": "ARR"}, - {"name": "The Second Coil of Bahamut - Turn 1", "level": 50, "expansion": "ARR"}, - {"name": "The Second Coil of Bahamut - Turn 2", "level": 50, "expansion": "ARR"}, - {"name": "The Second Coil of Bahamut - Turn 3", "level": 50, "expansion": "ARR"}, - {"name": "The Second Coil of Bahamut - Turn 4", "level": 50, "expansion": "ARR"}, - {"name": "The Final Coil of Bahamut - Turn 1", "level": 50, "expansion": "ARR"}, - {"name": "The Final Coil of Bahamut - Turn 2", "level": 50, "expansion": "ARR"}, - {"name": "The Final Coil of Bahamut - Turn 3", "level": 50, "expansion": "ARR"}, - {"name": "The Final Coil of Bahamut - Turn 4", "level": 50, "expansion": "ARR"}, - {"name": "Alexander - The Fist of the Father", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Cuff of the Father", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Arm of the Father", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Burden of the Father", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Fist of the Son", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Cuff of the Son", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Arm of the Son", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Burden of the Son", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Eyes of the Creator", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Breath of the Creator", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Heart of the Creator", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Soul of the Creator", "level": 60, "expansion": "HW"}, - {"name": "Deltascape V1.0", "level": 70, "expansion": "SB"}, - {"name": "Deltascape V2.0", "level": 70, "expansion": "SB"}, - {"name": "Deltascape V3.0", "level": 70, "expansion": "SB"}, - {"name": "Deltascape V4.0", "level": 70, "expansion": "SB"}, - {"name": "Sigmascape V1.0", "level": 70, "expansion": "SB"}, - {"name": "Sigmascape V2.0", "level": 70, "expansion": "SB"}, - {"name": "Sigmascape V3.0", "level": 70, "expansion": "SB"}, - {"name": "Sigmascape V4.0", "level": 70, "expansion": "SB"}, - {"name": "Alphascape V1.0", "level": 70, "expansion": "SB"}, - {"name": "Alphascape V2.0", "level": 70, "expansion": "SB"}, - {"name": "Alphascape V3.0", "level": 70, "expansion": "SB"}, - {"name": "Alphascape V4.0", "level": 70, "expansion": "SB"}, - {"name": "Eden's Gate: Resurrection", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Gate: Descent", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Gate: Inundation", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Gate: Sepulture", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Verse: Fulmination", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Verse: Furor", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Verse: Iconoclasm", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Verse: Refulgence", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Promise: Umbra", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Promise: Litany", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Promise: Anamorphosis", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Promise: Eternity", "level": 80, "expansion": "ShB"}, - {"name": "Asphodelos: The First Circle", "level": 90, "expansion": "EW"}, - {"name": "Asphodelos: The Second Circle", "level": 90, "expansion": "EW"}, - {"name": "Asphodelos: The Third Circle", "level": 90, "expansion": "EW"}, - {"name": "Asphodelos: The Fourth Circle", "level": 90, "expansion": "EW"}, - {"name": "Abyssos: The Fifth Circle", "level": 90, "expansion": "EW"}, - {"name": "Abyssos: The Sixth Circle", "level": 90, "expansion": "EW"}, - {"name": "Abyssos: The Seventh Circle", "level": 90, "expansion": "EW"}, - {"name": "Abyssos: The Eighth Circle", "level": 90, "expansion": "EW"} -] \ No newline at end of file diff --git a/duties/pvp.json b/duties/pvp.json deleted file mode 100644 index d104a7f..0000000 --- a/duties/pvp.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - {"name": "Crystalline Conflict (Casual Match)", "level": 30, "expansion": "ARR"}, - {"name": "Crystalline Conflict (Ranked Match)", "level": 30, "expansion": "ARR"}, - {"name": "Crystalline Conflict (Custom Match - The Palaistra)", "level": 30, "expansion": "ARR"}, - {"name": "Crystalline Conflict (Custom Match - The Volcanic Heart)", "level": 30, "expansion": "ARR"}, - {"name": "Crystalline Conflict (Custom Match - Cloud Nine)", "level": 30, "expansion": "ARR"}, - {"name": "The Borderland Ruins (Secure)", "level": 30, "expansion": "ARR"}, - {"name": "Seal Rock (Seize)", "level": 30, "expansion": "ARR"}, - {"name": "The Fields of Glory (Shatter)", "level": 30, "expansion": "ARR"}, - {"name": "Onsal Hakair (Danshig Naadam)", "level": 30, "expansion": "ARR"}, - {"name": "Astragalos", "level": 30, "expansion": "ARR"}, - {"name": "Hidden Gorge", "level": 30, "expansion": "ARR"} -] \ No newline at end of file diff --git a/duties/roulettes.json b/duties/roulettes.json deleted file mode 100644 index 5572804..0000000 --- a/duties/roulettes.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - {"name": "Expert", "level": 90}, - {"name": "Level 90 Dungeons", "level": 90}, - {"name": "Level 50/60/70/80", "level": 50}, - {"name": "Leveling", "level": 16}, - {"name": "Trials", "level": 50}, - {"name": "Main Scenario", "level": 50}, - {"name": "Guildhests", "level": 10}, - {"name": "Alliance Raid", "level": 50}, - {"name": "Normal Raid", "level": 60}, - {"name": "Mentor", "level": 90}, - {"name": "Frontline", "level": 30} -] \ No newline at end of file diff --git a/duties/savage.json b/duties/savage.json deleted file mode 100644 index cd19e54..0000000 --- a/duties/savage.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - {"name": "The Second Coil of Bahamut (Savage) - Turn 1", "level": 50, "expansion": "ARR"}, - {"name": "The Second Coil of Bahamut (Savage) - Turn 2", "level": 50, "expansion": "ARR"}, - {"name": "The Second Coil of Bahamut (Savage) - Turn 3", "level": 50, "expansion": "ARR"}, - {"name": "The Second Coil of Bahamut (Savage) - Turn 4", "level": 50, "expansion": "ARR"}, - {"name": "Alexander - The Fist of the Father (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Cuff of the Father (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Arm of the Father (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Burden of the Father (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Fist of the Son (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Cuff of the Son (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Arm of the Son (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Burden of the Son (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Eyes of the Creator (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Breath of the Creator (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Heart of the Creator (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Alexander - The Soul of the Creator (Savage)", "level": 60, "expansion": "HW"}, - {"name": "Deltascape V1.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Deltascape V2.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Deltascape V3.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Deltascape V4.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Sigmascape V1.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Sigmascape V2.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Sigmascape V3.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Sigmascape V4.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Alphascape V1.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Alphascape V2.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Alphascape V3.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Alphascape V4.0 (Savage)", "level": 70, "expansion": "SB"}, - {"name": "Eden's Gate: Resurrection (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Gate: Descent (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Gate: Inundation (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Gate: Sepulture (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Verse: Fulmination (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Verse: Furor (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Verse: Iconoclasm (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Verse: Refulgence (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Promise: Umbra (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Promise: Litany (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Promise: Anamorphosis (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Eden's Promise: Eternity (Savage)", "level": 80, "expansion": "ShB"}, - {"name": "Asphodelos: The First Circle (Savage)", "level": 90, "expansion": "EW"}, - {"name": "Asphodelos: The Second Circle (Savage)", "level": 90, "expansion": "EW"}, - {"name": "Asphodelos: The Third Circle (Savage)", "level": 90, "expansion": "EW"}, - {"name": "Asphodelos: The Fourth Circle (Savage)", "level": 90, "expansion": "EW"}, - {"name": "Abyssos: The Fifth Circle (Savage)", "level": 90, "expansion": "EW"}, - {"name": "Abyssos: The Sixth Circle (Savage)", "level": 90, "expansion": "EW"}, - {"name": "Abyssos: The Seventh Circle (Savage)", "level": 90, "expansion": "EW"}, - {"name": "Abyssos: The Eighth Circle (Savage)", "level": 90, "expansion": "EW"} -] \ No newline at end of file diff --git a/duties/trials.json b/duties/trials.json deleted file mode 100644 index 8c7964b..0000000 --- a/duties/trials.json +++ /dev/null @@ -1,48 +0,0 @@ -[ - {"name": "The Bowl of Embers", "level": 20, "expansion": "ARR"}, - {"name": "The Navel", "level": 34, "expansion": "ARR"}, - {"name": "The Howling Eye", "level": 44, "expansion": "ARR"}, - {"name": "The Porta Decumana", "level": 50, "expansion": "ARR"}, - {"name": "The Chrysalis", "level": 50, "expansion": "ARR"}, - {"name": "A Relic Reborn: the Chimera", "level": 50, "expansion": "ARR"}, - {"name": "A Relic Reborn: the Hydra", "level": 50, "expansion": "ARR"}, - {"name": "Battle on the Big Bridge", "level": 50, "expansion": "ARR"}, - {"name": "The Dragon's Neck", "level": 50, "expansion": "ARR"}, - {"name": "Battle in the Big Keep", "level": 50, "expansion": "ARR"}, - {"name": "The Bowl of Embers (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Howling Eye (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Navel (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "Thornmarch (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Whorleater (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Striking Tree (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "The Akh Afah Amphitheatre (Hard)", "level": 50, "expansion": "ARR"}, - {"name": "Urth's Fount", "level": 50, "expansion": "ARR"}, - {"name": "The Minstrel's Ballad: Ultima's Bane", "level": 50, "expansion": "ARR"}, - {"name": "Thok ast Thok (Hard)", "level": 53, "expansion": "HW"}, - {"name": "The Limitless Blue (Hard)", "level": 57, "expansion": "HW"}, - {"name": "The Singularity Reactor", "level": 60, "expansion": "HW"}, - {"name": "The Final Steps of Faith", "level": 60, "expansion": "HW"}, - {"name": "Containment Bay S1T7", "level": 60, "expansion": "HW"}, - {"name": "Containment Bay P1T6", "level": 60, "expansion": "HW"}, - {"name": "Containment Bay Z1T9", "level": 60, "expansion": "HW"}, - {"name": "The Pool of Tribute", "level": 63, "expansion": "SB"}, - {"name": "Emanation", "level": 67, "expansion": "SB"}, - {"name": "The Royal Menagerie", "level": 70, "expansion": "SB"}, - {"name": "Castrum Fluminis", "level": 70, "expansion": "SB"}, - {"name": "Kugane Ohashi", "level": 70, "expansion": "SB"}, - {"name": "The Great Hunt", "level": 70, "expansion": "SB"}, - {"name": "The Jade Stoa", "level": 70, "expansion": "SB"}, - {"name": "Hells' Kier", "level": 70, "expansion": "SB"}, - {"name": "The Wreath of Snakes", "level": 70, "expansion": "SB"}, - {"name": "The Dancing Plague", "level": 73, "expansion": "ShB"}, - {"name": "The Crown of the Immaculate", "level": 79, "expansion": "ShB"}, - {"name": "The Dying Gasp", "level": 80, "expansion": "ShB"}, - {"name": "Cinder Drift", "level": 80, "expansion": "ShB"}, - {"name": "The Seat of Sacrifice", "level": 80, "expansion": "ShB"}, - {"name": "Castrum Marinum", "level": 80, "expansion": "ShB"}, - {"name": "The Cloud Deck", "level": 80, "expansion": "ShB"}, - {"name": "The Dark Inside", "level": 83, "expansion": "EW"}, - {"name": "The Mothercrystal", "level": 89, "expansion": "EW"}, - {"name": "The Final Day", "level": 90, "expansion": "EW"}, - {"name": "Storm's Crown", "level": 90, "expansion": "EW"} -] \ No newline at end of file diff --git a/duties/ultimates.json b/duties/ultimates.json deleted file mode 100644 index 82c1ff7..0000000 --- a/duties/ultimates.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - {"name": "The Unending Coil of Bahamut (Ultimate)", "level": 70, "expansion": "SB"}, - {"name": "The Weapon's Refrain (Ultimate)", "level": 70, "expansion": "SB"}, - {"name": "The Epic of Alexander (Ultimate)", "level": 80, "expansion": "ShB"}, - {"name": "Dragonsong's Reprise (Ultimate)", "level": 90, "expansion": "EW"} -] \ No newline at end of file diff --git a/events/ClientReady.js b/events/ClientReady.js new file mode 100644 index 0000000..48db6d3 --- /dev/null +++ b/events/ClientReady.js @@ -0,0 +1,20 @@ +const { Events, ActivityType } = require('discord.js'); +const { mClient } = require('..'); + +module.exports = { + name: Events.ClientReady, + once: true, + async execute(client) { + console.log(`Ready! Logged in as ${client.user.tag}`); + + // Set presence + client.user.setPresence({ + activities: [{ + name: 'Surely this time, right...?', + type: ActivityType.Streaming, + url: 'https://twitch.tv/desq_blocki' + }], + status: 'online' + }); + } +}; \ No newline at end of file diff --git a/events/InteractionCreate.js b/events/InteractionCreate.js new file mode 100644 index 0000000..45f4052 --- /dev/null +++ b/events/InteractionCreate.js @@ -0,0 +1,98 @@ +const { Events, MessageFlags, Message } = require('discord.js') +const { mClient } = require('../index') +require('dotenv').config() + +module.exports = { + name: Events.InteractionCreate, + once: false, + async execute(interaction) { + if (interaction.isChatInputCommand()) { commandHandler(interaction) } + if (interaction.isButton()) { buttonHandler(interaction) } + if (interaction.isMentionableSelectMenu()) { selectMenuHandler(interaction) } + if (interaction.isUserSelectMenu()) { selectMenuHandler(interaction) } + if (interaction.isModalSubmit()) { modalHandler(interaction) } + } +} +async function commandHandler(interaction) { + const command = interaction.client.commands.get(interaction.commandName); + + if (!command) { return console.error(`No command matching ${interaction.commandName} was found.`) } + try { + await command.execute(interaction); + } catch (error) { + console.error(error); + if (interaction.replied || interaction.deferred) { + await interaction.followUp({ + content: 'There was an error while executing this command!', + flags: MessageFlags.Ephemeral + }); + } else { + await interaction.reply({ + content: 'There was an error while executing this command!', + flags: MessageFlags.Ephemeral + }); + } + } +} +async function buttonHandler(interaction) { + const button = interaction.client.buttons.get(interaction.customId) + if (!button) { return console.error(`No button registered matching ${interaction.customId}.`) } + try { + await button.execute(interaction); + } catch (error) { + console.error(error); + if (interaction.replied || interaction.deferred) { + await interaction.followUp({ + content: 'There was an error while executing this command!', + flags: MessageFlags.Ephemeral + }); + } else { + await interaction.reply({ + content: 'There was an error while executing this command!', + flags: MessageFlags.Ephemeral + }); + } + } +} +async function selectMenuHandler(interaction) { + const selectMenu = interaction.client.selectMenus.get(interaction.customId) + if (!selectMenu) { return console.error(`No Select Menu registered matching ${interaction.customId}.`) } + try { + await selectMenu.execute(interaction); + } catch (error) { + console.error(error); + if (interaction.replied || interaction.deferred) { + await interaction.followUp({ + content: 'There was an error while executing this command!', + flags: MessageFlags.Ephemeral + }); + } else { + await interaction.reply({ + content: 'There was an error while executing this command!', + flags: MessageFlags.Ephemeral + }); + } + } +} + +async function modalHandler(interaction) { + const modal = interaction.client.modals.get(interaction.customId); + if (!modal) { return console.error(`No Modal registered matching ${interaction.customId}.`); } + try { + await modal.execute(interaction); + } catch (error) { + console.error(error); + + if (interaction.replied || interaction.deferred) { + await interaction.followUp({ + content: 'There was an error while executing this modal!', + flags: MessageFlags.Ephemeral + }); + } else { + await interaction.reply({ + content: 'There was an error while executing this modal!', + flags: MessageFlags.Ephemeral + }); + } + } +} \ No newline at end of file diff --git a/handlers/buttons.js b/handlers/buttons.js new file mode 100644 index 0000000..6748d39 --- /dev/null +++ b/handlers/buttons.js @@ -0,0 +1,20 @@ +const fs = require('node:fs') +const path = require('node:path') +module.exports = (client) => { + const buttonsFoldersPath = path.join(__dirname, '../buttons'); + const buttonsFolders = fs.readdirSync(buttonsFoldersPath); + let buttonCount = 0 + for (const folder of buttonsFolders) { + const buttonsPath = path.join(buttonsFoldersPath, folder); + const buttonsFiles = fs.readdirSync(buttonsPath).filter(file => file.endsWith('.js')); + for (const file of buttonsFiles) { + buttonCount++ + const filePath = path.join(buttonsPath, file); + const button = require(filePath); + if ('execute' in button) { + client.buttons.set(button.name, button); + } + } + } + console.log(`[${buttonCount}] Button(s) initialized`) +} diff --git a/handlers/commands.js b/handlers/commands.js new file mode 100644 index 0000000..233f821 --- /dev/null +++ b/handlers/commands.js @@ -0,0 +1,41 @@ +const { REST, Routes } = require('discord.js') +const fs = require('node:fs') +const path = require('node:path') + +module.exports = (client) => { + let commands = [] // only used for REST API + const foldersPath = path.join(__dirname, '../commands'); + const commandFolders = fs.readdirSync(foldersPath); + for (const folder of commandFolders) { + // Grab all the command files from the commands directory you created earlier + const commandsPath = path.join(foldersPath, folder); + const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); + // Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment + for (const file of commandFiles) { + const filePath = path.join(commandsPath, file); + const command = require(filePath); + if ('data' in command && 'execute' in command) { + commands.push(command.data.toJSON()); + client.commands.set(command.data.name, command); + } else { + console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`); + } + } + } + const rest = new REST().setToken(process.env.D_TOKEN); + (async () => { + try { + console.log(`Started refreshing ${commands.length} application (/) commands.`); + // The put method is used to fully refresh all commands in the guild with the current set + const data = await rest.put( + Routes.applicationGuildCommands(process.env.D_ID, process.env.D_GID), + { 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); + } + })(); +} diff --git a/handlers/events.js b/handlers/events.js new file mode 100644 index 0000000..de7b6e3 --- /dev/null +++ b/handlers/events.js @@ -0,0 +1,18 @@ +const fs = require('node:fs') +const path = require('node:path') +module.exports = (client) => { + const eventsPath = path.join(__dirname, '../events') + const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js')) + + for (const file of eventFiles) { + const filePath = path.join(eventsPath, file) + const event = require(filePath) + if (event.once) { + client.once(event.name, (...args) => event.execute(...args, client)) + // added client to commomerate global usage + } else { + client.on(event.name, (...args) => event.execute(...args, client)) + // added client to commomerate global usage + } + } +} \ No newline at end of file diff --git a/handlers/selectMenus.js b/handlers/selectMenus.js new file mode 100644 index 0000000..73066e9 --- /dev/null +++ b/handlers/selectMenus.js @@ -0,0 +1,20 @@ +const fs = require('node:fs') +const path = require('node:path') +module.exports = (client) => { + const selectMenusFoldersPath = path.join(__dirname, '../selectMenus'); + const selectMenusFolders = fs.readdirSync(selectMenusFoldersPath); + let selectMenuCount = 0 + for (const folder of selectMenusFolders) { + const Path = path.join(selectMenusFoldersPath, folder); + const Files = fs.readdirSync(Path).filter(file => file.endsWith('.js')); + for (const file of Files) { + selectMenuCount++ + const filePath = path.join(Path, file); + const button = require(filePath); + if ('execute' in button) { + client.selectMenus.set(button.name, button); + } + } + } + console.log(`[${selectMenuCount}] Select Menu(s) initialized`) +} diff --git a/index.js b/index.js index 062a386..877e7c9 100644 --- a/index.js +++ b/index.js @@ -1,71 +1,33 @@ -const DiscordJS = require('discord.js') -const WOKCommands = require('wokcommands') -const path = require('path') -require('dotenv').config(); - -const { Intents } = DiscordJS -const client = new DiscordJS.Client({ - intents: [ - Intents.FLAGS.GUILDS, - Intents.FLAGS.GUILD_MESSAGES, - Intents.FLAGS.GUILD_MESSAGE_REACTIONS, - ], -}) -/* - To-Do: - - animal spawn time with weather condition check - - lodestone lookup???? - - change database structure: duties in one, filter by type (e.g. Dungeon, Raid. etc); classes in one, filter by type (e.g. Tank, Healer, etc) -*/ - -client.on('ready', async () => { - const dbOptions = { - keepAlive: true - } - new WOKCommands(client, { - commandsDir: path.join(__dirname, 'commands'), - featuresDir: path.join(__dirname, 'features'), - messagesPath: '', - typeScript: false, - showWarns: true, - delErrMsgCooldown: -1, - defaultLangauge: 'english', - ignoreBots: false, - ephemeral: false, - dbOptions: { - // These are the default options - keepAlive: true - }, - testServers: ['848610258306072576'], - botOwners: ['140508899064283136'], - disabledDefaultCommands: [ - // 'help', - // 'command', - // 'language', - // 'prefix', - // 'requiredrole', - // 'channelonly' - ], - mongoUri: process.env.URI, - debug: false -}) - .setDefaultPrefix('$') - // Used for the color of embeds sent by WOKCommands - .setColor(0xff0000) -}) - -client.login(process.env.TOKEN) - -/* -SUB_COMMAND 1 -SUB_COMMAND_GROUP 2 -STRING 3 -INTEGER 4 Any integer between -2^53 and 2^53 -BOOLEAN 5 -USER 6 -CHANNEL 7 Includes all channel types + categories -ROLE 8 -MENTIONABLE 9 Includes users and roles -NUMBER 10 Any double between -2^53 and 2^53 -ATTACHMENT 11 attachment object -*/ \ No newline at end of file +const { Client, GatewayIntentBits, Collection, Partials } = require('discord.js') +const { MongoClient } = require('mongodb') +require('dotenv').config() +const mClient = new MongoClient(process.env.M_URI) +exports.mClient = mClient; +const fs = require('node:fs') + +const client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.GuildPresences, + GatewayIntentBits.GuildMessageReactions, + GatewayIntentBits.GuildVoiceStates, + GatewayIntentBits.DirectMessages, + GatewayIntentBits.MessageContent, + ], + partials: [Partials.Channel, Partials.Message, Partials.User, Partials.GuildMember, Partials.Reaction] +}); +exports.client = client + +client.commands = new Collection() // slash commands collection +client.legacyCommands = new Collection() // legacy commands collection +client.aliases = new Collection() // list of command aliases +client.buttons = new Collection() // list of buttons +client.selectMenus = new Collection() // list of selectMenus + +fs.readdirSync('./handlers').forEach((handler) => { + require(`./handlers/${handler}`)(client) +}); + +client.login(process.env.D_TOKEN) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b5de689..9376ffc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,571 +1,470 @@ { - "name": "shaitest", + "name": "shaibot", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "shaitest", + "name": "shaibot", "version": "1.0.0", "license": "ISC", "dependencies": { - "dotenv": "^16.0.2", - "mongodb": "^4.9.1", - "mongoose": "^6.6.0", - "wokcommands": "^1.5.3" + "discord.js": "^14.27.0", + "dotenv": "^17.4.2", + "mongodb": "^7.5.0" } }, "node_modules/@discordjs/builders": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz", - "integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==", - "deprecated": "no longer supported", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.14.1.tgz", + "integrity": "sha512-gSKkhXLqs96TCzk66VZuHHl8z2bQMJFGwrXC0f33ngK+FLNau4hU1PYny3DNJfNdSH+gVMzE85/d5FQ2BpcNwQ==", + "license": "Apache-2.0", "dependencies": { - "@sapphire/shapeshift": "^3.5.1", - "discord-api-types": "^0.36.2", + "@discordjs/formatters": "^0.6.2", + "@discordjs/util": "^1.2.0", + "@sapphire/shapeshift": "^4.0.0", + "discord-api-types": "^0.38.40", "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.1", - "tslib": "^2.4.0" + "ts-mixer": "^6.0.4", + "tslib": "^2.6.3" }, "engines": { - "node": ">=16.9.0" + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" } }, - "node_modules/@discordjs/builders/node_modules/discord-api-types": { - "version": "0.36.3", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", - "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" - }, "node_modules/@discordjs/collection": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.7.0.tgz", - "integrity": "sha512-R5i8Wb8kIcBAFEPLLf7LVBQKBDYUL+ekb23sOgpkpyGT+V4P7V83wTxcsqmX+PbqHt4cEHn053uMWfRqh/Z/nA==", - "deprecated": "no longer supported", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "license": "Apache-2.0", "engines": { - "node": ">=16.9.0" + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.2.tgz", + "integrity": "sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ==", + "license": "Apache-2.0", + "dependencies": { + "discord-api-types": "^0.38.33" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/rest": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.6.3.tgz", + "integrity": "sha512-wvOylxNYJkwKjctS/Mn5GP1w9r3/rzyH+ThD1JlAca6zEdlHs8QWBBUQJpU5Q+W6DoIj/Ljh1IPlZs7hTU+UAg==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^2.1.1", + "@discordjs/util": "^1.2.0", + "@sapphire/async-queue": "^1.5.3", + "@sapphire/snowflake": "^3.5.5", + "@vladfrangu/async_event_emitter": "^2.4.6", + "discord-api-types": "^0.38.50", + "magic-bytes.js": "^1.13.0", + "tslib": "^2.6.3", + "undici": "^6.27.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/rest/node_modules/@discordjs/collection": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz", + "integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/util": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.2.0.tgz", + "integrity": "sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg==", + "license": "Apache-2.0", + "dependencies": { + "discord-api-types": "^0.38.33" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/ws": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.3.tgz", + "integrity": "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^2.1.0", + "@discordjs/rest": "^2.5.1", + "@discordjs/util": "^1.1.0", + "@sapphire/async-queue": "^1.5.2", + "@types/ws": "^8.5.10", + "@vladfrangu/async_event_emitter": "^2.2.4", + "discord-api-types": "^0.38.1", + "tslib": "^2.6.2", + "ws": "^8.17.0" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/collection": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz", + "integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.13.tgz", + "integrity": "sha512-E3Sv4eCYAlKYUTx8S3ioQcDUscOif+8zZ5OnW1IzJ+Tt+EO+ke8mn+Y3FX6N1H79picwbdOavVOb1jPi2EOyrg==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" } }, "node_modules/@sapphire/async-queue": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", - "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz", + "integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==", + "license": "MIT", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, "node_modules/@sapphire/shapeshift": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.6.0.tgz", - "integrity": "sha512-tu2WLRdo5wotHRvsCkspg3qMiP6ETC3Q1dns1Q5V6zKUki+1itq6AbhMwohF9ZcLoYqg+Y8LkgRRtVxxTQVTBQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz", + "integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", - "lodash.uniqwith": "^4.5.0" + "lodash": "^4.17.21" }, + "engines": { + "node": ">=v16" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.5.tgz", + "integrity": "sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==", + "license": "MIT", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, "node_modules/@types/node": { - "version": "18.7.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz", - "integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==" - }, - "node_modules/@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "version": "26.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", + "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "license": "MIT", "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, - "node_modules/@types/node-fetch/node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" + "undici-types": "~8.3.0" } }, "node_modules/@types/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" }, "node_modules/@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", + "license": "MIT", "dependencies": { - "@types/node": "*", "@types/webidl-conversions": "*" } }, "node_modules/@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bson": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", - "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", - "dependencies": { - "buffer": "^5.6.0" - }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.7.tgz", + "integrity": "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==", + "license": "MIT", "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/discord-api-types": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.33.5.tgz", - "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg==" - }, - "node_modules/discord.js": { - "version": "13.10.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.3.tgz", - "integrity": "sha512-cIARuxfpQDeqA9Zw3fz4IL20xAhtMsjwJIf7/K82R3n2xROG9/fAx+7qjX8ysp9BfflYqMu2ZskyWq1EAmL5BA==", - "dependencies": { - "@discordjs/builders": "^0.16.0", - "@discordjs/collection": "^0.7.0", - "@sapphire/async-queue": "^1.5.0", - "@types/node-fetch": "^2.6.2", - "@types/ws": "^8.5.3", - "discord-api-types": "^0.33.3", - "form-data": "^4.0.0", - "node-fetch": "^2.6.7", - "ws": "^8.8.1" - }, - "engines": { - "node": ">=16.6.0", + "node": ">=v14.0.0", "npm": ">=7.0.0" } }, + "node_modules/bson": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-7.3.2.tgz", + "integrity": "sha512-1w0ra+ho1cuE+w8jzwgzTFIimFtCfZeCoOsvIPQg6uyFCsp8M29U7bNNf5GrFh88TXbYg1g3TyKUGpd6O7q6zA==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/discord-api-types": { + "version": "0.38.53", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.53.tgz", + "integrity": "sha512-HL1zz/UuZ+bbJjA/X8Kbxx9gk8v9rJAbTeWRNYKmIdjwJ7EovjlHgoJTxcLpATfNJ+AonOtMdy3Y5MVIJAAd/A==", + "license": "MIT", + "workspaces": [ + "scripts/actions/documentation" + ] + }, + "node_modules/discord.js": { + "version": "14.27.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.27.0.tgz", + "integrity": "sha512-qHbFlFG2N7y3LjPySYsL6A1+BnX6bkTVgo842EX0CqVPk/KTMwZkojPHEXKsQUpWZNyz5BISNHK1cPpQw0+m4A==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/builders": "^1.14.1", + "@discordjs/collection": "1.5.3", + "@discordjs/formatters": "^0.6.2", + "@discordjs/rest": "^2.6.2", + "@discordjs/util": "^1.2.0", + "@discordjs/ws": "^1.2.3", + "@sapphire/snowflake": "3.5.5", + "discord-api-types": "^0.38.49", + "fast-deep-equal": "3.1.3", + "lodash.snakecase": "4.1.1", + "magic-bytes.js": "^1.13.0", + "tslib": "^2.6.3", + "undici": "^6.27.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, "node_modules/dotenv": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz", - "integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==", + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "license": "MIT" }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, - "node_modules/kareem": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.4.1.tgz", - "integrity": "sha512-aJ9opVoXroQUPfovYP5kaj2lM7Jn02Gw13bL0lg9v0V7SaUc0qavPs0Eue7d2DcC3NjqI6QAUElXNsuZSeM+EA==" - }, - "node_modules/lodash.uniqwith": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", - "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" + "node_modules/magic-bytes.js": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.13.1.tgz", + "integrity": "sha512-x5sn4UX2k5gCWlcfmoFwG4TPie8+dctESyqOBdhB5p6MsgWXdBKGmt9nXPObj/JI50TTL928lc5Yt1WntMn1bw==", + "license": "MIT" }, "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } + "license": "MIT" }, "node_modules/mongodb": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.1.tgz", - "integrity": "sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.5.0.tgz", + "integrity": "sha512-5FnrEDLnvp6ycUOGLNLLU33BfCx2qmp2mJjGPDwKLruYsVzXVSK5fsGpoDXvsXJwBfBsD7ebMRdawbDxC2814g==", + "license": "Apache-2.0", "dependencies": { - "bson": "^4.7.0", - "denque": "^2.1.0", - "mongodb-connection-string-url": "^2.5.3", - "socks": "^2.7.0" + "@mongodb-js/saslprep": "^1.4.11", + "bson": "^7.2.0", + "mongodb-connection-string-url": "^7.0.1" }, "engines": { - "node": ">=12.9.0" - }, - "optionalDependencies": { - "saslprep": "^1.0.3" - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", - "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", - "dependencies": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" - } - }, - "node_modules/mongoose": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.6.0.tgz", - "integrity": "sha512-5sS0D7qbmfT4G/nODkJhx5l2qvhqLMplhMlp08Wea8eoi6O/B6b+o1ukUEKjjm1MV8dAS3w8kx47R/klYKLPpQ==", - "dependencies": { - "bson": "^4.6.5", - "kareem": "2.4.1", - "mongodb": "4.9.1", - "mpath": "0.9.0", - "mquery": "4.0.3", - "ms": "2.1.3", - "sift": "16.0.0" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mongoose" - } - }, - "node_modules/mpath": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", - "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mquery": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", - "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", - "dependencies": { - "debug": "4.x" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" + "node": ">=20.19.0" }, "peerDependencies": { - "encoding": "^0.1.0" + "@aws-sdk/credential-providers": "^3.806.0", + "@mongodb-js/zstd": "^7.0.0", + "gcp-metadata": "^7.0.1", + "kerberos": "^7.0.0", + "mongodb-client-encryption": "^7.2.0", + "snappy": "^7.3.2", + "socks": "^2.8.6" }, "peerDependenciesMeta": { - "encoding": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { "optional": true } } }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "node_modules/mongodb-connection-string-url": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.2.tgz", + "integrity": "sha512-ZoS07RoFqpKYQwAk59qmrx8+jJHNHU30UjlU96QktiGn1ltvDr+vCznLX5DiUBLEpMAHatHNWV1nM/74ul66kA==", + "license": "Apache-2.0", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "@types/whatwg-url": "^13.0.0", + "whatwg-url": "^14.1.0" + }, + "engines": { + "node": ">=20.19.0" } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "dependencies": { - "sparse-bitfield": "^3.0.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/sift": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", - "integrity": "sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==" - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "optional": true, + "license": "MIT", "dependencies": { "memory-pager": "^1.0.2" } }, "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", "dependencies": { - "punycode": "^2.1.1" + "punycode": "^2.3.1" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/ts-mixer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz", - "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==" + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==", + "license": "MIT" }, "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/undici": { + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz", + "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "license": "MIT" }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" } }, "node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", "dependencies": { - "tr46": "^3.0.0", + "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=12" - } - }, - "node_modules/wokcommands": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/wokcommands/-/wokcommands-1.5.3.tgz", - "integrity": "sha512-oBb7ujov8zJ1DYSLz3G7OW9DJK+0l35t/ds5j/2nJ+4DwfzLU7w4i2yXGZOidSHkkygSegiNuaWKfZTP2okJOw==", - "dependencies": { - "discord.js": "^13.1.0", - "dotenv": "^8.2.0", - "mongoose": "^6.0.10" - } - }, - "node_modules/wokcommands/node_modules/dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", - "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -576,412 +475,5 @@ } } } - }, - "dependencies": { - "@discordjs/builders": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz", - "integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==", - "requires": { - "@sapphire/shapeshift": "^3.5.1", - "discord-api-types": "^0.36.2", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.1", - "tslib": "^2.4.0" - }, - "dependencies": { - "discord-api-types": { - "version": "0.36.3", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", - "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" - } - } - }, - "@discordjs/collection": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.7.0.tgz", - "integrity": "sha512-R5i8Wb8kIcBAFEPLLf7LVBQKBDYUL+ekb23sOgpkpyGT+V4P7V83wTxcsqmX+PbqHt4cEHn053uMWfRqh/Z/nA==" - }, - "@sapphire/async-queue": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", - "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==" - }, - "@sapphire/shapeshift": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.6.0.tgz", - "integrity": "sha512-tu2WLRdo5wotHRvsCkspg3qMiP6ETC3Q1dns1Q5V6zKUki+1itq6AbhMwohF9ZcLoYqg+Y8LkgRRtVxxTQVTBQ==", - "requires": { - "fast-deep-equal": "^3.1.3", - "lodash.uniqwith": "^4.5.0" - } - }, - "@types/node": { - "version": "18.7.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz", - "integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==" - }, - "@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - }, - "dependencies": { - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "@types/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" - }, - "@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", - "requires": { - "@types/node": "*", - "@types/webidl-conversions": "*" - } - }, - "@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", - "requires": { - "@types/node": "*" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bson": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", - "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", - "requires": { - "buffer": "^5.6.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" - }, - "discord-api-types": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.33.5.tgz", - "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg==" - }, - "discord.js": { - "version": "13.10.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.3.tgz", - "integrity": "sha512-cIARuxfpQDeqA9Zw3fz4IL20xAhtMsjwJIf7/K82R3n2xROG9/fAx+7qjX8ysp9BfflYqMu2ZskyWq1EAmL5BA==", - "requires": { - "@discordjs/builders": "^0.16.0", - "@discordjs/collection": "^0.7.0", - "@sapphire/async-queue": "^1.5.0", - "@types/node-fetch": "^2.6.2", - "@types/ws": "^8.5.3", - "discord-api-types": "^0.33.3", - "form-data": "^4.0.0", - "node-fetch": "^2.6.7", - "ws": "^8.8.1" - } - }, - "dotenv": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz", - "integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, - "kareem": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.4.1.tgz", - "integrity": "sha512-aJ9opVoXroQUPfovYP5kaj2lM7Jn02Gw13bL0lg9v0V7SaUc0qavPs0Eue7d2DcC3NjqI6QAUElXNsuZSeM+EA==" - }, - "lodash.uniqwith": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", - "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" - }, - "memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mongodb": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.1.tgz", - "integrity": "sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ==", - "requires": { - "bson": "^4.7.0", - "denque": "^2.1.0", - "mongodb-connection-string-url": "^2.5.3", - "saslprep": "^1.0.3", - "socks": "^2.7.0" - } - }, - "mongodb-connection-string-url": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", - "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", - "requires": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" - } - }, - "mongoose": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.6.0.tgz", - "integrity": "sha512-5sS0D7qbmfT4G/nODkJhx5l2qvhqLMplhMlp08Wea8eoi6O/B6b+o1ukUEKjjm1MV8dAS3w8kx47R/klYKLPpQ==", - "requires": { - "bson": "^4.6.5", - "kareem": "2.4.1", - "mongodb": "4.9.1", - "mpath": "0.9.0", - "mquery": "4.0.3", - "ms": "2.1.3", - "sift": "16.0.0" - } - }, - "mpath": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", - "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==" - }, - "mquery": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", - "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", - "requires": { - "debug": "4.x" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, - "sift": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", - "integrity": "sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==" - }, - "smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" - }, - "socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", - "requires": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - } - }, - "sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "optional": true, - "requires": { - "memory-pager": "^1.0.2" - } - }, - "tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "requires": { - "punycode": "^2.1.1" - } - }, - "ts-mixer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz", - "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==" - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" - }, - "whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "requires": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - } - }, - "wokcommands": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/wokcommands/-/wokcommands-1.5.3.tgz", - "integrity": "sha512-oBb7ujov8zJ1DYSLz3G7OW9DJK+0l35t/ds5j/2nJ+4DwfzLU7w4i2yXGZOidSHkkygSegiNuaWKfZTP2okJOw==", - "requires": { - "discord.js": "^13.1.0", - "dotenv": "^8.2.0", - "mongoose": "^6.0.10" - }, - "dependencies": { - "dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==" - } - } - }, - "ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", - "requires": {} - } } } diff --git a/package.json b/package.json index e9dd9f4..63b7c10 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,22 @@ { - "name": "shaitest", + "name": "shaibot", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, + "repository": { + "type": "git", + "url": "https://git.desq-gaming.de/admin_rb/ShaiBot.git" + }, "keywords": [], "author": "", "license": "ISC", + "type": "commonjs", "dependencies": { - "dotenv": "^16.0.2", - "mongodb": "^4.9.1", - "mongoose": "^6.6.0", - "wokcommands": "^1.5.3" + "discord.js": "^14.27.0", + "dotenv": "^17.4.2", + "mongodb": "^7.5.0" } } diff --git a/schemas/classSchema.js b/schemas/classSchema.js deleted file mode 100644 index 2f0ed2d..0000000 --- a/schemas/classSchema.js +++ /dev/null @@ -1,18 +0,0 @@ -const { default: mongoose } = require("mongoose"); - -const reqString = { - type: String, - required: true, -} - -const reqInteger = { - type: Number, - required: true, -} - -const classSchema = new mongoose.Schema({ - _id: reqInteger, - job: reqString -}) - -module.exports = mongoose.model('classes', classSchema) \ No newline at end of file diff --git a/schemas/cookieSchema.js b/schemas/cookieSchema.js deleted file mode 100644 index ed1f0cf..0000000 --- a/schemas/cookieSchema.js +++ /dev/null @@ -1,19 +0,0 @@ -const mongoose = require('mongoose') - -const reqString = { - type: String, - required: true, -} -const reqInteger = { - type: Number, - required: true, -} - -const cookieSchema = new mongoose.Schema({ - //Guild ID - _id: reqString, - user: reqString, - cookies: reqInteger -}) - -module.exports = mongoose.model('Cookies', cookieSchema) \ No newline at end of file diff --git a/schemas/cooldownSchema.js b/schemas/cooldownSchema.js deleted file mode 100644 index b870e5d..0000000 --- a/schemas/cooldownSchema.js +++ /dev/null @@ -1,20 +0,0 @@ -const { default: mongoose } = require("mongoose"); - -const reqString = { - type: String, - required: true, -} - -const reqInteger = { - type: Number, - required: true, -} - -const cooldownSchema = new mongoose.Schema({ - _id: reqString, - command: reqString, - subcommand: reqString, - cooldown: reqInteger -}) - -module.exports = mongoose.model('cooldowns', cooldownSchema) \ No newline at end of file