added runtiback and allin
This commit is contained in:
+349
-121
@@ -14,7 +14,9 @@ const {
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* SLOT CONFIG
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
const SLOT_BETS = [
|
||||
@@ -98,6 +100,40 @@ const SLOT_OUTCOMES = [
|
||||
async function showCrumbSaucer(
|
||||
interaction
|
||||
) {
|
||||
/*
|
||||
* If this is being called from a button,
|
||||
* verify that the player owns the current
|
||||
* Crumb Saucer / game session.
|
||||
*
|
||||
* This prevents another user from pressing
|
||||
* "Crumb Saucer" / "Back" on somebody else's
|
||||
* game message and taking over their session.
|
||||
*/
|
||||
|
||||
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
|
||||
@@ -116,11 +152,8 @@ async function showCrumbSaucer(
|
||||
|
||||
|
||||
/*
|
||||
* Slash command:
|
||||
* reply normally.
|
||||
*
|
||||
* Button:
|
||||
* update existing menu message.
|
||||
* update existing menu/game message.
|
||||
*/
|
||||
|
||||
if (
|
||||
@@ -136,6 +169,11 @@ async function showCrumbSaucer(
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Slash command:
|
||||
* create a new Crumb Saucer.
|
||||
*/
|
||||
|
||||
return interaction.reply({
|
||||
embeds: [
|
||||
embed
|
||||
@@ -145,51 +183,13 @@ async function showCrumbSaucer(
|
||||
});
|
||||
}
|
||||
|
||||
function getSlotsSessionOwner(
|
||||
interaction
|
||||
) {
|
||||
const footer =
|
||||
interaction.message
|
||||
.embeds[0]
|
||||
?.footer
|
||||
?.text;
|
||||
|
||||
|
||||
const parts =
|
||||
footer?.split(":")
|
||||
??
|
||||
[];
|
||||
|
||||
|
||||
/*
|
||||
* Main Crumb Saucer
|
||||
*/
|
||||
if (
|
||||
parts[0] ===
|
||||
"crumbSaucer"
|
||||
) {
|
||||
return parts[1];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Slots menu/result
|
||||
*/
|
||||
if (
|
||||
parts[0] ===
|
||||
"crumbSaucerSlots"
|
||||
) {
|
||||
return parts[1];
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
* ============================================================
|
||||
* SLOT MENU
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
async function showSlots(
|
||||
interaction
|
||||
) {
|
||||
@@ -224,19 +224,21 @@ async function showSlots(
|
||||
.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"
|
||||
"🍋 **Triple Lemon** — x1.5",
|
||||
"🍒 **Triple Cherry** — x2",
|
||||
"🍪 **Triple Cookie** — x3",
|
||||
"⭐ **Triple Star** — x5",
|
||||
"💎 **Jackpot** — x10"
|
||||
].join("\n")
|
||||
)
|
||||
|
||||
.addFields({
|
||||
name:
|
||||
"Your Vault",
|
||||
@@ -244,6 +246,7 @@ async function showSlots(
|
||||
value:
|
||||
`**${balance.toLocaleString()} 🍪**`
|
||||
})
|
||||
|
||||
.setFooter({
|
||||
text:
|
||||
`crumbSaucerSlots:${interaction.user.id}`
|
||||
@@ -260,6 +263,7 @@ async function showSlots(
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* PLAY SLOTS
|
||||
@@ -271,7 +275,7 @@ async function playSlots(
|
||||
bet
|
||||
) {
|
||||
const ownerId =
|
||||
getSlotsOwner(
|
||||
getSlotsSessionOwner(
|
||||
interaction
|
||||
);
|
||||
|
||||
@@ -308,6 +312,7 @@ async function playSlots(
|
||||
const playerId =
|
||||
interaction.user.id;
|
||||
|
||||
|
||||
const vaultId =
|
||||
interaction.client.user.id;
|
||||
|
||||
@@ -388,6 +393,7 @@ async function playSlots(
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -409,11 +415,6 @@ async function playSlots(
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* A few slow edits give a slot-machine feel
|
||||
* without hammering the Discord API.
|
||||
*/
|
||||
|
||||
await sleep(
|
||||
700
|
||||
);
|
||||
@@ -478,13 +479,11 @@ async function playSlots(
|
||||
|
||||
/*
|
||||
* House pays winnings.
|
||||
*
|
||||
* The original stake was already transferred
|
||||
* to the house, so x2 means a total payout of 2x.
|
||||
*/
|
||||
|
||||
if (
|
||||
payout > 0
|
||||
payout >
|
||||
0
|
||||
) {
|
||||
try {
|
||||
await transferCookies(
|
||||
@@ -509,6 +508,10 @@ async function playSlots(
|
||||
.setDescription(
|
||||
"The reels stopped, but the payout system had a problem. Please contact an administrator."
|
||||
)
|
||||
.setFooter({
|
||||
text:
|
||||
`crumbSaucerSlotsResult:${playerId}:${bet}`
|
||||
})
|
||||
],
|
||||
|
||||
components:
|
||||
@@ -543,6 +546,7 @@ async function playSlots(
|
||||
.setTitle(
|
||||
"🎰 Crumb Saucer Slots"
|
||||
)
|
||||
|
||||
.setDescription(
|
||||
[
|
||||
buildSlotDisplay(
|
||||
@@ -552,6 +556,7 @@ async function playSlots(
|
||||
`### ${getSlotResultName(outcome)}`
|
||||
].join("\n")
|
||||
)
|
||||
|
||||
.addFields(
|
||||
{
|
||||
name:
|
||||
@@ -569,7 +574,7 @@ async function playSlots(
|
||||
"Multiplier",
|
||||
|
||||
value:
|
||||
`×${outcome.multiplier}`,
|
||||
`x${outcome.multiplier}`,
|
||||
|
||||
inline:
|
||||
true
|
||||
@@ -619,9 +624,17 @@ async function playSlots(
|
||||
true
|
||||
}
|
||||
)
|
||||
|
||||
/*
|
||||
* Store owner + previous wager.
|
||||
*
|
||||
* Run It Back can now replay the exact
|
||||
* same wager without opening the bet menu.
|
||||
*/
|
||||
|
||||
.setFooter({
|
||||
text:
|
||||
`crumbSaucerSlots:${interaction.user.id}`
|
||||
`crumbSaucerSlotsResult:${playerId}:${bet}`
|
||||
});
|
||||
|
||||
|
||||
@@ -636,6 +649,88 @@ async function playSlots(
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* RUN IT BACK
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
async function runSlotsBack(
|
||||
interaction
|
||||
) {
|
||||
const footer =
|
||||
interaction.message
|
||||
?.embeds?.[0]
|
||||
?.footer
|
||||
?.text;
|
||||
|
||||
|
||||
const parts =
|
||||
footer?.split(":")
|
||||
??
|
||||
[];
|
||||
|
||||
|
||||
if (
|
||||
parts[0] !==
|
||||
"crumbSaucerSlotsResult"
|
||||
) {
|
||||
return temporaryEphemeralReply(
|
||||
interaction,
|
||||
{
|
||||
content:
|
||||
"This Slots result can no longer be replayed."
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const ownerId =
|
||||
parts[1];
|
||||
|
||||
|
||||
const bet =
|
||||
Number(
|
||||
parts[2]
|
||||
);
|
||||
|
||||
|
||||
if (
|
||||
ownerId !==
|
||||
interaction.user.id
|
||||
) {
|
||||
return temporaryEphemeralReply(
|
||||
interaction,
|
||||
{
|
||||
content:
|
||||
"These aren't your slots."
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
!SLOT_BETS.includes(
|
||||
bet
|
||||
)
|
||||
) {
|
||||
return temporaryEphemeralReply(
|
||||
interaction,
|
||||
{
|
||||
content:
|
||||
"The previous wager is no longer available."
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return playSlots(
|
||||
interaction,
|
||||
bet
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* MAIN MENU EMBED
|
||||
@@ -650,6 +745,7 @@ function buildMainMenuEmbed(
|
||||
.setTitle(
|
||||
"🎰 The Crumb Saucer"
|
||||
)
|
||||
|
||||
.setDescription(
|
||||
[
|
||||
`Welcome, ${user}!`,
|
||||
@@ -672,6 +768,7 @@ function buildMainMenuEmbed(
|
||||
"*More attractions coming soon... make a lala offering or buy me a white monster*"
|
||||
].join("\n")
|
||||
)
|
||||
|
||||
.addFields({
|
||||
name:
|
||||
"Your Vault",
|
||||
@@ -679,6 +776,7 @@ function buildMainMenuEmbed(
|
||||
value:
|
||||
`**${balance.toLocaleString()} 🍪**`
|
||||
})
|
||||
|
||||
.setFooter({
|
||||
text:
|
||||
`crumbSaucer:${user.id}`
|
||||
@@ -688,7 +786,7 @@ function buildMainMenuEmbed(
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* BUTTONS
|
||||
* MAIN MENU BUTTONS
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
@@ -755,6 +853,13 @@ function buildMainMenuButtons() {
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* SLOT BET BUTTONS
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function buildSlotBetButtons() {
|
||||
return [
|
||||
new ActionRowBuilder()
|
||||
@@ -850,16 +955,44 @@ function buildSlotBetButtons() {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* SLOT RESULT BUTTONS
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function buildResultButtons() {
|
||||
return [
|
||||
new ActionRowBuilder()
|
||||
.addComponents(
|
||||
/*
|
||||
* Exact same wager immediately.
|
||||
*/
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerSlotsRunItBack"
|
||||
)
|
||||
.setLabel(
|
||||
"Run It Back"
|
||||
)
|
||||
.setEmoji(
|
||||
"🔁"
|
||||
)
|
||||
.setStyle(
|
||||
ButtonStyle.Success
|
||||
),
|
||||
|
||||
/*
|
||||
* Return to wager selection.
|
||||
*/
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerSlots"
|
||||
)
|
||||
.setLabel(
|
||||
"Play Again"
|
||||
"Change Bet"
|
||||
)
|
||||
.setEmoji(
|
||||
"🎰"
|
||||
@@ -868,6 +1001,10 @@ function buildResultButtons() {
|
||||
ButtonStyle.Primary
|
||||
),
|
||||
|
||||
/*
|
||||
* Main Saucer.
|
||||
*/
|
||||
|
||||
new ButtonBuilder()
|
||||
.setCustomId(
|
||||
"crumbSaucerBack"
|
||||
@@ -920,7 +1057,8 @@ function rollSlotOutcome() {
|
||||
|
||||
|
||||
if (
|
||||
roll <= 0
|
||||
roll <=
|
||||
0
|
||||
) {
|
||||
return outcome;
|
||||
}
|
||||
@@ -959,10 +1097,6 @@ function generateOutcomeGrid(
|
||||
generateRandomGrid();
|
||||
|
||||
|
||||
/*
|
||||
* Winning middle row.
|
||||
*/
|
||||
|
||||
if (
|
||||
outcome.type ===
|
||||
"triple"
|
||||
@@ -978,10 +1112,6 @@ function generateOutcomeGrid(
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Pair.
|
||||
*/
|
||||
|
||||
if (
|
||||
outcome.type ===
|
||||
"pair"
|
||||
@@ -1002,14 +1132,11 @@ function generateOutcomeGrid(
|
||||
);
|
||||
|
||||
} while (
|
||||
other === symbol
|
||||
other ===
|
||||
symbol
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Randomize the location of the odd symbol.
|
||||
*/
|
||||
|
||||
const oddPosition =
|
||||
Math.floor(
|
||||
Math.random() *
|
||||
@@ -1034,11 +1161,6 @@ function generateOutcomeGrid(
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Loss:
|
||||
* ensure all three center symbols differ.
|
||||
*/
|
||||
|
||||
let line;
|
||||
|
||||
|
||||
@@ -1095,6 +1217,7 @@ function buildSpinningEmbed(
|
||||
.setTitle(
|
||||
"🎰 Crumb Saucer Slots"
|
||||
)
|
||||
|
||||
.setDescription(
|
||||
[
|
||||
buildSlotDisplay(
|
||||
@@ -1104,6 +1227,7 @@ function buildSpinningEmbed(
|
||||
`**${status}**`
|
||||
].join("\n")
|
||||
)
|
||||
|
||||
.addFields({
|
||||
name:
|
||||
"Bet",
|
||||
@@ -1134,23 +1258,28 @@ function getSlotResultName(
|
||||
|
||||
|
||||
switch (
|
||||
outcome.symbol
|
||||
outcome.symbol
|
||||
) {
|
||||
case "🍋":
|
||||
return "🍋 Triple Lemon!";
|
||||
|
||||
|
||||
case "🍒":
|
||||
return "🍒 Triple Cherry!";
|
||||
|
||||
|
||||
case "🍪":
|
||||
return "🍪 Triple Cookie!";
|
||||
|
||||
|
||||
case "⭐":
|
||||
return "⭐ Triple Star!";
|
||||
|
||||
|
||||
case "💎":
|
||||
return "💎 JACKPOT! 💎";
|
||||
|
||||
|
||||
default:
|
||||
return "Winner!";
|
||||
}
|
||||
@@ -1159,75 +1288,166 @@ function getSlotResultName(
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* OWNER RESOLUTION
|
||||
* SESSION OWNER RESOLUTION
|
||||
* ============================================================
|
||||
*
|
||||
* This intentionally understands every Crumb Saucer
|
||||
* screen that can navigate back to the main menu.
|
||||
*
|
||||
* That prevents another player from pressing the
|
||||
* Back / Crumb Saucer button on somebody else's
|
||||
* public interaction.
|
||||
*/
|
||||
|
||||
function getCrumbSaucerSessionOwner(
|
||||
interaction
|
||||
) {
|
||||
const footer =
|
||||
interaction.message
|
||||
?.embeds?.[0]
|
||||
?.footer
|
||||
?.text;
|
||||
|
||||
|
||||
const parts =
|
||||
footer?.split(":")
|
||||
??
|
||||
[];
|
||||
|
||||
|
||||
switch (
|
||||
parts[0]
|
||||
) {
|
||||
/*
|
||||
* Main menu
|
||||
*/
|
||||
case "crumbSaucer":
|
||||
|
||||
/*
|
||||
* Slots wager menu
|
||||
*/
|
||||
case "crumbSaucerSlots":
|
||||
|
||||
/*
|
||||
* Slots completed result
|
||||
*/
|
||||
case "crumbSaucerSlotsResult":
|
||||
|
||||
/*
|
||||
* Blackjack wager/result menu
|
||||
*/
|
||||
case "crumbSaucerBlackjack":
|
||||
|
||||
case "crumbSaucerBlackjackResult":
|
||||
|
||||
/*
|
||||
* Roulette
|
||||
*/
|
||||
case "crumbRouletteMenu":
|
||||
|
||||
case "crumbRouletteBet":
|
||||
|
||||
case "crumbRouletteResult":
|
||||
|
||||
/*
|
||||
* Heist
|
||||
*/
|
||||
case "crumbSaucerHeist":
|
||||
|
||||
case "cookieHeist":
|
||||
|
||||
return parts[1];
|
||||
|
||||
|
||||
/*
|
||||
* Active Blackjack footer:
|
||||
*
|
||||
* crumbBlackjack:<gameId>:<userId>
|
||||
*/
|
||||
|
||||
case "crumbBlackjack":
|
||||
|
||||
return parts[2];
|
||||
|
||||
|
||||
default:
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* SLOT OWNER RESOLUTION
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function getMenuOwner(
|
||||
function getSlotsSessionOwner(
|
||||
interaction
|
||||
) {
|
||||
const footer =
|
||||
interaction.message
|
||||
.embeds[0]
|
||||
?.embeds?.[0]
|
||||
?.footer
|
||||
?.text;
|
||||
|
||||
|
||||
const [
|
||||
type,
|
||||
userId
|
||||
] =
|
||||
footer
|
||||
?.split(":")
|
||||
const parts =
|
||||
footer?.split(":")
|
||||
??
|
||||
[];
|
||||
|
||||
|
||||
/*
|
||||
* Main Crumb Saucer.
|
||||
*/
|
||||
|
||||
if (
|
||||
type !==
|
||||
parts[0] ===
|
||||
"crumbSaucer"
|
||||
) {
|
||||
return null;
|
||||
return parts[1];
|
||||
}
|
||||
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
|
||||
function getSlotsOwner(
|
||||
interaction
|
||||
) {
|
||||
const footer =
|
||||
interaction.message
|
||||
.embeds[0]
|
||||
?.footer
|
||||
?.text;
|
||||
|
||||
|
||||
const [
|
||||
type,
|
||||
userId
|
||||
] =
|
||||
footer
|
||||
?.split(":")
|
||||
??
|
||||
[];
|
||||
|
||||
/*
|
||||
* Slots wager menu.
|
||||
*/
|
||||
|
||||
if (
|
||||
type !==
|
||||
parts[0] ===
|
||||
"crumbSaucerSlots"
|
||||
) {
|
||||
return null;
|
||||
return parts[1];
|
||||
}
|
||||
|
||||
|
||||
return userId;
|
||||
/*
|
||||
* Completed Slots result.
|
||||
*/
|
||||
|
||||
if (
|
||||
parts[0] ===
|
||||
"crumbSaucerSlotsResult"
|
||||
) {
|
||||
return parts[1];
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function sleep(ms) {
|
||||
/*
|
||||
* ============================================================
|
||||
* SLEEP
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
function sleep(
|
||||
ms
|
||||
) {
|
||||
return new Promise(
|
||||
resolve =>
|
||||
setTimeout(
|
||||
@@ -1238,8 +1458,16 @@ function sleep(ms) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* EXPORTS
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
showCrumbSaucer,
|
||||
|
||||
showSlots,
|
||||
playSlots
|
||||
playSlots,
|
||||
runSlotsBack
|
||||
};
|
||||
Reference in New Issue
Block a user