1289 lines
23 KiB
JavaScript
1289 lines
23 KiB
JavaScript
const {
|
|
EmbedBuilder
|
|
} = require("discord.js");
|
|
|
|
const {
|
|
getProfileCollections,
|
|
getDefaultStats,
|
|
trackProfileEvent,
|
|
trackGameActivity
|
|
} = require("./profileSystem");
|
|
|
|
const {
|
|
getUnixTime
|
|
} = require("./cookieEconomy");
|
|
|
|
|
|
const POKER_GAME_KEY =
|
|
"poker";
|
|
|
|
const PROFILE_HAND_HISTORY_LIMIT =
|
|
100;
|
|
|
|
const PROFILE_ACTION_HISTORY_LIMIT =
|
|
250;
|
|
|
|
|
|
const ACTION_STAT_PATHS = {
|
|
fold:
|
|
"games.poker.folds",
|
|
check:
|
|
"games.poker.checks",
|
|
call:
|
|
"games.poker.calls",
|
|
bet:
|
|
"games.poker.bets",
|
|
raise:
|
|
"games.poker.raises",
|
|
all_in:
|
|
"games.poker.allInActions"
|
|
};
|
|
|
|
|
|
const HAND_RANK_STAT_PATHS = {
|
|
"High Card":
|
|
"games.poker.handRanks.highCard",
|
|
Pair:
|
|
"games.poker.handRanks.pair",
|
|
"Two Pair":
|
|
"games.poker.handRanks.twoPair",
|
|
"Three of a Kind":
|
|
"games.poker.handRanks.threeOfAKind",
|
|
Straight:
|
|
"games.poker.handRanks.straight",
|
|
Flush:
|
|
"games.poker.handRanks.flush",
|
|
"Full House":
|
|
"games.poker.handRanks.fullHouse",
|
|
"Four of a Kind":
|
|
"games.poker.handRanks.fourOfAKind",
|
|
"Straight Flush":
|
|
"games.poker.handRanks.straightFlush",
|
|
"Royal Flush":
|
|
"games.poker.handRanks.royalFlush"
|
|
};
|
|
|
|
|
|
async function ensurePokerProfileDocument(
|
|
userId,
|
|
guildId
|
|
) {
|
|
const {
|
|
stats
|
|
} =
|
|
getProfileCollections();
|
|
|
|
await stats.updateOne(
|
|
{
|
|
userId,
|
|
guildId
|
|
},
|
|
{
|
|
$setOnInsert:
|
|
getDefaultStats(
|
|
userId,
|
|
guildId
|
|
)
|
|
},
|
|
{
|
|
upsert: true
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
function getPokerHandId(
|
|
game
|
|
) {
|
|
if (
|
|
!game?.gameId
|
|
||
|
|
!Number.isSafeInteger(
|
|
Number(
|
|
game?.data?.handNumber
|
|
)
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
`${game.gameId}:hand:${Number(game.data.handNumber)}`
|
|
);
|
|
}
|
|
|
|
|
|
function getPokerActionId(
|
|
game
|
|
) {
|
|
if (
|
|
!game?.gameId
|
|
||
|
|
!Number.isSafeInteger(
|
|
Number(game.version)
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
`${game.gameId}:action:v${Number(game.version)}`
|
|
);
|
|
}
|
|
|
|
|
|
function normalizeActionType(
|
|
action
|
|
) {
|
|
return String(
|
|
action?.type ?? ""
|
|
).toLowerCase();
|
|
}
|
|
|
|
|
|
function normalizeCardRank(
|
|
card
|
|
) {
|
|
return String(
|
|
card?.rank ?? ""
|
|
).toUpperCase();
|
|
}
|
|
|
|
|
|
function isPocketAces(
|
|
holeCards
|
|
) {
|
|
return (
|
|
Array.isArray(holeCards)
|
|
&&
|
|
holeCards.length === 2
|
|
&&
|
|
holeCards.every(
|
|
card =>
|
|
normalizeCardRank(card) ===
|
|
"A"
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
function isSevenDeuce(
|
|
holeCards
|
|
) {
|
|
if (
|
|
!Array.isArray(holeCards)
|
|
||
|
|
holeCards.length !== 2
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
const ranks =
|
|
holeCards
|
|
.map(
|
|
normalizeCardRank
|
|
)
|
|
.sort();
|
|
|
|
return (
|
|
ranks[0] === "2"
|
|
&&
|
|
ranks[1] === "7"
|
|
);
|
|
}
|
|
|
|
|
|
function getPotSizeFromResult(
|
|
result
|
|
) {
|
|
return Object.values(
|
|
result?.payouts ?? {}
|
|
).reduce(
|
|
(sum, value) =>
|
|
sum +
|
|
Number(value ?? 0),
|
|
0
|
|
);
|
|
}
|
|
|
|
|
|
function getPlayerOutcome(
|
|
game,
|
|
handPlayer
|
|
) {
|
|
const hand =
|
|
game?.data?.hand;
|
|
|
|
const result =
|
|
hand?.result ??
|
|
game?.data?.lastHandResult;
|
|
|
|
const winnerSeats =
|
|
Array.isArray(
|
|
result?.winnerSeats
|
|
)
|
|
? result.winnerSeats
|
|
: [];
|
|
|
|
const isWinner =
|
|
winnerSeats.includes(
|
|
handPlayer.seat
|
|
);
|
|
|
|
const isSplitWinner =
|
|
isWinner
|
|
&&
|
|
winnerSeats.length > 1;
|
|
|
|
const finalStack =
|
|
Number(
|
|
handPlayer.stack ?? 0
|
|
);
|
|
|
|
const startingStack =
|
|
Number(
|
|
handPlayer.startingStack ?? 0
|
|
);
|
|
|
|
const profit =
|
|
finalStack -
|
|
startingStack;
|
|
|
|
const potSize =
|
|
getPotSizeFromResult(
|
|
result
|
|
);
|
|
|
|
let resultName =
|
|
"loss";
|
|
|
|
if (isSplitWinner) {
|
|
resultName =
|
|
"push";
|
|
}
|
|
|
|
else if (isWinner) {
|
|
resultName =
|
|
"win";
|
|
}
|
|
|
|
const reachedShowdown =
|
|
result?.type ===
|
|
"showdown"
|
|
&&
|
|
handPlayer.folded !==
|
|
true;
|
|
|
|
return {
|
|
result,
|
|
winnerSeats,
|
|
isWinner,
|
|
isSplitWinner,
|
|
resultName,
|
|
profit,
|
|
potSize,
|
|
reachedShowdown,
|
|
allIn:
|
|
handPlayer.allIn ===
|
|
true,
|
|
handRank:
|
|
handPlayer.handRank ??
|
|
null,
|
|
pocketAces:
|
|
isPocketAces(
|
|
handPlayer.holeCards
|
|
),
|
|
sevenDeuce:
|
|
isSevenDeuce(
|
|
handPlayer.holeCards
|
|
),
|
|
foldWin:
|
|
isWinner
|
|
&&
|
|
result?.type ===
|
|
"fold",
|
|
fullTableWin:
|
|
isWinner
|
|
&&
|
|
Array.isArray(hand?.players)
|
|
&&
|
|
hand.players.length === 6
|
|
};
|
|
}
|
|
|
|
|
|
async function recordPokerActionProfile(
|
|
game,
|
|
userId,
|
|
action
|
|
) {
|
|
const guildId =
|
|
game?.guildId;
|
|
|
|
const actionType =
|
|
normalizeActionType(
|
|
action
|
|
);
|
|
|
|
const statPath =
|
|
ACTION_STAT_PATHS[
|
|
actionType
|
|
];
|
|
|
|
const actionId =
|
|
getPokerActionId(
|
|
game
|
|
);
|
|
|
|
if (
|
|
!guildId
|
|
||
|
|
!userId
|
|
||
|
|
!statPath
|
|
||
|
|
!actionId
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
await ensurePokerProfileDocument(
|
|
String(userId),
|
|
String(guildId)
|
|
);
|
|
|
|
const {
|
|
stats
|
|
} =
|
|
getProfileCollections();
|
|
|
|
const result =
|
|
await stats.updateOne(
|
|
{
|
|
userId:
|
|
String(userId),
|
|
guildId:
|
|
String(guildId),
|
|
"games.poker.processedActions": {
|
|
$ne:
|
|
actionId
|
|
}
|
|
},
|
|
{
|
|
$inc: {
|
|
[statPath]:
|
|
1
|
|
},
|
|
$push: {
|
|
"games.poker.processedActions": {
|
|
$each: [
|
|
actionId
|
|
],
|
|
$slice:
|
|
-PROFILE_ACTION_HISTORY_LIMIT
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
return (
|
|
result.modifiedCount ===
|
|
1
|
|
);
|
|
}
|
|
|
|
|
|
async function repairProfileBestStreaks(
|
|
userId,
|
|
guildId
|
|
) {
|
|
const {
|
|
stats
|
|
} =
|
|
getProfileCollections();
|
|
|
|
const current =
|
|
await stats.findOne(
|
|
{
|
|
userId,
|
|
guildId
|
|
},
|
|
{
|
|
projection: {
|
|
"games.poker.currentWinStreak":
|
|
1,
|
|
"games.poker.currentLossStreak":
|
|
1,
|
|
"streaks.currentWin":
|
|
1,
|
|
"streaks.currentLoss":
|
|
1
|
|
}
|
|
}
|
|
);
|
|
|
|
await stats.updateOne(
|
|
{
|
|
userId,
|
|
guildId
|
|
},
|
|
{
|
|
$max: {
|
|
"games.poker.bestWinStreak":
|
|
Number(
|
|
current
|
|
?.games
|
|
?.poker
|
|
?.currentWinStreak ??
|
|
0
|
|
),
|
|
"games.poker.bestLossStreak":
|
|
Number(
|
|
current
|
|
?.games
|
|
?.poker
|
|
?.currentLossStreak ??
|
|
0
|
|
),
|
|
"streaks.bestWin":
|
|
Number(
|
|
current
|
|
?.streaks
|
|
?.currentWin ??
|
|
0
|
|
),
|
|
"streaks.bestLoss":
|
|
Number(
|
|
current
|
|
?.streaks
|
|
?.currentLoss ??
|
|
0
|
|
)
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
async function recordPokerHandForPlayer(
|
|
game,
|
|
handPlayer
|
|
) {
|
|
const guildId =
|
|
String(
|
|
game.guildId
|
|
);
|
|
|
|
const userId =
|
|
String(
|
|
handPlayer.userId
|
|
);
|
|
|
|
const handId =
|
|
getPokerHandId(
|
|
game
|
|
);
|
|
|
|
if (!handId) {
|
|
return {
|
|
processed: false,
|
|
userId,
|
|
reason:
|
|
"INVALID_HAND_ID"
|
|
};
|
|
}
|
|
|
|
await ensurePokerProfileDocument(
|
|
userId,
|
|
guildId
|
|
);
|
|
|
|
const outcome =
|
|
getPlayerOutcome(
|
|
game,
|
|
handPlayer
|
|
);
|
|
|
|
const inc = {
|
|
"games.total.played":
|
|
1,
|
|
"games.poker.played":
|
|
1,
|
|
"games.poker.handsPlayed":
|
|
1
|
|
};
|
|
|
|
if (
|
|
outcome.resultName ===
|
|
"win"
|
|
) {
|
|
inc[
|
|
"games.total.won"
|
|
] = 1;
|
|
|
|
inc[
|
|
"games.poker.won"
|
|
] = 1;
|
|
|
|
inc[
|
|
"games.poker.handsWon"
|
|
] = 1;
|
|
}
|
|
|
|
else if (
|
|
outcome.resultName ===
|
|
"loss"
|
|
) {
|
|
inc[
|
|
"games.total.lost"
|
|
] = 1;
|
|
|
|
inc[
|
|
"games.poker.lost"
|
|
] = 1;
|
|
|
|
inc[
|
|
"games.poker.handsLost"
|
|
] = 1;
|
|
}
|
|
|
|
else {
|
|
inc[
|
|
"games.total.pushed"
|
|
] = 1;
|
|
|
|
inc[
|
|
"games.poker.pushed"
|
|
] = 1;
|
|
|
|
inc[
|
|
"games.poker.handsPushed"
|
|
] = 1;
|
|
}
|
|
|
|
const set = {};
|
|
|
|
if (
|
|
outcome.resultName ===
|
|
"win"
|
|
) {
|
|
inc[
|
|
"games.poker.currentWinStreak"
|
|
] = 1;
|
|
|
|
inc[
|
|
"streaks.currentWin"
|
|
] = 1;
|
|
|
|
set[
|
|
"games.poker.currentLossStreak"
|
|
] = 0;
|
|
|
|
set[
|
|
"streaks.currentLoss"
|
|
] = 0;
|
|
}
|
|
|
|
else if (
|
|
outcome.resultName ===
|
|
"loss"
|
|
) {
|
|
inc[
|
|
"games.poker.currentLossStreak"
|
|
] = 1;
|
|
|
|
inc[
|
|
"streaks.currentLoss"
|
|
] = 1;
|
|
|
|
set[
|
|
"games.poker.currentWinStreak"
|
|
] = 0;
|
|
|
|
set[
|
|
"streaks.currentWin"
|
|
] = 0;
|
|
}
|
|
|
|
if (
|
|
outcome.profit > 0
|
|
) {
|
|
inc[
|
|
"games.poker.cookiesWon"
|
|
] =
|
|
outcome.profit;
|
|
|
|
inc[
|
|
"economy.cookiesObtainedTotal"
|
|
] =
|
|
outcome.profit;
|
|
}
|
|
|
|
else if (
|
|
outcome.profit < 0
|
|
) {
|
|
const loss =
|
|
Math.abs(
|
|
outcome.profit
|
|
);
|
|
|
|
inc[
|
|
"games.poker.cookiesLost"
|
|
] =
|
|
loss;
|
|
|
|
inc[
|
|
"economy.cookiesLostTotal"
|
|
] =
|
|
loss;
|
|
}
|
|
|
|
if (
|
|
outcome.reachedShowdown
|
|
) {
|
|
inc[
|
|
"games.poker.showdowns"
|
|
] = 1;
|
|
|
|
if (outcome.isWinner) {
|
|
inc[
|
|
"games.poker.showdownWins"
|
|
] = 1;
|
|
}
|
|
}
|
|
|
|
if (
|
|
outcome.allIn
|
|
) {
|
|
inc[
|
|
"games.poker.allIns"
|
|
] = 1;
|
|
|
|
if (outcome.isWinner) {
|
|
inc[
|
|
"games.poker.allInWins"
|
|
] = 1;
|
|
}
|
|
}
|
|
|
|
if (
|
|
outcome.foldWin
|
|
) {
|
|
inc[
|
|
"games.poker.foldWins"
|
|
] = 1;
|
|
}
|
|
|
|
if (
|
|
outcome.fullTableWin
|
|
) {
|
|
inc[
|
|
"games.poker.fullTableWins"
|
|
] = 1;
|
|
}
|
|
|
|
if (
|
|
outcome.isWinner
|
|
&&
|
|
outcome.pocketAces
|
|
) {
|
|
inc[
|
|
"games.poker.pocketAcesWins"
|
|
] = 1;
|
|
}
|
|
|
|
if (
|
|
outcome.isWinner
|
|
&&
|
|
outcome.sevenDeuce
|
|
) {
|
|
inc[
|
|
"games.poker.sevenDeuceWins"
|
|
] = 1;
|
|
}
|
|
|
|
const handRankPath =
|
|
HAND_RANK_STAT_PATHS[
|
|
outcome.handRank?.name
|
|
];
|
|
|
|
if (
|
|
outcome.reachedShowdown
|
|
&&
|
|
handRankPath
|
|
) {
|
|
inc[
|
|
handRankPath
|
|
] = 1;
|
|
}
|
|
|
|
const {
|
|
stats
|
|
} =
|
|
getProfileCollections();
|
|
|
|
const update = {
|
|
$inc:
|
|
inc,
|
|
...(Object.keys(set).length
|
|
? {
|
|
$set:
|
|
set
|
|
}
|
|
: {}),
|
|
$push: {
|
|
"games.poker.processedHands": {
|
|
$each: [
|
|
handId
|
|
],
|
|
$slice:
|
|
-PROFILE_HAND_HISTORY_LIMIT
|
|
}
|
|
}
|
|
};
|
|
|
|
if (outcome.isWinner) {
|
|
update.$max = {
|
|
"games.poker.largestPotWon":
|
|
outcome.potSize
|
|
};
|
|
}
|
|
|
|
const write =
|
|
await stats.updateOne(
|
|
{
|
|
userId,
|
|
guildId,
|
|
"games.poker.processedHands": {
|
|
$ne:
|
|
handId
|
|
}
|
|
},
|
|
update
|
|
);
|
|
|
|
if (
|
|
write.modifiedCount !==
|
|
1
|
|
) {
|
|
await repairProfileBestStreaks(
|
|
userId,
|
|
guildId
|
|
);
|
|
|
|
return {
|
|
processed: false,
|
|
userId,
|
|
handId,
|
|
outcome
|
|
};
|
|
}
|
|
|
|
await repairProfileBestStreaks(
|
|
userId,
|
|
guildId
|
|
);
|
|
|
|
try {
|
|
await trackGameActivity(
|
|
userId,
|
|
guildId
|
|
);
|
|
}
|
|
|
|
catch (error) {
|
|
console.error(
|
|
`[PokerProfile] Activity tracking failed for ${userId}:`,
|
|
error
|
|
);
|
|
}
|
|
|
|
return {
|
|
processed: true,
|
|
userId,
|
|
handId,
|
|
outcome
|
|
};
|
|
}
|
|
|
|
|
|
async function recordPokerHandProfiles(
|
|
game
|
|
) {
|
|
const hand =
|
|
game?.data?.hand;
|
|
|
|
if (
|
|
!hand
|
|
||
|
|
hand.state !==
|
|
"PAYOUT"
|
|
||
|
|
!hand.result
|
|
||
|
|
!Array.isArray(
|
|
hand.players
|
|
)
|
|
) {
|
|
return [];
|
|
}
|
|
|
|
const results = [];
|
|
|
|
for (
|
|
const handPlayer
|
|
of hand.players
|
|
) {
|
|
try {
|
|
results.push(
|
|
await recordPokerHandForPlayer(
|
|
game,
|
|
handPlayer
|
|
)
|
|
);
|
|
}
|
|
|
|
catch (error) {
|
|
console.error(
|
|
`[PokerProfile] Failed to record hand ${getPokerHandId(game) ?? "unknown"} for ${handPlayer.userId}:`,
|
|
error
|
|
);
|
|
|
|
results.push({
|
|
processed: false,
|
|
userId:
|
|
String(
|
|
handPlayer.userId
|
|
),
|
|
error
|
|
});
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
|
|
async function claimPokerBadge(
|
|
context,
|
|
userId,
|
|
badgeId,
|
|
metadata = null
|
|
) {
|
|
const guildId =
|
|
context?.guildId;
|
|
|
|
if (!guildId) {
|
|
return false;
|
|
}
|
|
|
|
const {
|
|
badges
|
|
} =
|
|
getProfileCollections();
|
|
|
|
const set = {
|
|
ownerId:
|
|
String(userId),
|
|
unlockedAt:
|
|
getUnixTime()
|
|
};
|
|
|
|
if (
|
|
metadata
|
|
&&
|
|
typeof metadata ===
|
|
"object"
|
|
) {
|
|
set.metadata =
|
|
metadata;
|
|
}
|
|
|
|
const badge =
|
|
await badges.findOneAndUpdate(
|
|
{
|
|
guildId:
|
|
String(guildId),
|
|
badgeId,
|
|
ownerId:
|
|
null
|
|
},
|
|
{
|
|
$set:
|
|
set
|
|
},
|
|
{
|
|
returnDocument:
|
|
"after"
|
|
}
|
|
);
|
|
|
|
if (
|
|
!badge
|
|
||
|
|
badge.ownerId !==
|
|
String(userId)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
!context.channel
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
await context.channel.send({
|
|
embeds: [
|
|
new EmbedBuilder()
|
|
.setTitle(
|
|
"🏅 Unique Badge Claimed!"
|
|
)
|
|
.setDescription(
|
|
[
|
|
`${badge.emoji ?? "♠️"} **${badge.name ?? badge.badgeId}**`,
|
|
"",
|
|
`<@${userId}> claimed a guild-unique Poker badge!`,
|
|
"",
|
|
badge.description ??
|
|
"A unique Poker badge has been claimed.",
|
|
"",
|
|
"*This badge can no longer be earned by another player.*"
|
|
].join("\n")
|
|
)
|
|
.setFooter({
|
|
text:
|
|
`badge:${badge.badgeId}`
|
|
})
|
|
.setTimestamp()
|
|
]
|
|
});
|
|
}
|
|
|
|
catch (error) {
|
|
console.error(
|
|
`[PokerBadge] Failed to announce ${badgeId} for ${userId}:`,
|
|
error
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
async function evaluatePokerBadges(
|
|
context,
|
|
userId,
|
|
outcome
|
|
) {
|
|
const {
|
|
stats
|
|
} =
|
|
getProfileCollections();
|
|
|
|
const document =
|
|
await stats.findOne({
|
|
userId:
|
|
String(userId),
|
|
guildId:
|
|
String(context.guildId)
|
|
});
|
|
|
|
const poker =
|
|
document?.games?.poker ?? {};
|
|
|
|
if (
|
|
Number(
|
|
poker.won ?? 0
|
|
) >= 1
|
|
) {
|
|
await claimPokerBadge(
|
|
context,
|
|
userId,
|
|
"first_poker_win"
|
|
);
|
|
}
|
|
|
|
if (
|
|
Number(
|
|
poker.allInWins ?? 0
|
|
) >= 1
|
|
) {
|
|
await claimPokerBadge(
|
|
context,
|
|
userId,
|
|
"first_poker_allin_win"
|
|
);
|
|
}
|
|
|
|
if (
|
|
Number(
|
|
poker.pocketAcesWins ?? 0
|
|
) >= 1
|
|
) {
|
|
await claimPokerBadge(
|
|
context,
|
|
userId,
|
|
"first_poker_pocket_aces_win"
|
|
);
|
|
}
|
|
|
|
if (
|
|
Number(
|
|
poker.handRanks
|
|
?.royalFlush ?? 0
|
|
) >= 1
|
|
) {
|
|
await claimPokerBadge(
|
|
context,
|
|
userId,
|
|
"first_poker_royal_flush"
|
|
);
|
|
}
|
|
|
|
if (
|
|
Number(
|
|
poker.fullTableWins ?? 0
|
|
) >= 1
|
|
) {
|
|
await claimPokerBadge(
|
|
context,
|
|
userId,
|
|
"first_poker_full_table_win"
|
|
);
|
|
}
|
|
|
|
if (
|
|
Number(
|
|
poker.largestPotWon ?? 0
|
|
) >= 5000
|
|
) {
|
|
await claimPokerBadge(
|
|
context,
|
|
userId,
|
|
"first_poker_5000_pot",
|
|
{
|
|
pot:
|
|
outcome?.potSize ??
|
|
poker.largestPotWon
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
async function claimPokerAnnouncement(
|
|
game,
|
|
userId
|
|
) {
|
|
const handId =
|
|
getPokerHandId(
|
|
game
|
|
);
|
|
|
|
if (!handId) {
|
|
return false;
|
|
}
|
|
|
|
const {
|
|
stats
|
|
} =
|
|
getProfileCollections();
|
|
|
|
const result =
|
|
await stats.updateOne(
|
|
{
|
|
userId:
|
|
String(userId),
|
|
guildId:
|
|
String(game.guildId),
|
|
"games.poker.announcedHands": {
|
|
$ne:
|
|
handId
|
|
}
|
|
},
|
|
{
|
|
$push: {
|
|
"games.poker.announcedHands": {
|
|
$each: [
|
|
handId
|
|
],
|
|
$slice:
|
|
-PROFILE_HAND_HISTORY_LIMIT
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
return (
|
|
result.modifiedCount ===
|
|
1
|
|
);
|
|
}
|
|
|
|
|
|
async function announcePokerHandProgress(
|
|
context,
|
|
game
|
|
) {
|
|
if (
|
|
!context?.guildId
|
|
||
|
|
!game?.data?.hand
|
|
||
|
|
game.data.hand.state !==
|
|
"PAYOUT"
|
|
||
|
|
!Array.isArray(
|
|
game.data.hand.players
|
|
)
|
|
) {
|
|
return [];
|
|
}
|
|
|
|
const results = [];
|
|
|
|
for (
|
|
const handPlayer
|
|
of game.data.hand.players
|
|
) {
|
|
const userId =
|
|
String(
|
|
handPlayer.userId
|
|
);
|
|
|
|
try {
|
|
const claimed =
|
|
await claimPokerAnnouncement(
|
|
game,
|
|
userId
|
|
);
|
|
|
|
if (!claimed) {
|
|
continue;
|
|
}
|
|
|
|
const outcome =
|
|
getPlayerOutcome(
|
|
game,
|
|
handPlayer
|
|
);
|
|
|
|
await trackProfileEvent(
|
|
context,
|
|
userId,
|
|
{
|
|
type:
|
|
"profile_refresh",
|
|
source:
|
|
"poker",
|
|
game:
|
|
POKER_GAME_KEY,
|
|
result:
|
|
outcome.resultName,
|
|
profit:
|
|
outcome.profit,
|
|
allIn:
|
|
outcome.allIn,
|
|
handRank:
|
|
outcome.handRank?.name ??
|
|
null,
|
|
pocketAces:
|
|
outcome.pocketAces,
|
|
sevenDeuce:
|
|
outcome.sevenDeuce,
|
|
foldWin:
|
|
outcome.foldWin,
|
|
fullTableWin:
|
|
outcome.fullTableWin,
|
|
pot:
|
|
outcome.potSize
|
|
}
|
|
);
|
|
|
|
await evaluatePokerBadges(
|
|
context,
|
|
userId,
|
|
outcome
|
|
);
|
|
|
|
results.push({
|
|
userId,
|
|
announced: true
|
|
});
|
|
}
|
|
|
|
catch (error) {
|
|
console.error(
|
|
`[PokerProfile] Failed to refresh achievements/badges for ${userId}:`,
|
|
error
|
|
);
|
|
|
|
results.push({
|
|
userId,
|
|
announced: false,
|
|
error
|
|
});
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
|
|
async function createPokerProfileContext(
|
|
client,
|
|
game
|
|
) {
|
|
if (
|
|
!client
|
|
||
|
|
!game?.guildId
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
let channel =
|
|
null;
|
|
|
|
if (
|
|
game.channelId
|
|
) {
|
|
try {
|
|
channel =
|
|
await client.channels.fetch(
|
|
game.channelId
|
|
);
|
|
}
|
|
|
|
catch {}
|
|
}
|
|
|
|
return {
|
|
guildId:
|
|
String(game.guildId),
|
|
channel,
|
|
replied:
|
|
false,
|
|
deferred:
|
|
false
|
|
};
|
|
}
|
|
|
|
|
|
module.exports = {
|
|
ensurePokerProfileDocument,
|
|
getPokerHandId,
|
|
getPokerActionId,
|
|
getPlayerOutcome,
|
|
|
|
recordPokerActionProfile,
|
|
recordPokerHandProfiles,
|
|
announcePokerHandProgress,
|
|
createPokerProfileContext,
|
|
|
|
claimPokerBadge,
|
|
evaluatePokerBadges
|
|
};
|