const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); const { getCookieBalance, temporaryEphemeralReply } = require("./cookieEconomy"); /* * ============================================================ * MAIN MENU * ============================================================ */ async function showCrumbSaucer( interaction ) { /* * Button navigation must preserve ownership. */ if ( interaction.isButton() ) { const ownerId = getCrumbSaucerSessionOwner( 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 = buildMainMenuEmbed( interaction.user, balance ); if ( interaction.isButton() ) { return interaction.update({ embeds: [ embed ], components: buildMainMenuButtons() }); } return interaction.reply({ embeds: [ embed ], components: buildMainMenuButtons() }); } /* * ============================================================ * MAIN MENU EMBED * ============================================================ */ function buildMainMenuEmbed( user, balance ) { return new EmbedBuilder() .setTitle( "🎰 The Crumb Saucer" ) .setDescription( [ `Welcome, ${user}!`, "", "Where Cookies are won, lost,", "and occasionally confiscated by ShaiBot.", "", "### 🍪 Cookie Bakery", "Collect your regular batch of Cookies.", "", "### 🎰 Slots", "Spin the reels and chase the Cookie jackpot.", "", "### 🃏 Blackjack", "Beat the dealer without going over 21.", "", "### 🎡 Roulette", "Bet on Red, Black, Odd, Even, or Zero.", "", "### 🏦 Vault Heist", "Attempt to breach ShaiBot's Cookie Vault." ].join("\n") ) .addFields({ name: "Your Vault", value: `**${balance.toLocaleString()} 🍪**` }) .setFooter({ text: `crumbSaucer:${user.id}` }); } /* * ============================================================ * MAIN MENU BUTTONS * ============================================================ */ function buildMainMenuButtons() { return [ new ActionRowBuilder() .addComponents( new ButtonBuilder() .setCustomId( "crumbSaucerSlots" ) .setLabel( "Slots" ) .setEmoji( "🎰" ) .setStyle( ButtonStyle.Primary ), new ButtonBuilder() .setCustomId( "crumbSaucerBlackjack" ) .setLabel( "Blackjack" ) .setEmoji( "🃏" ) .setStyle( ButtonStyle.Success ), new ButtonBuilder() .setCustomId( "crumbSaucerRoulette" ) .setLabel( "Roulette" ) .setEmoji( "🎡" ) .setStyle( ButtonStyle.Primary ), new ButtonBuilder() .setCustomId( "crumbSaucerHeist" ) .setLabel( "Vault Heist" ) .setEmoji( "🏦" ) .setStyle( ButtonStyle.Danger ) ), new ActionRowBuilder() .addComponents( new ButtonBuilder() .setCustomId( "crumbSaucerCollectMenu" ) .setLabel( "Cookie Bakery" ) .setEmoji( "🍪" ) .setStyle( ButtonStyle.Success ), /* * Do NOT use global "abort" here. * * The dedicated handler validates * Crumb Saucer ownership first. */ new ButtonBuilder() .setCustomId( "crumbSaucerClose" ) .setLabel( "Close" ) .setEmoji( "✖️" ) .setStyle( ButtonStyle.Secondary ) ) ]; } /* * ============================================================ * SESSION OWNER * ============================================================ */ function getCrumbSaucerSessionOwner( interaction ) { const footer = interaction.message ?.embeds?.[0] ?.footer ?.text; const parts = footer?.split(":") ?? []; switch ( parts[0] ) { case "crumbSaucer": case "crumbSaucerCollect": case "crumbSaucerSlots": case "crumbSaucerSlotsResult": case "crumbSaucerBlackjack": case "crumbBlackjackResult": case "crumbRouletteMenu": case "crumbRouletteBet": case "crumbRouletteResult": case "cookieHeist": return parts[1]; /* * Active Blackjack: * * crumbBlackjack:: */ case "crumbBlackjack": return parts[2]; default: return null; } } /* * ============================================================ * EXPORTS * ============================================================ */ module.exports = { showCrumbSaucer, getCrumbSaucerSessionOwner };