added runtiback and allin

This commit is contained in:
DeSqBlocki
2026-08-22 19:52:47 +02:00
parent 1fd73538fa
commit 81ef97370c
14 changed files with 1463 additions and 444 deletions
+401 -70
View File
@@ -29,62 +29,33 @@ const ROULETTE_BETS = [
const ROULETTE_CHOICES = {
Red: {
name:
"Red",
emoji:
"🔴",
multiplier:
2
name: "Red",
emoji: "🔴",
multiplier: 2
},
Black: {
name:
"Black",
emoji:
"⚫",
multiplier:
2
name: "Black",
emoji: "⚫",
multiplier: 2
},
Odd: {
name:
"Odd",
emoji:
"🔢",
multiplier:
2
name: "Odd",
emoji: "🔢",
multiplier: 2
},
Even: {
name:
"Even",
emoji:
"2️⃣",
multiplier:
2
name: "Even",
emoji: "2️⃣",
multiplier: 2
},
Zero: {
name:
"Zero",
emoji:
"🟢",
multiplier:
36
name: "Zero",
emoji: "🟢",
multiplier: 36
}
};
@@ -156,19 +127,21 @@ async function showRoulette(
.setTitle(
"🎡 Crumb Saucer Roulette"
)
.setDescription(
[
"European Roulette — **0 to 36**.",
"",
"Choose your wager.",
"",
"🔴 **Red** — ×2",
"⚫ **Black** — ×2",
"🔢 **Odd** — ×2",
"2️⃣ **Even** — ×2",
"🟢 **Zero** — ×36"
"🔴 **Red** — x2",
"⚫ **Black** — x2",
"🔢 **Odd** — x2",
"2️⃣ **Even** — x2",
"🟢 **Zero** — x36"
].join("\n")
)
.addFields({
name:
"Your Vault",
@@ -176,6 +149,7 @@ async function showRoulette(
value:
`**${balance.toLocaleString()} 🍪**`
})
.setFooter({
text:
`crumbRouletteMenu:${interaction.user.id}`
@@ -195,7 +169,7 @@ async function showRoulette(
/*
* ============================================================
* CHOOSE WAGER
* CHOOSE NORMAL WAGER
* ============================================================
*/
@@ -238,6 +212,114 @@ async function chooseRouletteBet(
}
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
@@ -263,19 +345,29 @@ async function chooseRouletteBet(
.setTitle(
"🎡 Crumb Saucer Roulette"
)
.setDescription(
[
`Wager: **${bet.toLocaleString()} 🍪**`,
"",
"Where do you want to place your Cookies?",
"",
"🔴 **Red** — ×2",
"⚫ **Black** — ×2",
"🔢 **Odd** — ×2",
"2️⃣ **Even** — ×2",
"🟢 **Zero** — ×36"
"🔴 **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}`
@@ -293,6 +385,105 @@ async function chooseRouletteBet(
}
/*
* ============================================================
* 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
@@ -322,7 +513,7 @@ async function playRoulette(
const footer =
interaction.message
.embeds[0]
?.embeds?.[0]
?.footer
?.text;
@@ -371,10 +562,22 @@ async function playRoulette(
}
/*
* 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 (
!ROULETTE_BETS.includes(
!Number.isSafeInteger(
bet
)
||
bet <=
0
) {
return temporaryEphemeralReply(
interaction,
@@ -409,6 +612,11 @@ async function playRoulette(
]);
/*
* Balance may have changed while the player
* was choosing their bet type.
*/
if (
playerBalance <
bet
@@ -424,11 +632,17 @@ async function playRoulette(
/*
* Worst payout is Zero at x36.
* Worst payout depends on the selected wager.
*
* Once the player's wager is transferred to the house,
* the house must still be able to cover the remaining
* potential payout.
* 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 =
@@ -452,7 +666,9 @@ async function playRoulette(
/*
* Take wager.
* ========================================================
* TAKE WAGER
* ========================================================
*/
try {
@@ -545,8 +761,9 @@ async function playRoulette(
/*
* The real result is only generated after
* the animation completes.
* ========================================================
* ACTUAL RESULT
* ========================================================
*/
const result =
@@ -567,6 +784,12 @@ async function playRoulette(
: 0;
/*
* ========================================================
* PAYOUT
* ========================================================
*/
if (
payout >
0
@@ -591,9 +814,15 @@ async function playRoulette(
.setTitle(
"🎡 Roulette Error"
)
.setDescription(
"The wheel resolved, but the payout failed. Please contact an administrator."
)
.setFooter({
text:
`crumbRouletteResult:${playerId}:${bet}`
})
],
components:
@@ -630,6 +859,7 @@ async function playRoulette(
? "🎉 Roulette Winner!"
: "🎡 Roulette"
)
.setDescription(
[
"## The ball lands on...",
@@ -643,6 +873,7 @@ async function playRoulette(
: "The house takes this one."
].join("\n")
)
.addFields(
{
name:
@@ -699,9 +930,17 @@ async function playRoulette(
true
}
)
/*
* Remember only:
*
* owner
* wager
*/
.setFooter({
text:
`crumbRouletteResult:${interaction.user.id}`
`crumbRouletteResult:${playerId}:${bet}`
});
@@ -728,6 +967,7 @@ function didRouletteBetWin(
) {
switch (choice) {
case "Red":
return (
number !==
0
@@ -739,6 +979,7 @@ function didRouletteBetWin(
case "Black":
return (
number !==
0
@@ -750,6 +991,7 @@ function didRouletteBetWin(
case "Odd":
return (
number !==
0
@@ -761,6 +1003,7 @@ function didRouletteBetWin(
case "Even":
return (
number !==
0
@@ -772,6 +1015,7 @@ function didRouletteBetWin(
case "Zero":
return (
number ===
0
@@ -779,6 +1023,7 @@ function didRouletteBetWin(
default:
return false;
}
}
@@ -800,6 +1045,7 @@ function buildSpinEmbed(
.setTitle(
"🎡 Crumb Saucer Roulette"
)
.setDescription(
[
"## 🎡 Spinning...",
@@ -809,6 +1055,7 @@ function buildSpinEmbed(
`**${status}**`
].join("\n")
)
.addFields(
{
name:
@@ -861,7 +1108,7 @@ function formatRouletteNumber(
/*
* ============================================================
* BUTTON BUILDERS
* WAGER BUTTONS
* ============================================================
*/
@@ -875,12 +1122,15 @@ function buildBetButtons() {
.setCustomId(
`crumbRouletteBet${bet}`
)
.setLabel(
bet.toLocaleString()
)
.setEmoji(
"🍪"
)
.setStyle(
bet >=
500
@@ -892,6 +1142,20 @@ function buildBetButtons() {
new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId(
"crumbRouletteAllIn"
)
.setLabel(
"All In"
)
.setEmoji(
"🔥"
)
.setStyle(
ButtonStyle.Danger
),
new ButtonBuilder()
.setCustomId(
"crumbSaucerBack"
@@ -910,6 +1174,12 @@ function buildBetButtons() {
}
/*
* ============================================================
* CHOICE BUTTONS
* ============================================================
*/
function buildChoiceButtons() {
return [
new ActionRowBuilder()
@@ -999,16 +1269,46 @@ function buildChoiceButtons() {
}
/*
* ============================================================
* 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(
"Play Again"
"Change Bet"
)
.setEmoji(
"🎡"
@@ -1017,6 +1317,10 @@ function buildResultButtons() {
ButtonStyle.Primary
),
/*
* Main Crumb Saucer.
*/
new ButtonBuilder()
.setCustomId(
"crumbSaucerBack"
@@ -1046,7 +1350,7 @@ function getRouletteSessionOwner(
) {
const footer =
interaction.message
.embeds[0]
?.embeds?.[0]
?.footer
?.text;
@@ -1060,6 +1364,7 @@ function getRouletteSessionOwner(
/*
* Main Saucer
*/
if (
parts[0] ===
"crumbSaucer"
@@ -1071,6 +1376,7 @@ function getRouletteSessionOwner(
/*
* Roulette wager menu
*/
if (
parts[0] ===
"crumbRouletteMenu"
@@ -1080,8 +1386,21 @@ function getRouletteSessionOwner(
/*
* Roulette result
* Roulette choice menu.
*/
if (
parts[0] ===
"crumbRouletteBet"
) {
return parts[1];
}
/*
* Roulette result.
*/
if (
parts[0] ===
"crumbRouletteResult"
@@ -1121,8 +1440,20 @@ function sleep(
}
/*
* ============================================================
* EXPORTS
* ============================================================
*/
module.exports = {
showRoulette,
chooseRouletteBet,
playRoulette
startRouletteAllIn,
showRouletteChoices,
playRoulette,
runRouletteBack
};