1026 lines
22 KiB
JavaScript
1026 lines
22 KiB
JavaScript
const {
|
|
EmbedBuilder,
|
|
ActionRowBuilder,
|
|
ButtonBuilder,
|
|
ButtonStyle
|
|
} = require("discord.js");
|
|
|
|
const {
|
|
getCookieBalance,
|
|
transferCookies,
|
|
temporaryEphemeralReply
|
|
} = require("./cookieEconomy");
|
|
|
|
const {
|
|
recordGameOutcome,
|
|
trackProfileEvent
|
|
} = require("./profileSystem");
|
|
|
|
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
|
|
}
|
|
};
|
|
|
|
const RED_NUMBERS =
|
|
new Set([
|
|
1, 3, 5, 7, 9,
|
|
12, 14, 16, 18,
|
|
19, 21, 23, 25,
|
|
27, 30, 32, 34, 36
|
|
]);
|
|
|
|
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()
|
|
});
|
|
}
|
|
|
|
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,
|
|
false
|
|
);
|
|
}
|
|
|
|
async function startRouletteAllIn(
|
|
interaction
|
|
) {
|
|
const ownerId =
|
|
getRouletteSessionOwner(
|
|
interaction
|
|
);
|
|
|
|
if (
|
|
ownerId !==
|
|
interaction.user.id
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"This isn't your Roulette table."
|
|
}
|
|
);
|
|
}
|
|
|
|
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."
|
|
}
|
|
);
|
|
}
|
|
|
|
return showRouletteChoices(
|
|
interaction,
|
|
balance,
|
|
true
|
|
);
|
|
}
|
|
|
|
async function showRouletteChoices(
|
|
interaction,
|
|
bet,
|
|
requestedAllIn = false,
|
|
source = "normal",
|
|
previousAllIn = false,
|
|
previousBet = 0
|
|
) {
|
|
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}:${requestedAllIn ? 1 : 0}:${source}:${previousAllIn ? 1 : 0}:${previousBet}`
|
|
});
|
|
|
|
return interaction.update({
|
|
embeds: [embed],
|
|
components:
|
|
buildChoiceButtons()
|
|
});
|
|
}
|
|
|
|
async function runRouletteBack(
|
|
interaction
|
|
) {
|
|
const footer =
|
|
interaction.message
|
|
?.embeds?.[0]
|
|
?.footer
|
|
?.text;
|
|
|
|
const parts =
|
|
footer?.split(":") ?? [];
|
|
|
|
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]);
|
|
|
|
const previousAllIn =
|
|
parts[3] === "1";
|
|
|
|
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."
|
|
}
|
|
);
|
|
}
|
|
|
|
return showRouletteChoices(
|
|
interaction,
|
|
bet,
|
|
false,
|
|
"run_it_back",
|
|
previousAllIn,
|
|
bet
|
|
);
|
|
}
|
|
|
|
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]);
|
|
|
|
const source =
|
|
parts[4] || "normal";
|
|
|
|
const previousAllIn =
|
|
parts[5] === "1";
|
|
|
|
const previousBet =
|
|
Number(parts[6] ?? 0);
|
|
|
|
if (
|
|
ownerId !==
|
|
interaction.user.id
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"This isn't your Roulette table."
|
|
}
|
|
);
|
|
}
|
|
|
|
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)
|
|
]);
|
|
|
|
if (playerBalance < bet) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"You no longer have enough Cookies for that 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."
|
|
}
|
|
);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
const allIn =
|
|
bet === playerBalance;
|
|
|
|
await trackProfileEvent(
|
|
interaction,
|
|
playerId,
|
|
{
|
|
type: "game_start",
|
|
game: "roulette",
|
|
source,
|
|
bet,
|
|
allIn,
|
|
previousAllIn,
|
|
previousBet
|
|
}
|
|
);
|
|
|
|
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);
|
|
|
|
const result =
|
|
randomRouletteNumber();
|
|
|
|
const won =
|
|
didRouletteBetWin(
|
|
choiceKey,
|
|
result
|
|
);
|
|
|
|
const payout =
|
|
won
|
|
? bet *
|
|
choice.multiplier
|
|
: 0;
|
|
|
|
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;
|
|
|
|
await recordGameOutcome(
|
|
interaction,
|
|
playerId,
|
|
{
|
|
game:
|
|
"roulette",
|
|
result:
|
|
profit > 0
|
|
? "win"
|
|
: profit < 0
|
|
? "loss"
|
|
: "push",
|
|
profit,
|
|
zero:
|
|
won &&
|
|
choiceKey ===
|
|
"Zero",
|
|
allIn
|
|
}
|
|
);
|
|
|
|
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
|
|
}
|
|
)
|
|
.setFooter({
|
|
text:
|
|
`crumbRouletteResult:${playerId}:${bet}:${allIn ? 1 : 0}`
|
|
});
|
|
|
|
return interaction.editReply({
|
|
embeds: [resultEmbed],
|
|
components:
|
|
buildResultButtons()
|
|
});
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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}`;
|
|
}
|
|
|
|
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
|
|
)
|
|
)
|
|
];
|
|
}
|
|
|
|
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
|
|
)
|
|
)
|
|
];
|
|
}
|
|
|
|
function buildResultButtons() {
|
|
return [
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbRouletteRunItBack"
|
|
)
|
|
.setLabel(
|
|
"Run It Back"
|
|
)
|
|
.setEmoji("🔁")
|
|
.setStyle(
|
|
ButtonStyle.Success
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbSaucerRoulette"
|
|
)
|
|
.setLabel(
|
|
"Change Bet"
|
|
)
|
|
.setEmoji("🎡")
|
|
.setStyle(
|
|
ButtonStyle.Primary
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"crumbSaucerBack"
|
|
)
|
|
.setLabel(
|
|
"Crumb Saucer"
|
|
)
|
|
.setEmoji("◀️")
|
|
.setStyle(
|
|
ButtonStyle.Secondary
|
|
)
|
|
)
|
|
];
|
|
}
|
|
|
|
function getRouletteSessionOwner(
|
|
interaction
|
|
) {
|
|
const footer =
|
|
interaction.message
|
|
?.embeds?.[0]
|
|
?.footer
|
|
?.text;
|
|
|
|
const parts =
|
|
footer?.split(":") ?? [];
|
|
|
|
if (parts[0] === "crumbSaucer") {
|
|
return parts[1];
|
|
}
|
|
|
|
if (
|
|
parts[0] ===
|
|
"crumbRouletteMenu"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
if (
|
|
parts[0] ===
|
|
"crumbRouletteBet"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
if (
|
|
parts[0] ===
|
|
"crumbRouletteResult"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function randomRouletteNumber() {
|
|
return Math.floor(
|
|
Math.random() * 37
|
|
);
|
|
}
|
|
|
|
function sleep(ms) {
|
|
return new Promise(
|
|
resolve =>
|
|
setTimeout(
|
|
resolve,
|
|
ms
|
|
)
|
|
);
|
|
}
|
|
|
|
module.exports = {
|
|
showRoulette,
|
|
chooseRouletteBet,
|
|
startRouletteAllIn,
|
|
showRouletteChoices,
|
|
playRoulette,
|
|
runRouletteBack
|
|
};
|