1175 lines
22 KiB
JavaScript
1175 lines
22 KiB
JavaScript
const {
|
||
EmbedBuilder,
|
||
ActionRowBuilder,
|
||
ButtonBuilder,
|
||
ButtonStyle
|
||
} = require("discord.js");
|
||
|
||
const {
|
||
getCookieBalance,
|
||
transferCookies,
|
||
temporaryEphemeralReply,
|
||
randomItem
|
||
} = require("./cookieEconomy");
|
||
|
||
|
||
/*
|
||
* SLOT CONFIG
|
||
*/
|
||
|
||
const SLOT_BETS = [
|
||
10,
|
||
50,
|
||
100,
|
||
500,
|
||
1000
|
||
];
|
||
|
||
|
||
const SLOT_SYMBOLS = [
|
||
"🍒",
|
||
"🍋",
|
||
"🍪",
|
||
"⭐",
|
||
"💎"
|
||
];
|
||
|
||
|
||
/*
|
||
* Weighted outcomes.
|
||
*/
|
||
|
||
const SLOT_OUTCOMES = [
|
||
{
|
||
weight: 300,
|
||
type: "loss",
|
||
multiplier: 0
|
||
},
|
||
|
||
{
|
||
weight: 390,
|
||
type: "pair",
|
||
multiplier: 0.5
|
||
},
|
||
|
||
{
|
||
weight: 150,
|
||
type: "triple",
|
||
symbol: "🍋",
|
||
multiplier: 1.5
|
||
},
|
||
|
||
{
|
||
weight: 80,
|
||
type: "triple",
|
||
symbol: "🍒",
|
||
multiplier: 2
|
||
},
|
||
|
||
{
|
||
weight: 45,
|
||
type: "triple",
|
||
symbol: "🍪",
|
||
multiplier: 3
|
||
},
|
||
|
||
{
|
||
weight: 25,
|
||
type: "triple",
|
||
symbol: "⭐",
|
||
multiplier: 5
|
||
},
|
||
|
||
{
|
||
weight: 10,
|
||
type: "triple",
|
||
symbol: "💎",
|
||
multiplier: 10
|
||
}
|
||
];
|
||
|
||
|
||
/*
|
||
* ============================================================
|
||
* MAIN MENU
|
||
* ============================================================
|
||
*/
|
||
|
||
async function showCrumbSaucer(
|
||
interaction
|
||
) {
|
||
const balance =
|
||
await getCookieBalance(
|
||
interaction.user.id
|
||
);
|
||
|
||
|
||
const embed =
|
||
buildMainMenuEmbed(
|
||
interaction.user,
|
||
balance
|
||
);
|
||
|
||
|
||
const components =
|
||
buildMainMenuButtons();
|
||
|
||
|
||
/*
|
||
* Slash command:
|
||
* reply normally.
|
||
*
|
||
* Button:
|
||
* update existing menu message.
|
||
*/
|
||
|
||
if (
|
||
interaction.isButton()
|
||
) {
|
||
return interaction.update({
|
||
embeds: [
|
||
embed
|
||
],
|
||
|
||
components
|
||
});
|
||
}
|
||
|
||
|
||
return interaction.reply({
|
||
embeds: [
|
||
embed
|
||
],
|
||
|
||
components
|
||
});
|
||
}
|
||
|
||
|
||
/*
|
||
* ============================================================
|
||
* SLOT MENU
|
||
* ============================================================
|
||
*/
|
||
|
||
async function showSlots(
|
||
interaction
|
||
) {
|
||
const ownerId =
|
||
getMenuOwner(
|
||
interaction
|
||
);
|
||
|
||
|
||
if (
|
||
ownerId !==
|
||
interaction.user.id
|
||
) {
|
||
return temporaryEphemeralReply(
|
||
interaction,
|
||
{
|
||
content:
|
||
"This isn't your Crumb Saucer session. Open your own with `/crumbsaucer`."
|
||
}
|
||
);
|
||
}
|
||
|
||
|
||
const balance =
|
||
await getCookieBalance(
|
||
interaction.user.id
|
||
);
|
||
|
||
|
||
const embed =
|
||
new EmbedBuilder()
|
||
.setTitle(
|
||
"🎰 Crumb Saucer Slots"
|
||
)
|
||
.setDescription(
|
||
[
|
||
"Welcome to the Cookie reels.",
|
||
"",
|
||
"Choose your wager below.",
|
||
"",
|
||
"🍋 **Triple Lemon** — ×1.5",
|
||
"🍒 **Triple Cherry** — ×2",
|
||
"🍪 **Triple Cookie** — ×3",
|
||
"⭐ **Triple Star** — ×5",
|
||
"💎 **Jackpot** — ×10"
|
||
].join("\n")
|
||
)
|
||
.addFields({
|
||
name:
|
||
"Your Vault",
|
||
|
||
value:
|
||
`**${balance.toLocaleString()} 🍪**`
|
||
})
|
||
.setFooter({
|
||
text:
|
||
`crumbSaucerSlots:${interaction.user.id}`
|
||
});
|
||
|
||
|
||
return interaction.update({
|
||
embeds: [
|
||
embed
|
||
],
|
||
|
||
components:
|
||
buildSlotBetButtons()
|
||
});
|
||
}
|
||
|
||
|
||
/*
|
||
* ============================================================
|
||
* PLAY SLOTS
|
||
* ============================================================
|
||
*/
|
||
|
||
async function playSlots(
|
||
interaction,
|
||
bet
|
||
) {
|
||
const ownerId =
|
||
getSlotsOwner(
|
||
interaction
|
||
);
|
||
|
||
|
||
if (
|
||
ownerId !==
|
||
interaction.user.id
|
||
) {
|
||
return temporaryEphemeralReply(
|
||
interaction,
|
||
{
|
||
content:
|
||
"These aren't your slots. Open your own Crumb Saucer session."
|
||
}
|
||
);
|
||
}
|
||
|
||
|
||
if (
|
||
!SLOT_BETS.includes(
|
||
bet
|
||
)
|
||
) {
|
||
return temporaryEphemeralReply(
|
||
interaction,
|
||
{
|
||
content:
|
||
"That wager isn't available."
|
||
}
|
||
);
|
||
}
|
||
|
||
|
||
const playerId =
|
||
interaction.user.id;
|
||
|
||
const vaultId =
|
||
interaction.client.user.id;
|
||
|
||
|
||
const [
|
||
playerBalance,
|
||
vaultBalance
|
||
] =
|
||
await Promise.all([
|
||
getCookieBalance(
|
||
playerId
|
||
),
|
||
|
||
getCookieBalance(
|
||
vaultId
|
||
)
|
||
]);
|
||
|
||
|
||
if (
|
||
playerBalance <
|
||
bet
|
||
) {
|
||
return temporaryEphemeralReply(
|
||
interaction,
|
||
{
|
||
content:
|
||
`You need **${bet.toLocaleString()} Cookies** for that wager.`
|
||
}
|
||
);
|
||
}
|
||
|
||
|
||
/*
|
||
* Worst-case payout is x10.
|
||
*
|
||
* Once the house receives the player's bet,
|
||
* it needs another 9x available to cover
|
||
* the complete x10 payout.
|
||
*/
|
||
|
||
if (
|
||
vaultBalance <
|
||
bet * 9
|
||
) {
|
||
return temporaryEphemeralReply(
|
||
interaction,
|
||
{
|
||
content:
|
||
"The Crumb Saucer vault doesn't currently have enough Cookies to cover that wager."
|
||
}
|
||
);
|
||
}
|
||
|
||
|
||
/*
|
||
* Take wager first.
|
||
*/
|
||
|
||
try {
|
||
await transferCookies(
|
||
playerId,
|
||
vaultId,
|
||
bet
|
||
);
|
||
|
||
} catch (error) {
|
||
if (
|
||
error.message ===
|
||
"INSUFFICIENT_COOKIES"
|
||
) {
|
||
return temporaryEphemeralReply(
|
||
interaction,
|
||
{
|
||
content:
|
||
"Your Cookie balance changed before the spin could begin."
|
||
}
|
||
);
|
||
}
|
||
|
||
throw error;
|
||
}
|
||
|
||
|
||
/*
|
||
* Lock the buttons while spinning.
|
||
*/
|
||
|
||
await interaction.update({
|
||
embeds: [
|
||
buildSpinningEmbed(
|
||
bet,
|
||
generateRandomGrid(),
|
||
"🎰 Spinning..."
|
||
)
|
||
],
|
||
|
||
components: []
|
||
});
|
||
|
||
|
||
/*
|
||
* A few slow edits give a slot-machine feel
|
||
* without hammering the Discord API.
|
||
*/
|
||
|
||
await sleep(
|
||
700
|
||
);
|
||
|
||
|
||
await interaction.editReply({
|
||
embeds: [
|
||
buildSpinningEmbed(
|
||
bet,
|
||
generateRandomGrid(),
|
||
"🎰 The reels are moving..."
|
||
)
|
||
],
|
||
|
||
components: []
|
||
});
|
||
|
||
|
||
await sleep(
|
||
700
|
||
);
|
||
|
||
|
||
await interaction.editReply({
|
||
embeds: [
|
||
buildSpinningEmbed(
|
||
bet,
|
||
generateRandomGrid(),
|
||
"🎰 Almost..."
|
||
)
|
||
],
|
||
|
||
components: []
|
||
});
|
||
|
||
|
||
await sleep(
|
||
700
|
||
);
|
||
|
||
|
||
/*
|
||
* Actual outcome is determined only now.
|
||
*/
|
||
|
||
const outcome =
|
||
rollSlotOutcome();
|
||
|
||
|
||
const grid =
|
||
generateOutcomeGrid(
|
||
outcome
|
||
);
|
||
|
||
|
||
const payout =
|
||
Math.floor(
|
||
bet *
|
||
outcome.multiplier
|
||
);
|
||
|
||
|
||
/*
|
||
* House pays winnings.
|
||
*
|
||
* The original stake was already transferred
|
||
* to the house, so x2 means a total payout of 2x.
|
||
*/
|
||
|
||
if (
|
||
payout > 0
|
||
) {
|
||
try {
|
||
await transferCookies(
|
||
vaultId,
|
||
playerId,
|
||
payout
|
||
);
|
||
|
||
} catch (error) {
|
||
console.error(
|
||
"CRITICAL: Crumb Saucer payout failed:",
|
||
error
|
||
);
|
||
|
||
|
||
return interaction.editReply({
|
||
embeds: [
|
||
new EmbedBuilder()
|
||
.setTitle(
|
||
"🎰 Crumb Saucer Error"
|
||
)
|
||
.setDescription(
|
||
"The reels stopped, but the payout system had a problem. Please contact an administrator."
|
||
)
|
||
],
|
||
|
||
components:
|
||
buildResultButtons()
|
||
});
|
||
}
|
||
}
|
||
|
||
|
||
const [
|
||
playerAfter,
|
||
vaultAfter
|
||
] =
|
||
await Promise.all([
|
||
getCookieBalance(
|
||
playerId
|
||
),
|
||
|
||
getCookieBalance(
|
||
vaultId
|
||
)
|
||
]);
|
||
|
||
|
||
const profit =
|
||
payout -
|
||
bet;
|
||
|
||
|
||
const resultEmbed =
|
||
new EmbedBuilder()
|
||
.setTitle(
|
||
"🎰 Crumb Saucer Slots"
|
||
)
|
||
.setDescription(
|
||
[
|
||
buildSlotDisplay(
|
||
grid
|
||
),
|
||
"",
|
||
`### ${getSlotResultName(outcome)}`
|
||
].join("\n")
|
||
)
|
||
.addFields(
|
||
{
|
||
name:
|
||
"Bet",
|
||
|
||
value:
|
||
`${bet.toLocaleString()} 🍪`,
|
||
|
||
inline:
|
||
true
|
||
},
|
||
|
||
{
|
||
name:
|
||
"Multiplier",
|
||
|
||
value:
|
||
`×${outcome.multiplier}`,
|
||
|
||
inline:
|
||
true
|
||
},
|
||
|
||
{
|
||
name:
|
||
"Payout",
|
||
|
||
value:
|
||
`${payout.toLocaleString()} 🍪`,
|
||
|
||
inline:
|
||
true
|
||
},
|
||
|
||
{
|
||
name:
|
||
"Profit",
|
||
|
||
value:
|
||
`${profit >= 0 ? "+" : ""}${profit.toLocaleString()} 🍪`,
|
||
|
||
inline:
|
||
true
|
||
},
|
||
|
||
{
|
||
name:
|
||
"Your Vault",
|
||
|
||
value:
|
||
`${playerAfter.toLocaleString()} 🍪`,
|
||
|
||
inline:
|
||
true
|
||
},
|
||
|
||
{
|
||
name:
|
||
"House Vault",
|
||
|
||
value:
|
||
`${vaultAfter.toLocaleString()} 🍪`,
|
||
|
||
inline:
|
||
true
|
||
}
|
||
)
|
||
.setFooter({
|
||
text:
|
||
`crumbSaucerSlots:${interaction.user.id}`
|
||
});
|
||
|
||
|
||
return interaction.editReply({
|
||
embeds: [
|
||
resultEmbed
|
||
],
|
||
|
||
components:
|
||
buildResultButtons()
|
||
});
|
||
}
|
||
|
||
|
||
/*
|
||
* ============================================================
|
||
* 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.",
|
||
"",
|
||
"### 🎰 Slots",
|
||
"Spin the reels and chase the Cookie jackpot.",
|
||
"",
|
||
"### 🏦 Vault Heist",
|
||
"Attempt to breach ShaiBot's Cookie Vault.",
|
||
"",
|
||
"*More attractions coming soon...*"
|
||
].join("\n")
|
||
)
|
||
.addFields({
|
||
name:
|
||
"Your Vault",
|
||
|
||
value:
|
||
`**${balance.toLocaleString()} 🍪**`
|
||
})
|
||
.setFooter({
|
||
text:
|
||
`crumbSaucer:${user.id}`
|
||
});
|
||
}
|
||
|
||
|
||
/*
|
||
* ============================================================
|
||
* BUTTONS
|
||
* ============================================================
|
||
*/
|
||
|
||
function buildMainMenuButtons() {
|
||
return [
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerSlots"
|
||
)
|
||
.setLabel(
|
||
"Slots"
|
||
)
|
||
.setEmoji(
|
||
"🎰"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Primary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerHeist"
|
||
)
|
||
.setLabel(
|
||
"Vault Heist"
|
||
)
|
||
.setEmoji(
|
||
"🏦"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Danger
|
||
)
|
||
)
|
||
];
|
||
}
|
||
|
||
|
||
function buildSlotBetButtons() {
|
||
return [
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerSlots10"
|
||
)
|
||
.setLabel(
|
||
"10"
|
||
)
|
||
.setEmoji(
|
||
"🍪"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerSlots50"
|
||
)
|
||
.setLabel(
|
||
"50"
|
||
)
|
||
.setEmoji(
|
||
"🍪"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerSlots100"
|
||
)
|
||
.setLabel(
|
||
"100"
|
||
)
|
||
.setEmoji(
|
||
"🍪"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Primary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerSlots500"
|
||
)
|
||
.setLabel(
|
||
"500"
|
||
)
|
||
.setEmoji(
|
||
"🍪"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Primary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerSlots1000"
|
||
)
|
||
.setLabel(
|
||
"1,000"
|
||
)
|
||
.setEmoji(
|
||
"🍪"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Danger
|
||
)
|
||
),
|
||
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerBack"
|
||
)
|
||
.setLabel(
|
||
"Back to Crumb Saucer"
|
||
)
|
||
.setEmoji(
|
||
"◀️"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
)
|
||
)
|
||
];
|
||
}
|
||
|
||
|
||
function buildResultButtons() {
|
||
return [
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerSlots"
|
||
)
|
||
.setLabel(
|
||
"Play Again"
|
||
)
|
||
.setEmoji(
|
||
"🎰"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Primary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"crumbSaucerBack"
|
||
)
|
||
.setLabel(
|
||
"Crumb Saucer"
|
||
)
|
||
.setEmoji(
|
||
"◀️"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
)
|
||
)
|
||
];
|
||
}
|
||
|
||
|
||
/*
|
||
* ============================================================
|
||
* SLOT LOGIC
|
||
* ============================================================
|
||
*/
|
||
|
||
function rollSlotOutcome() {
|
||
const totalWeight =
|
||
SLOT_OUTCOMES.reduce(
|
||
(
|
||
total,
|
||
outcome
|
||
) =>
|
||
total +
|
||
outcome.weight,
|
||
|
||
0
|
||
);
|
||
|
||
|
||
let roll =
|
||
Math.random() *
|
||
totalWeight;
|
||
|
||
|
||
for (
|
||
const outcome
|
||
of SLOT_OUTCOMES
|
||
) {
|
||
roll -=
|
||
outcome.weight;
|
||
|
||
|
||
if (
|
||
roll <= 0
|
||
) {
|
||
return outcome;
|
||
}
|
||
}
|
||
|
||
|
||
return SLOT_OUTCOMES[0];
|
||
}
|
||
|
||
|
||
function generateRandomGrid() {
|
||
return Array.from(
|
||
{
|
||
length: 3
|
||
},
|
||
|
||
() =>
|
||
Array.from(
|
||
{
|
||
length: 3
|
||
},
|
||
|
||
() =>
|
||
randomItem(
|
||
SLOT_SYMBOLS
|
||
)
|
||
)
|
||
);
|
||
}
|
||
|
||
|
||
function generateOutcomeGrid(
|
||
outcome
|
||
) {
|
||
const grid =
|
||
generateRandomGrid();
|
||
|
||
|
||
/*
|
||
* Winning middle row.
|
||
*/
|
||
|
||
if (
|
||
outcome.type ===
|
||
"triple"
|
||
) {
|
||
grid[1] = [
|
||
outcome.symbol,
|
||
outcome.symbol,
|
||
outcome.symbol
|
||
];
|
||
|
||
|
||
return grid;
|
||
}
|
||
|
||
|
||
/*
|
||
* Pair.
|
||
*/
|
||
|
||
if (
|
||
outcome.type ===
|
||
"pair"
|
||
) {
|
||
const symbol =
|
||
randomItem(
|
||
SLOT_SYMBOLS
|
||
);
|
||
|
||
|
||
let other;
|
||
|
||
|
||
do {
|
||
other =
|
||
randomItem(
|
||
SLOT_SYMBOLS
|
||
);
|
||
|
||
} while (
|
||
other === symbol
|
||
);
|
||
|
||
|
||
/*
|
||
* Randomize the location of the odd symbol.
|
||
*/
|
||
|
||
const oddPosition =
|
||
Math.floor(
|
||
Math.random() *
|
||
3
|
||
);
|
||
|
||
|
||
grid[1] = [
|
||
symbol,
|
||
symbol,
|
||
symbol
|
||
];
|
||
|
||
|
||
grid[1][
|
||
oddPosition
|
||
] =
|
||
other;
|
||
|
||
|
||
return grid;
|
||
}
|
||
|
||
|
||
/*
|
||
* Loss:
|
||
* ensure all three center symbols differ.
|
||
*/
|
||
|
||
let line;
|
||
|
||
|
||
do {
|
||
line = [
|
||
randomItem(
|
||
SLOT_SYMBOLS
|
||
),
|
||
|
||
randomItem(
|
||
SLOT_SYMBOLS
|
||
),
|
||
|
||
randomItem(
|
||
SLOT_SYMBOLS
|
||
)
|
||
];
|
||
|
||
} while (
|
||
new Set(
|
||
line
|
||
).size <
|
||
3
|
||
);
|
||
|
||
|
||
grid[1] =
|
||
line;
|
||
|
||
|
||
return grid;
|
||
}
|
||
|
||
|
||
function buildSlotDisplay(
|
||
grid
|
||
) {
|
||
return [
|
||
"╔═════════════╗",
|
||
`║ ${grid[0][0]} │ ${grid[0][1]} │ ${grid[0][2]} ║`,
|
||
`║ ${grid[1][0]} │ ${grid[1][1]} │ ${grid[1][2]} ║`,
|
||
`║ ${grid[2][0]} │ ${grid[2][1]} │ ${grid[2][2]} ║`,
|
||
"╚═════════════╝"
|
||
].join("\n");
|
||
}
|
||
|
||
|
||
function buildSpinningEmbed(
|
||
bet,
|
||
grid,
|
||
status
|
||
) {
|
||
return new EmbedBuilder()
|
||
.setTitle(
|
||
"🎰 Crumb Saucer Slots"
|
||
)
|
||
.setDescription(
|
||
[
|
||
buildSlotDisplay(
|
||
grid
|
||
),
|
||
"",
|
||
`**${status}**`
|
||
].join("\n")
|
||
)
|
||
.addFields({
|
||
name:
|
||
"Bet",
|
||
|
||
value:
|
||
`**${bet.toLocaleString()} 🍪**`
|
||
});
|
||
}
|
||
|
||
|
||
function getSlotResultName(
|
||
outcome
|
||
) {
|
||
if (
|
||
outcome.type ===
|
||
"loss"
|
||
) {
|
||
return "No luck this time.";
|
||
}
|
||
|
||
|
||
if (
|
||
outcome.type ===
|
||
"pair"
|
||
) {
|
||
return "Pair!";
|
||
}
|
||
|
||
|
||
switch (
|
||
outcome.symbol
|
||
) {
|
||
case "🍋":
|
||
return "🍋 Triple Lemon!";
|
||
|
||
case "🍒":
|
||
return "🍒 Triple Cherry!";
|
||
|
||
case "🍪":
|
||
return "🍪 Triple Cookie!";
|
||
|
||
case "⭐":
|
||
return "⭐ Triple Star!";
|
||
|
||
case "💎":
|
||
return "💎 JACKPOT! 💎";
|
||
|
||
default:
|
||
return "Winner!";
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
* ============================================================
|
||
* OWNER RESOLUTION
|
||
* ============================================================
|
||
*/
|
||
|
||
function getMenuOwner(
|
||
interaction
|
||
) {
|
||
const footer =
|
||
interaction.message
|
||
.embeds[0]
|
||
?.footer
|
||
?.text;
|
||
|
||
|
||
const [
|
||
type,
|
||
userId
|
||
] =
|
||
footer
|
||
?.split(":")
|
||
??
|
||
[];
|
||
|
||
|
||
if (
|
||
type !==
|
||
"crumbSaucer"
|
||
) {
|
||
return null;
|
||
}
|
||
|
||
|
||
return userId;
|
||
}
|
||
|
||
|
||
function getSlotsOwner(
|
||
interaction
|
||
) {
|
||
const footer =
|
||
interaction.message
|
||
.embeds[0]
|
||
?.footer
|
||
?.text;
|
||
|
||
|
||
const [
|
||
type,
|
||
userId
|
||
] =
|
||
footer
|
||
?.split(":")
|
||
??
|
||
[];
|
||
|
||
|
||
if (
|
||
type !==
|
||
"crumbSaucerSlots"
|
||
) {
|
||
return null;
|
||
}
|
||
|
||
|
||
return userId;
|
||
}
|
||
|
||
|
||
function sleep(ms) {
|
||
return new Promise(
|
||
resolve =>
|
||
setTimeout(
|
||
resolve,
|
||
ms
|
||
)
|
||
);
|
||
}
|
||
|
||
|
||
module.exports = {
|
||
showCrumbSaucer,
|
||
showSlots,
|
||
playSlots
|
||
}; |