1459 lines
28 KiB
JavaScript
1459 lines
28 KiB
JavaScript
const {
|
|
EmbedBuilder,
|
|
ActionRowBuilder,
|
|
ButtonBuilder,
|
|
ButtonStyle
|
|
} = require("discord.js");
|
|
|
|
const {
|
|
getCookieBalance,
|
|
transferCookies,
|
|
temporaryEphemeralReply
|
|
} = require("./cookieEconomy");
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* CONFIG
|
|
* ============================================================
|
|
*/
|
|
|
|
const ROULETTE_BETS = [
|
|
10,
|
|
50,
|
|
100,
|
|
500,
|
|
1000
|
|
];
|
|
|
|
|
|
const ROULETTE_CHOICES = {
|
|
Red: {
|
|
name: "Red",
|
|
emoji: "🔴",
|
|
multiplier: 2
|
|
},
|
|
|
|
Black: {
|
|
name: "Black",
|
|
emoji: "⚫",
|
|
multiplier: 2
|
|
},
|
|
|
|
Odd: {
|
|
name: "Odd",
|
|
emoji: "🔢",
|
|
multiplier: 2
|
|
},
|
|
|
|
Even: {
|
|
name: "Even",
|
|
emoji: "2️⃣",
|
|
multiplier: 2
|
|
},
|
|
|
|
Zero: {
|
|
name: "Zero",
|
|
emoji: "🟢",
|
|
multiplier: 36
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
* European Roulette red numbers.
|
|
*/
|
|
|
|
const RED_NUMBERS =
|
|
new Set([
|
|
1,
|
|
3,
|
|
5,
|
|
7,
|
|
9,
|
|
12,
|
|
14,
|
|
16,
|
|
18,
|
|
19,
|
|
21,
|
|
23,
|
|
25,
|
|
27,
|
|
30,
|
|
32,
|
|
34,
|
|
36
|
|
]);
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* SHOW ROULETTE
|
|
* ============================================================
|
|
*/
|
|
|
|
async function showRoulette(
|
|
interaction
|
|
) {
|
|
const ownerId =
|
|
getRouletteSessionOwner(
|
|
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 Roulette"
|
|
)
|
|
|
|
.setDescription(
|
|
[
|
|
"European Roulette — **0 to 36**.",
|
|
"",
|
|
"Choose your wager.",
|
|
"",
|
|
"🔴 **Red** — x2",
|
|
"⚫ **Black** — x2",
|
|
"🔢 **Odd** — x2",
|
|
"2️⃣ **Even** — x2",
|
|
"🟢 **Zero** — x36"
|
|
].join("\n")
|
|
)
|
|
|
|
.addFields({
|
|
name:
|
|
"Your Vault",
|
|
|
|
value:
|
|
`**${balance.toLocaleString()} 🍪**`
|
|
})
|
|
|
|
.setFooter({
|
|
text:
|
|
`crumbRouletteMenu:${interaction.user.id}`
|
|
});
|
|
|
|
|
|
return interaction.update({
|
|
embeds: [
|
|
embed
|
|
],
|
|
|
|
components:
|
|
buildBetButtons()
|
|
});
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* CHOOSE NORMAL WAGER
|
|
* ============================================================
|
|
*/
|
|
|
|
async function chooseRouletteBet(
|
|
interaction,
|
|
bet
|
|
) {
|
|
if (
|
|
!ROULETTE_BETS.includes(
|
|
bet
|
|
)
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"That Roulette wager isn't available."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const ownerId =
|
|
getRouletteSessionOwner(
|
|
interaction
|
|
);
|
|
|
|
|
|
if (
|
|
ownerId !==
|
|
interaction.user.id
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"This isn't your Roulette table."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
return showRouletteChoices(
|
|
interaction,
|
|
bet
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* ALL IN
|
|
* ============================================================
|
|
*/
|
|
|
|
async function startRouletteAllIn(
|
|
interaction
|
|
) {
|
|
const ownerId =
|
|
getRouletteSessionOwner(
|
|
interaction
|
|
);
|
|
|
|
|
|
if (
|
|
ownerId !==
|
|
interaction.user.id
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"This isn't your Roulette table."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* Resolve the balance at click time.
|
|
*/
|
|
|
|
const balance =
|
|
await getCookieBalance(
|
|
interaction.user.id
|
|
);
|
|
|
|
|
|
if (
|
|
balance <=
|
|
0
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"You don't have any Cookies to go All In with."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* All In only selects the wager.
|
|
*
|
|
* Nothing is transferred until the player
|
|
* chooses Red / Black / Odd / Even / Zero.
|
|
*/
|
|
|
|
return showRouletteChoices(
|
|
interaction,
|
|
balance
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* SHOW CHOICE MENU
|
|
* ============================================================
|
|
*
|
|
* Shared by:
|
|
*
|
|
* - normal wager buttons
|
|
* - All In
|
|
* - Run It Back
|
|
*/
|
|
|
|
async function showRouletteChoices(
|
|
interaction,
|
|
bet
|
|
) {
|
|
if (
|
|
!Number.isSafeInteger(
|
|
bet
|
|
)
|
|
||
|
|
bet <=
|
|
0
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"That Roulette wager isn't valid."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const balance =
|
|
await getCookieBalance(
|
|
interaction.user.id
|
|
);
|
|
|
|
|
|
if (
|
|
balance <
|
|
bet
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
`You need **${bet.toLocaleString()} Cookies** for that wager.`
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const embed =
|
|
new EmbedBuilder()
|
|
.setTitle(
|
|
"🎡 Crumb Saucer Roulette"
|
|
)
|
|
|
|
.setDescription(
|
|
[
|
|
`Wager: **${bet.toLocaleString()} 🍪**`,
|
|
"",
|
|
"Where do you want to place your Cookies?",
|
|
"",
|
|
"🔴 **Red** — x2",
|
|
"⚫ **Black** — x2",
|
|
"🔢 **Odd** — x2",
|
|
"2️⃣ **Even** — x2",
|
|
"🟢 **Zero** — x36"
|
|
].join("\n")
|
|
)
|
|
|
|
.addFields({
|
|
name:
|
|
"Your Vault",
|
|
|
|
value:
|
|
`**${balance.toLocaleString()} 🍪**`
|
|
})
|
|
|
|
.setFooter({
|
|
text:
|
|
`crumbRouletteBet:${interaction.user.id}:${bet}`
|
|
});
|
|
|
|
|
|
return interaction.update({
|
|
embeds: [
|
|
embed
|
|
],
|
|
|
|
components:
|
|
buildChoiceButtons()
|
|
});
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* RUN IT BACK
|
|
* ============================================================
|
|
*
|
|
* Remembers ONLY the previous wager.
|
|
*
|
|
* It does NOT remember Red / Black / Odd / Even / Zero.
|
|
*/
|
|
|
|
async function runRouletteBack(
|
|
interaction
|
|
) {
|
|
const footer =
|
|
interaction.message
|
|
?.embeds?.[0]
|
|
?.footer
|
|
?.text;
|
|
|
|
|
|
const parts =
|
|
footer?.split(":")
|
|
??
|
|
[];
|
|
|
|
|
|
/*
|
|
* Expected:
|
|
*
|
|
* crumbRouletteResult:<userId>:<bet>
|
|
*/
|
|
|
|
if (
|
|
parts[0] !==
|
|
"crumbRouletteResult"
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"This Roulette result can no longer be replayed."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const ownerId =
|
|
parts[1];
|
|
|
|
|
|
const bet =
|
|
Number(
|
|
parts[2]
|
|
);
|
|
|
|
|
|
if (
|
|
ownerId !==
|
|
interaction.user.id
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"This isn't your Roulette session."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
if (
|
|
!Number.isSafeInteger(
|
|
bet
|
|
)
|
|
||
|
|
bet <=
|
|
0
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"The previous wager is no longer valid."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* Same wager, fresh choice.
|
|
*/
|
|
|
|
return showRouletteChoices(
|
|
interaction,
|
|
bet
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* PLAY ROULETTE
|
|
* ============================================================
|
|
*/
|
|
|
|
async function playRoulette(
|
|
interaction,
|
|
choiceKey
|
|
) {
|
|
const choice =
|
|
ROULETTE_CHOICES[
|
|
choiceKey
|
|
];
|
|
|
|
|
|
if (!choice) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"That Roulette bet doesn't exist."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const footer =
|
|
interaction.message
|
|
?.embeds?.[0]
|
|
?.footer
|
|
?.text;
|
|
|
|
|
|
const parts =
|
|
footer?.split(":")
|
|
??
|
|
[];
|
|
|
|
|
|
if (
|
|
parts[0] !==
|
|
"crumbRouletteBet"
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"This Roulette wager is no longer valid."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const ownerId =
|
|
parts[1];
|
|
|
|
|
|
const bet =
|
|
Number(
|
|
parts[2]
|
|
);
|
|
|
|
|
|
if (
|
|
ownerId !==
|
|
interaction.user.id
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"This isn't your Roulette table."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* IMPORTANT:
|
|
*
|
|
* Do NOT require ROULETTE_BETS.includes(bet) here.
|
|
*
|
|
* All In and Run It Back may legitimately use
|
|
* amounts outside the predefined wager buttons.
|
|
*/
|
|
|
|
if (
|
|
!Number.isSafeInteger(
|
|
bet
|
|
)
|
|
||
|
|
bet <=
|
|
0
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"That Roulette wager is invalid."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const playerId =
|
|
interaction.user.id;
|
|
|
|
|
|
const houseId =
|
|
interaction.client.user.id;
|
|
|
|
|
|
const [
|
|
playerBalance,
|
|
houseBalance
|
|
] =
|
|
await Promise.all([
|
|
getCookieBalance(
|
|
playerId
|
|
),
|
|
|
|
getCookieBalance(
|
|
houseId
|
|
)
|
|
]);
|
|
|
|
|
|
/*
|
|
* Balance may have changed while the player
|
|
* was choosing their bet type.
|
|
*/
|
|
|
|
if (
|
|
playerBalance <
|
|
bet
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"You no longer have enough Cookies for that wager."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* Worst payout depends on the selected wager.
|
|
*
|
|
* Red / Black / Odd / Even:
|
|
* x2
|
|
*
|
|
* Zero:
|
|
* x36
|
|
*
|
|
* The player's wager is transferred to the house
|
|
* before payout, so houseBalance + bet is available
|
|
* after accepting the wager.
|
|
*/
|
|
|
|
const maximumPayout =
|
|
bet *
|
|
choice.multiplier;
|
|
|
|
|
|
if (
|
|
houseBalance +
|
|
bet <
|
|
maximumPayout
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"The Crumb Saucer vault can't currently cover that Roulette wager."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* ========================================================
|
|
* TAKE WAGER
|
|
* ========================================================
|
|
*/
|
|
|
|
try {
|
|
await transferCookies(
|
|
playerId,
|
|
houseId,
|
|
bet
|
|
);
|
|
|
|
} catch (error) {
|
|
if (
|
|
error.message ===
|
|
"INSUFFICIENT_COOKIES"
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"Your balance changed before the wheel could spin."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
throw error;
|
|
}
|
|
|
|
|
|
/*
|
|
* ========================================================
|
|
* PSEUDO ANIMATION
|
|
* ========================================================
|
|
*/
|
|
|
|
await interaction.update({
|
|
embeds: [
|
|
buildSpinEmbed(
|
|
choice,
|
|
bet,
|
|
randomRouletteNumber(),
|
|
"The wheel begins to spin..."
|
|
)
|
|
],
|
|
|
|
components: []
|
|
});
|
|
|
|
|
|
await sleep(
|
|
650
|
|
);
|
|
|
|
|
|
await interaction.editReply({
|
|
embeds: [
|
|
buildSpinEmbed(
|
|
choice,
|
|
bet,
|
|
randomRouletteNumber(),
|
|
"Round and round..."
|
|
)
|
|
],
|
|
|
|
components: []
|
|
});
|
|
|
|
|
|
await sleep(
|
|
650
|
|
);
|
|
|
|
|
|
await interaction.editReply({
|
|
embeds: [
|
|
buildSpinEmbed(
|
|
choice,
|
|
bet,
|
|
randomRouletteNumber(),
|
|
"The ball is slowing down..."
|
|
)
|
|
],
|
|
|
|
components: []
|
|
});
|
|
|
|
|
|
await sleep(
|
|
750
|
|
);
|
|
|
|
|
|
/*
|
|
* ========================================================
|
|
* ACTUAL RESULT
|
|
* ========================================================
|
|
*/
|
|
|
|
const result =
|
|
randomRouletteNumber();
|
|
|
|
|
|
const won =
|
|
didRouletteBetWin(
|
|
choiceKey,
|
|
result
|
|
);
|
|
|
|
|
|
const payout =
|
|
won
|
|
? bet *
|
|
choice.multiplier
|
|
: 0;
|
|
|
|
|
|
/*
|
|
* ========================================================
|
|
* PAYOUT
|
|
* ========================================================
|
|
*/
|
|
|
|
if (
|
|
payout >
|
|
0
|
|
) {
|
|
try {
|
|
await transferCookies(
|
|
houseId,
|
|
playerId,
|
|
payout
|
|
);
|
|
|
|
} catch (error) {
|
|
console.error(
|
|
"[Roulette] Payout failed:",
|
|
error
|
|
);
|
|
|
|
|
|
return interaction.editReply({
|
|
embeds: [
|
|
new EmbedBuilder()
|
|
.setTitle(
|
|
"🎡 Roulette Error"
|
|
)
|
|
|
|
.setDescription(
|
|
"The wheel resolved, but the payout failed. Please contact an administrator."
|
|
)
|
|
|
|
.setFooter({
|
|
text:
|
|
`crumbRouletteResult:${playerId}:${bet}`
|
|
})
|
|
],
|
|
|
|
components:
|
|
buildResultButtons()
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
const [
|
|
playerAfter,
|
|
houseAfter
|
|
] =
|
|
await Promise.all([
|
|
getCookieBalance(
|
|
playerId
|
|
),
|
|
|
|
getCookieBalance(
|
|
houseId
|
|
)
|
|
]);
|
|
|
|
|
|
const profit =
|
|
payout -
|
|
bet;
|
|
|
|
|
|
const resultEmbed =
|
|
new EmbedBuilder()
|
|
.setTitle(
|
|
won
|
|
? "🎉 Roulette Winner!"
|
|
: "🎡 Roulette"
|
|
)
|
|
|
|
.setDescription(
|
|
[
|
|
"## The ball lands on...",
|
|
"",
|
|
`# ${formatRouletteNumber(result)}`,
|
|
"",
|
|
`${choice.emoji} Your bet: **${choice.name}**`,
|
|
"",
|
|
won
|
|
? `🎉 **YOU WIN ${payout.toLocaleString()} 🍪!**`
|
|
: "The house takes this one."
|
|
].join("\n")
|
|
)
|
|
|
|
.addFields(
|
|
{
|
|
name:
|
|
"Wager",
|
|
|
|
value:
|
|
`${bet.toLocaleString()} 🍪`,
|
|
|
|
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:
|
|
`${houseAfter.toLocaleString()} 🍪`,
|
|
|
|
inline:
|
|
true
|
|
}
|
|
)
|
|
|
|
/*
|
|
* Remember only:
|
|
*
|
|
* owner
|
|
* wager
|
|
*/
|
|
|
|
.setFooter({
|
|
text:
|
|
`crumbRouletteResult:${playerId}:${bet}`
|
|
});
|
|
|
|
|
|
return interaction.editReply({
|
|
embeds: [
|
|
resultEmbed
|
|
],
|
|
|
|
components:
|
|
buildResultButtons()
|
|
});
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* RESULT LOGIC
|
|
* ============================================================
|
|
*/
|
|
|
|
function didRouletteBetWin(
|
|
choice,
|
|
number
|
|
) {
|
|
switch (choice) {
|
|
case "Red":
|
|
|
|
return (
|
|
number !==
|
|
0
|
|
&&
|
|
RED_NUMBERS.has(
|
|
number
|
|
)
|
|
);
|
|
|
|
|
|
case "Black":
|
|
|
|
return (
|
|
number !==
|
|
0
|
|
&&
|
|
!RED_NUMBERS.has(
|
|
number
|
|
)
|
|
);
|
|
|
|
|
|
case "Odd":
|
|
|
|
return (
|
|
number !==
|
|
0
|
|
&&
|
|
number %
|
|
2 ===
|
|
1
|
|
);
|
|
|
|
|
|
case "Even":
|
|
|
|
return (
|
|
number !==
|
|
0
|
|
&&
|
|
number %
|
|
2 ===
|
|
0
|
|
);
|
|
|
|
|
|
case "Zero":
|
|
|
|
return (
|
|
number ===
|
|
0
|
|
);
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* DISPLAY
|
|
* ============================================================
|
|
*/
|
|
|
|
function buildSpinEmbed(
|
|
choice,
|
|
bet,
|
|
number,
|
|
status
|
|
) {
|
|
return new EmbedBuilder()
|
|
.setTitle(
|
|
"🎡 Crumb Saucer Roulette"
|
|
)
|
|
|
|
.setDescription(
|
|
[
|
|
"## 🎡 Spinning...",
|
|
"",
|
|
`### ${formatRouletteNumber(number)}`,
|
|
"",
|
|
`**${status}**`
|
|
].join("\n")
|
|
)
|
|
|
|
.addFields(
|
|
{
|
|
name:
|
|
"Bet",
|
|
|
|
value:
|
|
`${choice.emoji} ${choice.name}`,
|
|
|
|
inline:
|
|
true
|
|
},
|
|
|
|
{
|
|
name:
|
|
"Wager",
|
|
|
|
value:
|
|
`${bet.toLocaleString()} 🍪`,
|
|
|
|
inline:
|
|
true
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
function formatRouletteNumber(
|
|
number
|
|
) {
|
|
if (
|
|
number ===
|
|
0
|
|
) {
|
|
return "🟢 0";
|
|
}
|
|
|
|
|
|
if (
|
|
RED_NUMBERS.has(
|
|
number
|
|
)
|
|
) {
|
|
return `🔴 ${number}`;
|
|
}
|
|
|
|
|
|
return `⚫ ${number}`;
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* WAGER BUTTONS
|
|
* ============================================================
|
|
*/
|
|
|
|
function buildBetButtons() {
|
|
return [
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
...ROULETTE_BETS.map(
|
|
bet =>
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
`crumbRouletteBet${bet}`
|
|
)
|
|
|
|
.setLabel(
|
|
bet.toLocaleString()
|
|
)
|
|
|
|
.setEmoji(
|
|
"🍪"
|
|
)
|
|
|
|
.setStyle(
|
|
bet >=
|
|
500
|
|
? ButtonStyle.Primary
|
|
: ButtonStyle.Secondary
|
|
)
|
|
)
|
|
),
|
|
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbRouletteAllIn"
|
|
)
|
|
.setLabel(
|
|
"All In"
|
|
)
|
|
.setEmoji(
|
|
"🔥"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Danger
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbSaucerBack"
|
|
)
|
|
.setLabel(
|
|
"Back to Crumb Saucer"
|
|
)
|
|
.setEmoji(
|
|
"◀️"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Secondary
|
|
)
|
|
)
|
|
];
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* CHOICE BUTTONS
|
|
* ============================================================
|
|
*/
|
|
|
|
function buildChoiceButtons() {
|
|
return [
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbRouletteRed"
|
|
)
|
|
.setLabel(
|
|
"Red"
|
|
)
|
|
.setEmoji(
|
|
"🔴"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Danger
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbRouletteBlack"
|
|
)
|
|
.setLabel(
|
|
"Black"
|
|
)
|
|
.setEmoji(
|
|
"⚫"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Secondary
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbRouletteOdd"
|
|
)
|
|
.setLabel(
|
|
"Odd"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Primary
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbRouletteEven"
|
|
)
|
|
.setLabel(
|
|
"Even"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Primary
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbRouletteZero"
|
|
)
|
|
.setLabel(
|
|
"Zero"
|
|
)
|
|
.setEmoji(
|
|
"🟢"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Success
|
|
)
|
|
),
|
|
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbSaucerRoulette"
|
|
)
|
|
.setLabel(
|
|
"Change Wager"
|
|
)
|
|
.setEmoji(
|
|
"↩️"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Secondary
|
|
)
|
|
)
|
|
];
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* RESULT BUTTONS
|
|
* ============================================================
|
|
*/
|
|
|
|
function buildResultButtons() {
|
|
return [
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
/*
|
|
* Same wager.
|
|
*
|
|
* Player chooses Red/Black/etc again.
|
|
*/
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbRouletteRunItBack"
|
|
)
|
|
.setLabel(
|
|
"Run It Back"
|
|
)
|
|
.setEmoji(
|
|
"🔁"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Success
|
|
),
|
|
|
|
/*
|
|
* Return to wager selection.
|
|
*/
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbSaucerRoulette"
|
|
)
|
|
.setLabel(
|
|
"Change Bet"
|
|
)
|
|
.setEmoji(
|
|
"🎡"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Primary
|
|
),
|
|
|
|
/*
|
|
* Main Crumb Saucer.
|
|
*/
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbSaucerBack"
|
|
)
|
|
.setLabel(
|
|
"Crumb Saucer"
|
|
)
|
|
.setEmoji(
|
|
"◀️"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Secondary
|
|
)
|
|
)
|
|
];
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* SESSION OWNER
|
|
* ============================================================
|
|
*/
|
|
|
|
function getRouletteSessionOwner(
|
|
interaction
|
|
) {
|
|
const footer =
|
|
interaction.message
|
|
?.embeds?.[0]
|
|
?.footer
|
|
?.text;
|
|
|
|
|
|
const parts =
|
|
footer?.split(":")
|
|
??
|
|
[];
|
|
|
|
|
|
/*
|
|
* Main Saucer
|
|
*/
|
|
|
|
if (
|
|
parts[0] ===
|
|
"crumbSaucer"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
|
|
/*
|
|
* Roulette wager menu
|
|
*/
|
|
|
|
if (
|
|
parts[0] ===
|
|
"crumbRouletteMenu"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
|
|
/*
|
|
* Roulette choice menu.
|
|
*/
|
|
|
|
if (
|
|
parts[0] ===
|
|
"crumbRouletteBet"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
|
|
/*
|
|
* Roulette result.
|
|
*/
|
|
|
|
if (
|
|
parts[0] ===
|
|
"crumbRouletteResult"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* RANDOM
|
|
* ============================================================
|
|
*/
|
|
|
|
function randomRouletteNumber() {
|
|
return Math.floor(
|
|
Math.random() *
|
|
37
|
|
);
|
|
}
|
|
|
|
|
|
function sleep(
|
|
ms
|
|
) {
|
|
return new Promise(
|
|
resolve =>
|
|
setTimeout(
|
|
resolve,
|
|
ms
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* EXPORTS
|
|
* ============================================================
|
|
*/
|
|
|
|
module.exports = {
|
|
showRoulette,
|
|
|
|
chooseRouletteBet,
|
|
startRouletteAllIn,
|
|
showRouletteChoices,
|
|
|
|
playRoulette,
|
|
|
|
runRouletteBack
|
|
}; |