975 lines
18 KiB
JavaScript
975 lines
18 KiB
JavaScript
const {
|
|
EmbedBuilder,
|
|
ActionRowBuilder,
|
|
ButtonBuilder,
|
|
ButtonStyle
|
|
} = require("discord.js");
|
|
|
|
const {
|
|
getNutBalance,
|
|
transferNuts,
|
|
temporaryEphemeralReply
|
|
} = require("./nutEconomy");
|
|
|
|
|
|
const ROULETTE_BETS = [
|
|
10,
|
|
50,
|
|
100,
|
|
500,
|
|
1000
|
|
];
|
|
|
|
|
|
const CHOICES = {
|
|
Red: {
|
|
name:
|
|
"Red",
|
|
|
|
emoji:
|
|
"🔴",
|
|
|
|
multiplier:
|
|
2
|
|
},
|
|
|
|
Black: {
|
|
name:
|
|
"Black",
|
|
|
|
emoji:
|
|
"⚫",
|
|
|
|
multiplier:
|
|
2
|
|
},
|
|
|
|
Odd: {
|
|
name:
|
|
"Odd",
|
|
|
|
emoji:
|
|
"1️⃣",
|
|
|
|
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
|
|
]);
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* MENU
|
|
* ============================================================
|
|
*/
|
|
|
|
async function showNutRoulette(
|
|
interaction
|
|
) {
|
|
const ownerId =
|
|
getRouletteOwner(
|
|
interaction
|
|
);
|
|
|
|
|
|
if (
|
|
ownerId !==
|
|
interaction.user.id
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"Das ist nicht deine Nut-Hub-Session."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const balance =
|
|
await getNutBalance(
|
|
interaction.user.id
|
|
);
|
|
|
|
|
|
const embed =
|
|
new EmbedBuilder()
|
|
.setTitle(
|
|
"🎡 Nut Roulette"
|
|
)
|
|
|
|
.setDescription(
|
|
[
|
|
"European Roulette — **0 bis 36**.",
|
|
"",
|
|
"🔴 **Red** — x2",
|
|
"⚫ **Black** — x2",
|
|
"1️⃣ **Odd** — x2",
|
|
"2️⃣ **Even** — x2",
|
|
"🟢 **Zero** — x36",
|
|
"",
|
|
"Choose your wager."
|
|
].join("\n")
|
|
)
|
|
|
|
.addFields({
|
|
name:
|
|
"Deine Nüsse",
|
|
|
|
value:
|
|
`${balance.toLocaleString()} 🥜`
|
|
})
|
|
|
|
.setFooter({
|
|
text:
|
|
`nutRouletteMenu:${interaction.user.id}`
|
|
});
|
|
|
|
|
|
return interaction.update({
|
|
embeds: [
|
|
embed
|
|
],
|
|
|
|
components:
|
|
buildBetButtons()
|
|
});
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* WAGER
|
|
* ============================================================
|
|
*/
|
|
|
|
async function chooseNutRouletteBet(
|
|
interaction,
|
|
bet
|
|
) {
|
|
const ownerId =
|
|
getRouletteOwner(
|
|
interaction
|
|
);
|
|
|
|
|
|
if (
|
|
ownerId !==
|
|
interaction.user.id
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"Das ist nicht dein Roulette-Tisch."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
if (
|
|
!ROULETTE_BETS.includes(
|
|
bet
|
|
)
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"Dieser Einsatz ist ungültig."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const balance =
|
|
await getNutBalance(
|
|
interaction.user.id
|
|
);
|
|
|
|
|
|
if (
|
|
balance <
|
|
bet
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
`Du brauchst **${bet.toLocaleString()} Nüsse**.`
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const embed =
|
|
new EmbedBuilder()
|
|
.setTitle(
|
|
"🎡 Nut Roulette"
|
|
)
|
|
|
|
.setDescription(
|
|
[
|
|
`Einsatz: **${bet.toLocaleString()} 🥜**`,
|
|
"",
|
|
"Wo sollen deine Nüsse landen?",
|
|
"",
|
|
"🔴 Red",
|
|
"⚫ Black",
|
|
"1️⃣ Odd",
|
|
"2️⃣ Even",
|
|
"🟢 Zero"
|
|
].join("\n")
|
|
)
|
|
|
|
.setFooter({
|
|
text:
|
|
`nutRouletteBet:${interaction.user.id}:${bet}`
|
|
});
|
|
|
|
|
|
return interaction.update({
|
|
embeds: [
|
|
embed
|
|
],
|
|
|
|
components:
|
|
buildChoiceButtons()
|
|
});
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* PLAY
|
|
* ============================================================
|
|
*/
|
|
|
|
async function playNutRoulette(
|
|
interaction,
|
|
choiceKey
|
|
) {
|
|
const choice =
|
|
CHOICES[
|
|
choiceKey
|
|
];
|
|
|
|
|
|
if (!choice) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"Diese Roulette-Wette existiert nicht."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const footer =
|
|
interaction.message
|
|
?.embeds?.[0]
|
|
?.footer
|
|
?.text;
|
|
|
|
|
|
const parts =
|
|
footer?.split(":")
|
|
??
|
|
[];
|
|
|
|
|
|
if (
|
|
parts[0] !==
|
|
"nutRouletteBet"
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"Diese Roulette-Wette ist nicht mehr gültig."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const ownerId =
|
|
parts[1];
|
|
|
|
|
|
const bet =
|
|
Number(
|
|
parts[2]
|
|
);
|
|
|
|
|
|
if (
|
|
ownerId !==
|
|
interaction.user.id
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"Das ist nicht dein Roulette-Tisch."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const playerId =
|
|
interaction.user.id;
|
|
|
|
|
|
const houseId =
|
|
interaction.client.user.id;
|
|
|
|
|
|
const [
|
|
playerBalance,
|
|
houseBalance
|
|
] =
|
|
await Promise.all([
|
|
getNutBalance(
|
|
playerId
|
|
),
|
|
|
|
getNutBalance(
|
|
houseId
|
|
)
|
|
]);
|
|
|
|
|
|
if (
|
|
playerBalance <
|
|
bet
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"Du hast nicht mehr genug Nüsse."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
const maxPayout =
|
|
bet *
|
|
choice.multiplier;
|
|
|
|
|
|
if (
|
|
houseBalance +
|
|
bet <
|
|
maxPayout
|
|
) {
|
|
return temporaryEphemeralReply(
|
|
interaction,
|
|
{
|
|
content:
|
|
"Der Nut Vault kann diesen Einsatz nicht absichern."
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
await transferNuts(
|
|
playerId,
|
|
houseId,
|
|
bet
|
|
);
|
|
|
|
|
|
/*
|
|
* Pseudo animation.
|
|
*/
|
|
|
|
await interaction.update({
|
|
embeds: [
|
|
buildSpinEmbed(
|
|
choice,
|
|
bet,
|
|
randomRouletteNumber(),
|
|
"Das Rad beginnt sich zu drehen..."
|
|
)
|
|
],
|
|
|
|
components: []
|
|
});
|
|
|
|
|
|
await delay(
|
|
650
|
|
);
|
|
|
|
|
|
await interaction.editReply({
|
|
embeds: [
|
|
buildSpinEmbed(
|
|
choice,
|
|
bet,
|
|
randomRouletteNumber(),
|
|
"Round and round..."
|
|
)
|
|
]
|
|
});
|
|
|
|
|
|
await delay(
|
|
650
|
|
);
|
|
|
|
|
|
await interaction.editReply({
|
|
embeds: [
|
|
buildSpinEmbed(
|
|
choice,
|
|
bet,
|
|
randomRouletteNumber(),
|
|
"Die Kugel wird langsamer..."
|
|
)
|
|
]
|
|
});
|
|
|
|
|
|
await delay(
|
|
750
|
|
);
|
|
|
|
|
|
const result =
|
|
randomRouletteNumber();
|
|
|
|
|
|
const won =
|
|
didBetWin(
|
|
choiceKey,
|
|
result
|
|
);
|
|
|
|
|
|
const payout =
|
|
won
|
|
? bet *
|
|
choice.multiplier
|
|
: 0;
|
|
|
|
|
|
if (
|
|
payout >
|
|
0
|
|
) {
|
|
await transferNuts(
|
|
houseId,
|
|
playerId,
|
|
payout
|
|
);
|
|
}
|
|
|
|
|
|
const balance =
|
|
await getNutBalance(
|
|
playerId
|
|
);
|
|
|
|
|
|
const profit =
|
|
payout -
|
|
bet;
|
|
|
|
|
|
const embed =
|
|
new EmbedBuilder()
|
|
.setTitle(
|
|
won
|
|
? "🎉 Nut Roulette — WIN!"
|
|
: "🎡 Nut Roulette"
|
|
)
|
|
|
|
.setDescription(
|
|
[
|
|
"## Die Kugel landet auf...",
|
|
"",
|
|
`# ${formatRouletteNumber(result)}`,
|
|
"",
|
|
`${choice.emoji} Deine Wette: **${choice.name}**`,
|
|
"",
|
|
won
|
|
? `🎉 **${payout.toLocaleString()} Nüsse gewonnen!**`
|
|
: "Das Haus gewinnt."
|
|
].join("\n")
|
|
)
|
|
|
|
.addFields(
|
|
{
|
|
name:
|
|
"Einsatz",
|
|
|
|
value:
|
|
`${bet.toLocaleString()} 🥜`,
|
|
|
|
inline:
|
|
true
|
|
},
|
|
|
|
{
|
|
name:
|
|
"Payout",
|
|
|
|
value:
|
|
`${payout.toLocaleString()} 🥜`,
|
|
|
|
inline:
|
|
true
|
|
},
|
|
|
|
{
|
|
name:
|
|
"Profit",
|
|
|
|
value:
|
|
`${profit >= 0 ? "+" : ""}${profit.toLocaleString()} 🥜`,
|
|
|
|
inline:
|
|
true
|
|
},
|
|
|
|
{
|
|
name:
|
|
"Deine Nüsse",
|
|
|
|
value:
|
|
`${balance.toLocaleString()} 🥜`
|
|
}
|
|
)
|
|
|
|
.setFooter({
|
|
text:
|
|
`nutRouletteResult:${playerId}`
|
|
});
|
|
|
|
|
|
return interaction.editReply({
|
|
embeds: [
|
|
embed
|
|
],
|
|
|
|
components:
|
|
buildResultButtons()
|
|
});
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* RULES
|
|
* ============================================================
|
|
*/
|
|
|
|
function didBetWin(
|
|
choice,
|
|
number
|
|
) {
|
|
if (
|
|
number ===
|
|
0
|
|
) {
|
|
return choice ===
|
|
"Zero";
|
|
}
|
|
|
|
|
|
switch (choice) {
|
|
case "Red":
|
|
return RED_NUMBERS.has(
|
|
number
|
|
);
|
|
|
|
case "Black":
|
|
return !RED_NUMBERS.has(
|
|
number
|
|
);
|
|
|
|
case "Odd":
|
|
return number %
|
|
2 ===
|
|
1;
|
|
|
|
case "Even":
|
|
return number %
|
|
2 ===
|
|
0;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
function formatRouletteNumber(
|
|
number
|
|
) {
|
|
if (
|
|
number ===
|
|
0
|
|
) {
|
|
return "🟢 0";
|
|
}
|
|
|
|
|
|
if (
|
|
RED_NUMBERS.has(
|
|
number
|
|
)
|
|
) {
|
|
return `🔴 ${number}`;
|
|
}
|
|
|
|
|
|
return `⚫ ${number}`;
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* DISPLAY
|
|
* ============================================================
|
|
*/
|
|
|
|
function buildSpinEmbed(
|
|
choice,
|
|
bet,
|
|
number,
|
|
text
|
|
) {
|
|
return new EmbedBuilder()
|
|
.setTitle(
|
|
"🎡 Nut Roulette"
|
|
)
|
|
|
|
.setDescription(
|
|
[
|
|
"## 🎡 Spinning...",
|
|
"",
|
|
`### ${formatRouletteNumber(number)}`,
|
|
"",
|
|
`**${text}**`
|
|
].join("\n")
|
|
)
|
|
|
|
.addFields(
|
|
{
|
|
name:
|
|
"Wette",
|
|
|
|
value:
|
|
`${choice.emoji} ${choice.name}`,
|
|
|
|
inline:
|
|
true
|
|
},
|
|
|
|
{
|
|
name:
|
|
"Einsatz",
|
|
|
|
value:
|
|
`${bet.toLocaleString()} 🥜`,
|
|
|
|
inline:
|
|
true
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* BUTTONS
|
|
* ============================================================
|
|
*/
|
|
|
|
function buildBetButtons() {
|
|
return [
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
...ROULETTE_BETS.map(
|
|
bet =>
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
`nutRouletteBet${bet}`
|
|
)
|
|
.setLabel(
|
|
bet.toLocaleString()
|
|
)
|
|
.setEmoji(
|
|
"🥜"
|
|
)
|
|
.setStyle(
|
|
bet >=
|
|
500
|
|
? ButtonStyle.Primary
|
|
: ButtonStyle.Secondary
|
|
)
|
|
)
|
|
),
|
|
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"nutHubBack"
|
|
)
|
|
.setLabel(
|
|
"Nut Hub"
|
|
)
|
|
.setEmoji(
|
|
"◀️"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Secondary
|
|
)
|
|
)
|
|
];
|
|
}
|
|
|
|
|
|
function buildChoiceButtons() {
|
|
return [
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"nutRouletteRed"
|
|
)
|
|
.setLabel(
|
|
"Red"
|
|
)
|
|
.setEmoji(
|
|
"🔴"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Danger
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"nutRouletteBlack"
|
|
)
|
|
.setLabel(
|
|
"Black"
|
|
)
|
|
.setEmoji(
|
|
"⚫"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Secondary
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"nutRouletteOdd"
|
|
)
|
|
.setLabel(
|
|
"Odd"
|
|
)
|
|
.setEmoji(
|
|
"1️⃣"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Primary
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"nutRouletteEven"
|
|
)
|
|
.setLabel(
|
|
"Even"
|
|
)
|
|
.setEmoji(
|
|
"2️⃣"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Primary
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"nutRouletteZero"
|
|
)
|
|
.setLabel(
|
|
"Zero"
|
|
)
|
|
.setEmoji(
|
|
"🟢"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Success
|
|
)
|
|
)
|
|
];
|
|
}
|
|
|
|
|
|
function buildResultButtons() {
|
|
return [
|
|
new ActionRowBuilder()
|
|
.addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"nutHubRoulette"
|
|
)
|
|
.setLabel(
|
|
"Play Again"
|
|
)
|
|
.setEmoji(
|
|
"🎡"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Primary
|
|
),
|
|
|
|
new ButtonBuilder()
|
|
.setCustomId(
|
|
"nutHubBack"
|
|
)
|
|
.setLabel(
|
|
"Nut Hub"
|
|
)
|
|
.setEmoji(
|
|
"◀️"
|
|
)
|
|
.setStyle(
|
|
ButtonStyle.Secondary
|
|
)
|
|
)
|
|
];
|
|
}
|
|
|
|
|
|
/*
|
|
* ============================================================
|
|
* OWNERSHIP
|
|
* ============================================================
|
|
*/
|
|
|
|
function getRouletteOwner(
|
|
interaction
|
|
) {
|
|
const footer =
|
|
interaction.message
|
|
?.embeds?.[0]
|
|
?.footer
|
|
?.text;
|
|
|
|
|
|
const parts =
|
|
footer?.split(":")
|
|
??
|
|
[];
|
|
|
|
|
|
if (
|
|
parts[0] ===
|
|
"nutHub"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
|
|
if (
|
|
parts[0] ===
|
|
"nutRouletteMenu"
|
|
||
|
|
parts[0] ===
|
|
"nutRouletteResult"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
|
|
if (
|
|
parts[0] ===
|
|
"nutRouletteBet"
|
|
) {
|
|
return parts[1];
|
|
}
|
|
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
function randomRouletteNumber() {
|
|
return Math.floor(
|
|
Math.random() *
|
|
37
|
|
);
|
|
}
|
|
|
|
|
|
function delay(
|
|
ms
|
|
) {
|
|
return new Promise(
|
|
resolve =>
|
|
setTimeout(
|
|
resolve,
|
|
ms
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
module.exports = {
|
|
showNutRoulette,
|
|
chooseNutRouletteBet,
|
|
playNutRoulette
|
|
}; |