Files
ShaiBot/utils/crumbCollect.js
2026-08-27 19:50:12 +02:00

403 lines
7.9 KiB
JavaScript

const {
EmbedBuilder,
ActionRowBuilder,
ButtonBuilder,
ButtonStyle
} = require("discord.js");
const {
getCookieBalance,
changeCookies,
claimCooldown,
temporaryEphemeralReply
} = require("./cookieEconomy");
const {
trackProfileEvent
} = require("./profileSystem");
/*
* ============================================================
* CONFIG
* ============================================================
*/
const COLLECT_COOLDOWN = 60 * 60;
const COLLECT_MIN = 1;
const COLLECT_MAX = 1000;
const COLLECT_COOLDOWN_KEY = "collect";
/*
* ============================================================
* SHARED COLLECT LOGIC
* ============================================================
*
* This is the one authoritative implementation used by:
*
* - /cookies collect
* - Crumb Saucer Cookie Bakery
*
* It does not reply/update Discord itself.
*/
async function collectCookies(
interaction,
userId = interaction.user.id
) {
const cooldown = await claimCooldown(
userId,
interaction.guildId,
COLLECT_COOLDOWN_KEY,
COLLECT_COOLDOWN
);
if (!cooldown.claimed) {
const balance = await getCookieBalance(
userId
);
return {
collected: false,
cooldown,
balance,
amount: 0
};
}
const amount =
Math.floor(
Math.random() *
(
COLLECT_MAX -
COLLECT_MIN +
1
)
) +
COLLECT_MIN;
await changeCookies(
userId,
amount
);
await trackProfileEvent(
interaction,
userId,
{
type: "cookie_gain",
source: "collect",
amount
}
);
const balance = await getCookieBalance(
userId
);
return {
collected: true,
cooldown,
balance,
amount
};
}
/*
* ============================================================
* SHARED EMBED BUILDERS
* ============================================================
*/
function buildCollectSuccessEmbed(
userId,
result,
footerType = "crumbSaucerCollect"
) {
return new EmbedBuilder()
.setTitle(
"🍪 Fresh Batch!"
)
.setDescription(
[
`You collected **${result.amount.toLocaleString()} Cookies**! 🍪`,
"",
`Your next batch will be ready <t:${result.cooldown.next}:R>.`
].join("\n")
)
.addFields({
name: "Your Vault",
value:
`**${result.balance.toLocaleString()} 🍪**`
})
.setFooter({
text:
`${footerType}:${userId}`
});
}
function buildCollectCooldownEmbed(
userId,
result,
footerType = "crumbSaucerCollect"
) {
return new EmbedBuilder()
.setTitle(
"🍪 Cookie Bakery"
)
.setDescription(
[
"Your next batch isn't ready yet.",
"",
`Come back <t:${result.cooldown.next}:R>.`
].join("\n")
)
.addFields({
name: "Your Vault",
value:
`**${result.balance.toLocaleString()} 🍪**`
})
.setFooter({
text:
`${footerType}:${userId}`
});
}
/*
* ============================================================
* SHOW SAUCER COLLECT PAGE
* ============================================================
*/
async function showCollectPage(
interaction
) {
const ownerId =
getCollectOwner(
interaction
);
if (
ownerId !==
interaction.user.id
) {
return temporaryEphemeralReply(
interaction,
{
content:
"This isn't your Crumb Saucer session."
}
);
}
const balance =
await getCookieBalance(
interaction.user.id
);
const embed =
new EmbedBuilder()
.setTitle(
"🍪 Crumb Saucer Cookie Bakery"
)
.setDescription(
[
"Fresh Cookies are prepared regularly.",
"",
"Press **Collect Cookies** to claim your batch.",
"",
"Your collection cooldown is shared with `/cookies collect`."
].join("\n")
)
.addFields({
name: "Your Vault",
value:
`**${balance.toLocaleString()} 🍪**`
})
.setFooter({
text:
`crumbSaucerCollect:${interaction.user.id}`
});
return interaction.update({
embeds: [embed],
components:
buildCollectButtons()
});
}
/*
* ============================================================
* SAUCER COLLECT WRAPPER
* ============================================================
*/
async function collectCookiesFromSaucer(
interaction
) {
const ownerId =
getCollectOwner(
interaction
);
if (
ownerId !==
interaction.user.id
) {
return temporaryEphemeralReply(
interaction,
{
content:
"This isn't your Crumb Saucer session."
}
);
}
const result =
await collectCookies(
interaction,
interaction.user.id
);
const embed =
result.collected
? buildCollectSuccessEmbed(
interaction.user.id,
result
)
: buildCollectCooldownEmbed(
interaction.user.id,
result
);
return interaction.update({
embeds: [embed],
components:
buildCollectButtons()
});
}
/*
* ============================================================
* BUTTONS
* ============================================================
*/
function buildCollectButtons() {
return [
new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId(
"crumbSaucerCollect"
)
.setLabel(
"Collect Cookies"
)
.setEmoji(
"🍪"
)
.setStyle(
ButtonStyle.Success
),
new ButtonBuilder()
.setCustomId(
"crumbSaucerBack"
)
.setLabel(
"Crumb Saucer"
)
.setEmoji(
"◀️"
)
.setStyle(
ButtonStyle.Secondary
)
)
];
}
/*
* ============================================================
* OWNER
* ============================================================
*/
function getCollectOwner(
interaction
) {
const footer =
interaction.message
?.embeds?.[0]
?.footer
?.text;
const parts =
footer?.split(":")
??
[];
if (
parts[0] ===
"crumbSaucer"
) {
return parts[1];
}
if (
parts[0] ===
"crumbSaucerCollect"
) {
return parts[1];
}
return null;
}
/*
* ============================================================
* EXPORTS
* ============================================================
*/
module.exports = {
collectCookies,
buildCollectSuccessEmbed,
buildCollectCooldownEmbed,
showCollectPage,
collectCookiesFromSaucer,
COLLECT_COOLDOWN,
COLLECT_MIN,
COLLECT_MAX
};