1060 lines
24 KiB
JavaScript
1060 lines
24 KiB
JavaScript
const {
|
||
EmbedBuilder,
|
||
ActionRowBuilder,
|
||
ButtonBuilder,
|
||
ButtonStyle,
|
||
StringSelectMenuBuilder,
|
||
MessageFlags
|
||
} = require("discord.js");
|
||
|
||
const {
|
||
cardToString,
|
||
getLegalActions
|
||
} = require("./pokerEngine");
|
||
|
||
const {
|
||
getPokerService,
|
||
publicTableState,
|
||
POKER_DEFAULT_BUY_IN,
|
||
POKER_DEFAULT_SMALL_BLIND,
|
||
POKER_DEFAULT_BIG_BLIND,
|
||
POKER_TURN_TIMEOUT
|
||
} = require("./crumbPoker");
|
||
|
||
const POKER_TABLE_FOOTER_PREFIX =
|
||
"pokerTable";
|
||
|
||
const POKER_CARD_RESPONSE_LIFETIME =
|
||
5000;
|
||
|
||
const POKER_ACTIVE_STATES_FOR_DISPLAY =
|
||
new Set([
|
||
"PREFLOP",
|
||
"FLOP",
|
||
"TURN",
|
||
"RIVER"
|
||
]);
|
||
|
||
|
||
function getPokerGameIdFromInteraction(
|
||
interaction
|
||
) {
|
||
const footer =
|
||
interaction.message
|
||
?.embeds?.[0]
|
||
?.footer
|
||
?.text;
|
||
|
||
const [
|
||
prefix,
|
||
gameId
|
||
] =
|
||
footer?.split(":") ?? [];
|
||
|
||
if (
|
||
prefix !==
|
||
POKER_TABLE_FOOTER_PREFIX
|
||
||
|
||
!gameId
|
||
) {
|
||
return null;
|
||
}
|
||
|
||
return gameId;
|
||
}
|
||
|
||
|
||
function pokerTableUrl(
|
||
game
|
||
) {
|
||
if (
|
||
!game?.guildId
|
||
||
|
||
!game?.channelId
|
||
||
|
||
!game?.messageId
|
||
) {
|
||
return null;
|
||
}
|
||
|
||
return (
|
||
`https://discord.com/channels/` +
|
||
`${game.guildId}/` +
|
||
`${game.channelId}/` +
|
||
`${game.messageId}`
|
||
);
|
||
}
|
||
|
||
|
||
function formatPokerError(
|
||
error
|
||
) {
|
||
const known = {
|
||
TABLE_NOT_FOUND:
|
||
"This Poker table is no longer active.",
|
||
PLAYER_ALREADY_SEATED:
|
||
"You are already seated at a Poker table.",
|
||
TABLE_NOT_JOINABLE:
|
||
"That Poker table is not accepting new players right now.",
|
||
TABLE_FULL:
|
||
"That Poker table is full.",
|
||
NOT_TABLE_PLAYER:
|
||
"You are not seated at this Poker table.",
|
||
NOT_TABLE_OWNER:
|
||
"Only the table owner can start the next hand.",
|
||
NOT_ENOUGH_PLAYERS:
|
||
"At least two eligible players are required to start.",
|
||
HAND_ALREADY_ACTIVE:
|
||
"A Poker hand is already active.",
|
||
HAND_NOT_ACTIVE:
|
||
"There is no active Poker hand.",
|
||
HAND_ACTIVE:
|
||
"You cannot cash out during an active Poker hand.",
|
||
CANCEL_HAND_ACTIVE:
|
||
"Finish the current hand before cancelling the table.",
|
||
TABLE_NOT_CANCELLABLE:
|
||
"This Poker table cannot be cancelled right now.",
|
||
OUT_OF_TURN:
|
||
"It isn't your turn.",
|
||
TURN_EXPIRED:
|
||
"Your Poker turn has already expired.",
|
||
STATE_CONFLICT:
|
||
"The table changed at the same time. Please try again.",
|
||
INSUFFICIENT_COOKIES:
|
||
"You do not have enough Cookies for this Poker buy-in."
|
||
};
|
||
|
||
return (
|
||
known[error?.code]
|
||
??
|
||
known[error?.message]
|
||
??
|
||
error?.message
|
||
??
|
||
"The Poker action could not be completed."
|
||
);
|
||
}
|
||
|
||
|
||
async function deferPokerReply(
|
||
interaction
|
||
) {
|
||
if (
|
||
interaction.deferred
|
||
||
|
||
interaction.replied
|
||
) {
|
||
return;
|
||
}
|
||
|
||
await interaction.deferReply({
|
||
flags:
|
||
MessageFlags.Ephemeral
|
||
});
|
||
}
|
||
|
||
|
||
async function editPokerError(
|
||
interaction,
|
||
error
|
||
) {
|
||
return interaction.editReply({
|
||
content:
|
||
`❌ ${formatPokerError(error)}`,
|
||
embeds: [],
|
||
components: []
|
||
});
|
||
}
|
||
|
||
|
||
function buildPokerHubEmbed() {
|
||
return new EmbedBuilder()
|
||
.setTitle(
|
||
"♠️ Shai Poker"
|
||
)
|
||
.setDescription(
|
||
[
|
||
"Multiplayer Poker inside the Crumb Saucer.",
|
||
"",
|
||
`**Default Buy-In:** ${POKER_DEFAULT_BUY_IN.toLocaleString()} 🍪`,
|
||
`**Blinds:** ${POKER_DEFAULT_SMALL_BLIND.toLocaleString()} / ${POKER_DEFAULT_BIG_BLIND.toLocaleString()} 🍪`,
|
||
"**Players:** 2–6",
|
||
`**Turn Timer:** ${POKER_TURN_TIMEOUT} seconds`,
|
||
"",
|
||
"Create a public table, join an available table, or return to the table you are already seated at.",
|
||
"",
|
||
"Poker uses an internal chip stack. Cookies only move when you buy in or cash out."
|
||
].join("\n")
|
||
);
|
||
}
|
||
|
||
|
||
function buildPokerHubComponents() {
|
||
return [
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerCreate"
|
||
)
|
||
.setLabel(
|
||
"Create Table"
|
||
)
|
||
.setEmoji(
|
||
"➕"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Success
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerBrowse"
|
||
)
|
||
.setLabel(
|
||
"Join Table"
|
||
)
|
||
.setEmoji(
|
||
"🪑"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Primary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerMyTable"
|
||
)
|
||
.setLabel(
|
||
"My Table"
|
||
)
|
||
.setEmoji(
|
||
"♠️"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
)
|
||
)
|
||
];
|
||
}
|
||
|
||
|
||
function buildJoinPicker(
|
||
tables
|
||
) {
|
||
const embed =
|
||
new EmbedBuilder()
|
||
.setTitle(
|
||
"🪑 Join a Poker Table"
|
||
);
|
||
|
||
if (!tables.length) {
|
||
embed.setDescription(
|
||
"There are no joinable Poker tables in this channel right now."
|
||
);
|
||
|
||
return {
|
||
embeds: [embed],
|
||
components: []
|
||
};
|
||
}
|
||
|
||
embed.setDescription(
|
||
"Choose a table below. The buy-in is debited only after your seat is successfully reserved."
|
||
);
|
||
|
||
const menu =
|
||
new StringSelectMenuBuilder()
|
||
.setCustomId(
|
||
"pokerJoinSelect"
|
||
)
|
||
.setPlaceholder(
|
||
"Choose a Poker table"
|
||
)
|
||
.addOptions(
|
||
tables.map(
|
||
table => {
|
||
const seats =
|
||
table.data.players.length;
|
||
|
||
return {
|
||
label:
|
||
`Table ${table.gameId.slice(-8)}`,
|
||
description:
|
||
`${seats}/${table.data.maxPlayers} players • ${table.data.buyIn.toLocaleString()} Cookie buy-in`,
|
||
value:
|
||
table.gameId,
|
||
emoji:
|
||
"♠️"
|
||
};
|
||
}
|
||
)
|
||
);
|
||
|
||
return {
|
||
embeds: [embed],
|
||
components: [
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
menu
|
||
)
|
||
]
|
||
};
|
||
}
|
||
|
||
|
||
function playerDisplayStack(
|
||
publicGame,
|
||
player
|
||
) {
|
||
const handPlayer =
|
||
publicGame.data.hand
|
||
?.players
|
||
?.find(
|
||
candidate =>
|
||
candidate.userId ===
|
||
player.userId
|
||
);
|
||
|
||
return (
|
||
handPlayer?.stack
|
||
??
|
||
player.stack
|
||
??
|
||
0
|
||
);
|
||
}
|
||
|
||
|
||
function buildPlayerLine(
|
||
publicGame,
|
||
player
|
||
) {
|
||
const hand =
|
||
publicGame.data.hand;
|
||
|
||
const handPlayer =
|
||
hand?.players?.find(
|
||
candidate =>
|
||
candidate.userId ===
|
||
player.userId
|
||
);
|
||
|
||
let status = "🟢";
|
||
|
||
if (
|
||
player.status ===
|
||
"BUSTED"
|
||
) {
|
||
status = "⚪";
|
||
}
|
||
|
||
else if (
|
||
handPlayer?.folded
|
||
) {
|
||
status = "⚫";
|
||
}
|
||
|
||
else if (
|
||
handPlayer?.allIn
|
||
) {
|
||
status = "🔒";
|
||
}
|
||
|
||
if (
|
||
hand?.currentSeat ===
|
||
player.seat
|
||
) {
|
||
status = "▶️";
|
||
}
|
||
|
||
const markers = [];
|
||
|
||
if (
|
||
publicGame.data.dealerSeat ===
|
||
player.seat
|
||
) {
|
||
markers.push("D");
|
||
}
|
||
|
||
if (
|
||
hand?.smallBlindSeat ===
|
||
player.seat
|
||
) {
|
||
markers.push("SB");
|
||
}
|
||
|
||
if (
|
||
hand?.bigBlindSeat ===
|
||
player.seat
|
||
) {
|
||
markers.push("BB");
|
||
}
|
||
|
||
const markerText =
|
||
markers.length
|
||
? ` **[${markers.join("/")}]**`
|
||
: "";
|
||
|
||
const stack =
|
||
playerDisplayStack(
|
||
publicGame,
|
||
player
|
||
);
|
||
|
||
const streetBet =
|
||
handPlayer?.streetBet ?? 0;
|
||
|
||
const betText =
|
||
streetBet > 0
|
||
? ` • bet ${streetBet.toLocaleString()}`
|
||
: "";
|
||
|
||
return (
|
||
`${status} <@${player.userId}>${markerText} — ` +
|
||
`**${stack.toLocaleString()}**${betText}`
|
||
);
|
||
}
|
||
|
||
|
||
function buildLastHandText(
|
||
publicGame
|
||
) {
|
||
const result =
|
||
publicGame.data.lastHandResult;
|
||
|
||
if (!result) {
|
||
return null;
|
||
}
|
||
|
||
const winners =
|
||
(result.winnerSeats ?? [])
|
||
.map(
|
||
seat =>
|
||
publicGame.data.players.find(
|
||
player =>
|
||
player.seat ===
|
||
seat
|
||
)
|
||
)
|
||
.filter(Boolean);
|
||
|
||
if (!winners.length) {
|
||
return null;
|
||
}
|
||
|
||
const winnerText =
|
||
winners
|
||
.map(
|
||
player =>
|
||
`<@${player.userId}>`
|
||
)
|
||
.join(", ");
|
||
|
||
const payout =
|
||
Object.values(
|
||
result.payouts ?? {}
|
||
)
|
||
.reduce(
|
||
(sum, value) =>
|
||
sum + Number(value ?? 0),
|
||
0
|
||
);
|
||
|
||
const handName =
|
||
result.handRank?.name
|
||
??
|
||
null;
|
||
|
||
return [
|
||
`${winnerText} won **${payout.toLocaleString()} 🍪**.`,
|
||
handName
|
||
? `Winning hand: **${handName}**`
|
||
: null
|
||
]
|
||
.filter(Boolean)
|
||
.join("\n");
|
||
}
|
||
|
||
|
||
function buildPokerTableEmbed(
|
||
game
|
||
) {
|
||
const publicGame =
|
||
publicTableState(
|
||
game
|
||
);
|
||
|
||
const hand =
|
||
publicGame.data.hand;
|
||
|
||
const cards =
|
||
hand?.communityCards ?? [];
|
||
|
||
const community = [];
|
||
|
||
for (
|
||
let index = 0;
|
||
index < 5;
|
||
index++
|
||
) {
|
||
community.push(
|
||
cards[index]
|
||
? cardToString(
|
||
cards[index]
|
||
)
|
||
: "🂠"
|
||
);
|
||
}
|
||
|
||
const playerLines =
|
||
publicGame.data.players
|
||
.slice()
|
||
.sort(
|
||
(a, b) =>
|
||
a.seat - b.seat
|
||
)
|
||
.map(
|
||
player =>
|
||
buildPlayerLine(
|
||
publicGame,
|
||
player
|
||
)
|
||
);
|
||
|
||
const stateLabel =
|
||
publicGame.state ===
|
||
"NEXT_HAND"
|
||
? "🏆 HAND COMPLETE"
|
||
: POKER_ACTIVE_STATES_FOR_DISPLAY.has(
|
||
publicGame.state
|
||
)
|
||
? `🃏 ${publicGame.state.replaceAll("_", " ")}`
|
||
: publicGame.state
|
||
.replaceAll("_", " ");
|
||
|
||
const pot =
|
||
hand?.pot ?? 0;
|
||
|
||
const description = [
|
||
`**State:** ${stateLabel}`,
|
||
hand && POKER_ACTIVE_STATES_FOR_DISPLAY.has(
|
||
publicGame.state
|
||
)
|
||
? `**Hand #${publicGame.data.handNumber}** • 🃏 Cards have been dealt. Use **Cards** to view your hand.`
|
||
: null,
|
||
`**Blinds:** ${publicGame.data.smallBlind.toLocaleString()} / ${publicGame.data.bigBlind.toLocaleString()} 🍪`,
|
||
`**Buy-In:** ${publicGame.data.buyIn.toLocaleString()} 🍪`,
|
||
`**Pot:** ${pot.toLocaleString()} 🍪`,
|
||
"",
|
||
"### Community Cards",
|
||
community.join(" "),
|
||
"",
|
||
"### Players",
|
||
playerLines.length
|
||
? playerLines.join("\n")
|
||
: "No players seated."
|
||
];
|
||
|
||
if (
|
||
hand?.currentSeat !==
|
||
null
|
||
&&
|
||
hand?.currentSeat !==
|
||
undefined
|
||
) {
|
||
const current =
|
||
hand.players.find(
|
||
player =>
|
||
player.seat ===
|
||
hand.currentSeat
|
||
);
|
||
|
||
if (current) {
|
||
description.push(
|
||
"",
|
||
"━━━━━━━━━━━━━━━━━━",
|
||
`### 👉 CURRENT TURN: <@${current.userId}>`
|
||
);
|
||
|
||
if (
|
||
publicGame.data.turnExpiresAt
|
||
) {
|
||
description.push(
|
||
`⏱️ **90-second turn** • Auto-folds <t:${publicGame.data.turnExpiresAt}:R>`
|
||
);
|
||
}
|
||
|
||
description.push(
|
||
"━━━━━━━━━━━━━━━━━━"
|
||
);
|
||
}
|
||
}
|
||
|
||
const lastHand =
|
||
buildLastHandText(
|
||
publicGame
|
||
);
|
||
|
||
if (lastHand) {
|
||
description.push(
|
||
"",
|
||
"### Last Hand",
|
||
lastHand
|
||
);
|
||
}
|
||
|
||
if (
|
||
publicGame.state ===
|
||
"WAITING"
|
||
||
|
||
publicGame.state ===
|
||
"NEXT_HAND"
|
||
) {
|
||
description.push(
|
||
"",
|
||
`Lobby expires <t:${publicGame.data.lobbyExpiresAt}:R>.`
|
||
);
|
||
}
|
||
|
||
if (
|
||
publicGame.state ===
|
||
"CLOSED"
|
||
) {
|
||
description.push(
|
||
"",
|
||
"This Poker table is closed."
|
||
);
|
||
}
|
||
|
||
return new EmbedBuilder()
|
||
.setTitle(
|
||
"♠️ SHAI POKER"
|
||
)
|
||
.setDescription(
|
||
description.join("\n")
|
||
)
|
||
.setFooter({
|
||
text:
|
||
`${POKER_TABLE_FOOTER_PREFIX}:${publicGame.gameId}`
|
||
})
|
||
.setTimestamp();
|
||
}
|
||
|
||
|
||
function buildPokerTableComponents(
|
||
game
|
||
) {
|
||
if (
|
||
!game
|
||
||
|
||
game.state ===
|
||
"CLOSED"
|
||
) {
|
||
return [];
|
||
}
|
||
|
||
if (
|
||
game.state ===
|
||
"WAITING"
|
||
||
|
||
game.state ===
|
||
"NEXT_HAND"
|
||
) {
|
||
return [
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerJoinTable"
|
||
)
|
||
.setLabel(
|
||
"Join Table"
|
||
)
|
||
.setEmoji(
|
||
"🪑"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Success
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerStart"
|
||
)
|
||
.setLabel(
|
||
game.state ===
|
||
"NEXT_HAND"
|
||
? "Next Hand"
|
||
: "Start Hand"
|
||
)
|
||
.setEmoji(
|
||
"▶️"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Primary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerCashOut"
|
||
)
|
||
.setLabel(
|
||
"Cash Out"
|
||
)
|
||
.setEmoji(
|
||
"🍪"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerRefresh"
|
||
)
|
||
.setLabel(
|
||
"Refresh"
|
||
)
|
||
.setEmoji(
|
||
"🔄"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerCancel"
|
||
)
|
||
.setLabel(
|
||
"Cancel Table"
|
||
)
|
||
.setEmoji(
|
||
"🛑"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Danger
|
||
)
|
||
)
|
||
];
|
||
}
|
||
|
||
const hand =
|
||
game.data.hand;
|
||
|
||
if (!hand) {
|
||
return [];
|
||
}
|
||
|
||
const currentPlayer =
|
||
hand.players.find(
|
||
player =>
|
||
player.seat ===
|
||
hand.currentSeat
|
||
);
|
||
|
||
const legal =
|
||
currentPlayer
|
||
? getLegalActions(
|
||
hand,
|
||
currentPlayer.userId
|
||
)
|
||
: {
|
||
actions: []
|
||
};
|
||
|
||
const can =
|
||
action =>
|
||
legal.actions?.includes(
|
||
action
|
||
);
|
||
|
||
const callLabel =
|
||
legal.toCall > 0
|
||
? `Call ${legal.toCall.toLocaleString()}`
|
||
: "Call";
|
||
|
||
const raiseType =
|
||
can("bet")
|
||
? "bet"
|
||
: "raise";
|
||
|
||
const raiseLabel =
|
||
legal.minRaiseTo
|
||
? `${raiseType === "bet" ? "Bet" : "Raise to"} ${legal.minRaiseTo.toLocaleString()}`
|
||
: "Raise";
|
||
|
||
return [
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerCards"
|
||
)
|
||
.setLabel(
|
||
"Cards"
|
||
)
|
||
.setEmoji(
|
||
"🃏"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerFold"
|
||
)
|
||
.setLabel(
|
||
"Fold"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Danger
|
||
)
|
||
.setDisabled(
|
||
!can("fold")
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerCheck"
|
||
)
|
||
.setLabel(
|
||
"Check"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
)
|
||
.setDisabled(
|
||
!can("check")
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerCall"
|
||
)
|
||
.setLabel(
|
||
callLabel
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Success
|
||
)
|
||
.setDisabled(
|
||
!can("call")
|
||
)
|
||
),
|
||
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerRaise"
|
||
)
|
||
.setLabel(
|
||
raiseLabel
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Primary
|
||
)
|
||
.setDisabled(
|
||
!can("bet")
|
||
&&
|
||
!can("raise")
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerAllIn"
|
||
)
|
||
.setLabel(
|
||
"All-In"
|
||
)
|
||
.setEmoji(
|
||
"🔥"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Danger
|
||
)
|
||
.setDisabled(
|
||
!can("all_in")
|
||
),
|
||
|
||
new ButtonBuilder()
|
||
.setCustomId(
|
||
"pokerRefresh"
|
||
)
|
||
.setLabel(
|
||
"Refresh"
|
||
)
|
||
.setEmoji(
|
||
"🔄"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Secondary
|
||
)
|
||
)
|
||
];
|
||
}
|
||
|
||
|
||
async function refreshPokerTableMessage(
|
||
client,
|
||
game
|
||
) {
|
||
if (
|
||
!game?.channelId
|
||
||
|
||
!game?.messageId
|
||
) {
|
||
return null;
|
||
}
|
||
|
||
try {
|
||
const channel =
|
||
await client.channels.fetch(
|
||
game.channelId
|
||
);
|
||
|
||
if (
|
||
!channel
|
||
||
|
||
!channel.messages
|
||
) {
|
||
return null;
|
||
}
|
||
|
||
const message =
|
||
await channel.messages.fetch(
|
||
game.messageId
|
||
);
|
||
|
||
await message.edit({
|
||
embeds: [
|
||
buildPokerTableEmbed(
|
||
game
|
||
)
|
||
],
|
||
components:
|
||
buildPokerTableComponents(
|
||
game
|
||
)
|
||
});
|
||
|
||
return message;
|
||
}
|
||
|
||
catch (error) {
|
||
console.error(
|
||
`[Poker] Failed to refresh table ${game.gameId}:`,
|
||
error
|
||
);
|
||
|
||
return null;
|
||
}
|
||
}
|
||
|
||
|
||
async function publishPokerTable(
|
||
interaction,
|
||
game
|
||
) {
|
||
const message =
|
||
await interaction.channel.send({
|
||
embeds: [
|
||
buildPokerTableEmbed(
|
||
game
|
||
)
|
||
],
|
||
components:
|
||
buildPokerTableComponents(
|
||
game
|
||
)
|
||
});
|
||
|
||
const service =
|
||
getPokerService();
|
||
|
||
const updated =
|
||
await service.setMessageId({
|
||
gameId:
|
||
game.gameId,
|
||
messageId:
|
||
message.id
|
||
});
|
||
|
||
await message.edit({
|
||
embeds: [
|
||
buildPokerTableEmbed(
|
||
updated
|
||
)
|
||
],
|
||
components:
|
||
buildPokerTableComponents(
|
||
updated
|
||
)
|
||
});
|
||
|
||
return {
|
||
game:
|
||
updated,
|
||
message
|
||
};
|
||
}
|
||
|
||
|
||
function buildOpenTableLink(
|
||
game,
|
||
label = "Open Poker Table"
|
||
) {
|
||
const url =
|
||
pokerTableUrl(
|
||
game
|
||
);
|
||
|
||
if (!url) {
|
||
return [];
|
||
}
|
||
|
||
return [
|
||
new ActionRowBuilder()
|
||
.addComponents(
|
||
new ButtonBuilder()
|
||
.setLabel(
|
||
label
|
||
)
|
||
.setEmoji(
|
||
"♠️"
|
||
)
|
||
.setStyle(
|
||
ButtonStyle.Link
|
||
)
|
||
.setURL(
|
||
url
|
||
)
|
||
)
|
||
];
|
||
}
|
||
|
||
|
||
module.exports = {
|
||
POKER_TABLE_FOOTER_PREFIX,
|
||
POKER_CARD_RESPONSE_LIFETIME,
|
||
|
||
getPokerGameIdFromInteraction,
|
||
pokerTableUrl,
|
||
formatPokerError,
|
||
deferPokerReply,
|
||
editPokerError,
|
||
|
||
buildPokerHubEmbed,
|
||
buildPokerHubComponents,
|
||
buildJoinPicker,
|
||
buildPokerTableEmbed,
|
||
buildPokerTableComponents,
|
||
buildOpenTableLink,
|
||
|
||
refreshPokerTableMessage,
|
||
publishPokerTable
|
||
};
|