Files
Arthonor-Neo/utils/nutRoulette.js
T

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
};