added new logic to the new rewards

This commit is contained in:
DeSqBlocki
2026-08-23 00:43:43 +02:00
parent 4d858554be
commit 425686ec40
15 changed files with 1644 additions and 2662 deletions
+30 -27
View File
@@ -1,51 +1,54 @@
const { const {
requireProfileOwner,
buildAchievementsEmbed, buildAchievementsEmbed,
buildProfileButtons, buildProfileButtons,
buildProfilePaginationButtons getProfileContextFromFooter,
} = require("../../utils/profileSystem"); requireProfileOwner
} = require(
"../../utils/profileSystem"
);
module.exports = { module.exports = {
name: "profileAchievements", name:
"profileAchievements",
async execute(interaction) { async execute(
const session = await requireProfileOwner( interaction
) {
const context =
await requireProfileOwner(
interaction interaction
); );
if (!session) { if (!context) {
return; return;
} }
const user = await interaction.client.users.fetch( const user =
session.profileUserId await interaction.client.users.fetch(
context.profileUserId
); );
const result = await buildAchievementsEmbed( const embed =
await buildAchievementsEmbed(
interaction.guildId, interaction.guildId,
user, user,
0, context.sessionOwnerId,
session.sessionOwnerId 0
); );
const components = [ const pageContext =
...buildProfileButtons() getProfileContextFromFooter(
]; embed.data.footer?.text
if (result.pageCount > 1) {
components.push(
buildProfilePaginationButtons(
"profileAchievementsLeft",
"profileAchievementsRight",
result.page,
result.pageCount
)
); );
}
return interaction.update({ return interaction.update({
embeds: [result.embed], embeds: [embed],
components components:
buildProfileButtons(
"achievements",
pageContext?.page ?? 0,
pageContext?.pageCount ?? 1
)
}); });
} }
}; };
+30 -29
View File
@@ -1,53 +1,54 @@
// buttons/profile/achievementsLeft.js
const { const {
requireProfileOwner,
buildAchievementsEmbed, buildAchievementsEmbed,
buildProfileButtons, buildProfileButtons,
buildProfilePaginationButtons getProfileContextFromFooter,
} = require("../../utils/profileSystem"); requireProfileOwner
} = require(
"../../utils/profileSystem"
);
module.exports = { module.exports = {
name: "profileAchievementsLeft", name:
"profileAchievementsLeft",
async execute(interaction) { async execute(
const session = await requireProfileOwner( interaction
) {
const context =
await requireProfileOwner(
interaction interaction
); );
if (!session) { if (!context) {
return; return;
} }
const user = await interaction.client.users.fetch( const user =
session.profileUserId await interaction.client.users.fetch(
context.profileUserId
); );
const result = await buildAchievementsEmbed( const embed =
await buildAchievementsEmbed(
interaction.guildId, interaction.guildId,
user, user,
session.page - 1, context.sessionOwnerId,
session.sessionOwnerId context.page - 1
); );
const components = [ const pageContext =
...buildProfileButtons() getProfileContextFromFooter(
]; embed.data.footer?.text
if (result.pageCount > 1) {
components.push(
buildProfilePaginationButtons(
"profileAchievementsLeft",
"profileAchievementsRight",
result.page,
result.pageCount
)
); );
}
return interaction.update({ return interaction.update({
embeds: [result.embed], embeds: [embed],
components components:
buildProfileButtons(
"achievements",
pageContext?.page ?? 0,
pageContext?.pageCount ?? 1
)
}); });
} }
}; };
+30 -29
View File
@@ -1,53 +1,54 @@
// buttons/profile/achievementsRight.js
const { const {
requireProfileOwner,
buildAchievementsEmbed, buildAchievementsEmbed,
buildProfileButtons, buildProfileButtons,
buildProfilePaginationButtons getProfileContextFromFooter,
} = require("../../utils/profileSystem"); requireProfileOwner
} = require(
"../../utils/profileSystem"
);
module.exports = { module.exports = {
name: "profileAchievementsRight", name:
"profileAchievementsRight",
async execute(interaction) { async execute(
const session = await requireProfileOwner( interaction
) {
const context =
await requireProfileOwner(
interaction interaction
); );
if (!session) { if (!context) {
return; return;
} }
const user = await interaction.client.users.fetch( const user =
session.profileUserId await interaction.client.users.fetch(
context.profileUserId
); );
const result = await buildAchievementsEmbed( const embed =
await buildAchievementsEmbed(
interaction.guildId, interaction.guildId,
user, user,
session.page + 1, context.sessionOwnerId,
session.sessionOwnerId context.page + 1
); );
const components = [ const pageContext =
...buildProfileButtons() getProfileContextFromFooter(
]; embed.data.footer?.text
if (result.pageCount > 1) {
components.push(
buildProfilePaginationButtons(
"profileAchievementsLeft",
"profileAchievementsRight",
result.page,
result.pageCount
)
); );
}
return interaction.update({ return interaction.update({
embeds: [result.embed], embeds: [embed],
components components:
buildProfileButtons(
"achievements",
pageContext?.page ?? 0,
pageContext?.pageCount ?? 1
)
}); });
} }
}; };
+30 -27
View File
@@ -1,51 +1,54 @@
const { const {
requireProfileOwner,
buildBadgesEmbed, buildBadgesEmbed,
buildProfileButtons, buildProfileButtons,
buildProfilePaginationButtons getProfileContextFromFooter,
} = require("../../utils/profileSystem"); requireProfileOwner
} = require(
"../../utils/profileSystem"
);
module.exports = { module.exports = {
name: "profileBadges", name:
"profileBadges",
async execute(interaction) { async execute(
const session = await requireProfileOwner( interaction
) {
const context =
await requireProfileOwner(
interaction interaction
); );
if (!session) { if (!context) {
return; return;
} }
const user = await interaction.client.users.fetch( const user =
session.profileUserId await interaction.client.users.fetch(
context.profileUserId
); );
const result = await buildBadgesEmbed( const embed =
await buildBadgesEmbed(
interaction.guildId, interaction.guildId,
user, user,
0, context.sessionOwnerId,
session.sessionOwnerId 0
); );
const components = [ const pageContext =
...buildProfileButtons() getProfileContextFromFooter(
]; embed.data.footer?.text
if (result.pageCount > 1) {
components.push(
buildProfilePaginationButtons(
"profileBadgesLeft",
"profileBadgesRight",
result.page,
result.pageCount
)
); );
}
return interaction.update({ return interaction.update({
embeds: [result.embed], embeds: [embed],
components components:
buildProfileButtons(
"badges",
pageContext?.page ?? 0,
pageContext?.pageCount ?? 1
)
}); });
} }
}; };
+30 -29
View File
@@ -1,53 +1,54 @@
// buttons/profile/badgesLeft.js
const { const {
requireProfileOwner,
buildBadgesEmbed, buildBadgesEmbed,
buildProfileButtons, buildProfileButtons,
buildProfilePaginationButtons getProfileContextFromFooter,
} = require("../../utils/profileSystem"); requireProfileOwner
} = require(
"../../utils/profileSystem"
);
module.exports = { module.exports = {
name: "profileBadgesLeft", name:
"profileBadgesLeft",
async execute(interaction) { async execute(
const session = await requireProfileOwner( interaction
) {
const context =
await requireProfileOwner(
interaction interaction
); );
if (!session) { if (!context) {
return; return;
} }
const user = await interaction.client.users.fetch( const user =
session.profileUserId await interaction.client.users.fetch(
context.profileUserId
); );
const result = await buildBadgesEmbed( const embed =
await buildBadgesEmbed(
interaction.guildId, interaction.guildId,
user, user,
session.page - 1, context.sessionOwnerId,
session.sessionOwnerId context.page - 1
); );
const components = [ const pageContext =
...buildProfileButtons() getProfileContextFromFooter(
]; embed.data.footer?.text
if (result.pageCount > 1) {
components.push(
buildProfilePaginationButtons(
"profileBadgesLeft",
"profileBadgesRight",
result.page,
result.pageCount
)
); );
}
return interaction.update({ return interaction.update({
embeds: [result.embed], embeds: [embed],
components components:
buildProfileButtons(
"badges",
pageContext?.page ?? 0,
pageContext?.pageCount ?? 1
)
}); });
} }
}; };
+30 -29
View File
@@ -1,53 +1,54 @@
// buttons/profile/badgesRight.js
const { const {
requireProfileOwner,
buildBadgesEmbed, buildBadgesEmbed,
buildProfileButtons, buildProfileButtons,
buildProfilePaginationButtons getProfileContextFromFooter,
} = require("../../utils/profileSystem"); requireProfileOwner
} = require(
"../../utils/profileSystem"
);
module.exports = { module.exports = {
name: "profileBadgesRight", name:
"profileBadgesRight",
async execute(interaction) { async execute(
const session = await requireProfileOwner( interaction
) {
const context =
await requireProfileOwner(
interaction interaction
); );
if (!session) { if (!context) {
return; return;
} }
const user = await interaction.client.users.fetch( const user =
session.profileUserId await interaction.client.users.fetch(
context.profileUserId
); );
const result = await buildBadgesEmbed( const embed =
await buildBadgesEmbed(
interaction.guildId, interaction.guildId,
user, user,
session.page + 1, context.sessionOwnerId,
session.sessionOwnerId context.page + 1
); );
const components = [ const pageContext =
...buildProfileButtons() getProfileContextFromFooter(
]; embed.data.footer?.text
if (result.pageCount > 1) {
components.push(
buildProfilePaginationButtons(
"profileBadgesLeft",
"profileBadgesRight",
result.page,
result.pageCount
)
); );
}
return interaction.update({ return interaction.update({
embeds: [result.embed], embeds: [embed],
components components:
buildProfileButtons(
"badges",
pageContext?.page ?? 0,
pageContext?.pageCount ?? 1
)
}); });
} }
}; };
+26 -13
View File
@@ -1,34 +1,47 @@
const { const {
requireProfileOwner, buildStatsEmbed,
buildProfileStatsEmbed, buildProfileButtons,
buildProfileButtons requireProfileOwner
} = require("../../utils/profileSystem"); } = require(
"../../utils/profileSystem"
);
module.exports = { module.exports = {
name: "profileStats", name:
"profileStats",
async execute(interaction) { async execute(
const session = await requireProfileOwner( interaction
) {
const context =
await requireProfileOwner(
interaction interaction
); );
if (!session) { if (!context) {
return; return;
} }
const user = await interaction.client.users.fetch( const user =
session.profileUserId await interaction.client.users.fetch(
context.profileUserId
); );
const embed = await buildProfileStatsEmbed( const embed =
await buildStatsEmbed(
interaction.guildId, interaction.guildId,
user, user,
session.sessionOwnerId context.sessionOwnerId
); );
return interaction.update({ return interaction.update({
embeds: [embed], embeds: [embed],
components: buildProfileButtons() components:
buildProfileButtons(
"stats",
0,
1
)
}); });
} }
}; };
+46 -29
View File
@@ -1,46 +1,63 @@
const { SlashCommandBuilder } = require("discord.js"); const {
SlashCommandBuilder
} = require(
"discord.js"
);
const { const {
buildProfileOverview, buildProfileOverview,
buildProfileButtons buildProfileButtons
} = require("../../utils/profileSystem"); } = require(
const { "../../utils/profileSystem"
createInteractionSession );
} = require("../../utils/interactionSession");
module.exports = { module.exports = {
data: new SlashCommandBuilder() data:
.setName("profile") new SlashCommandBuilder()
.setDescription("View a player profile") .setName(
.addUserOption(option => "profile"
)
.setDescription(
"View a player profile"
)
.addUserOption(
option =>
option option
.setName("user") .setName(
.setDescription("Player to view") "user"
)
.setDescription(
"Player to view"
)
), ),
async execute(interaction) { async execute(
const user = interaction.options.getUser("user") ?? interaction.user; interaction
) {
const user =
interaction.options.getUser(
"user"
) ??
interaction.user;
const embed = await buildProfileOverview( const sessionOwnerId =
interaction.user.id;
const embed =
await buildProfileOverview(
interaction.guildId, interaction.guildId,
user, user,
interaction.user.id sessionOwnerId
); );
await interaction.reply({ return interaction.reply({
embeds: [embed], embeds: [embed],
components: buildProfileButtons() components:
buildProfileButtons(
"overview",
0,
1
)
}); });
const message = await interaction.fetchReply();
await createInteractionSession(
interaction,
{
messageId: message.id,
ownerId: interaction.user.id,
kind: "profile",
targetId: user.id
}
);
} }
}; };
+173 -325
View File
@@ -1,415 +1,263 @@
const { const {
SlashCommandBuilder, SlashCommandBuilder,
MessageFlags PermissionFlagsBits,
} = require( MessageFlags,
"discord.js" EmbedBuilder
); } = require("discord.js");
const { const {
requireAdminAccess reconcileUserAchievements,
reconcileAllAchievements,
auditProfileData
} = require( } = require(
"../../utils/permissions" "../../utils/profileMaintenance"
); );
const {
reconcileProfileAchievements,
auditProfileSystem
} = require(
"../../utils/profileSystem"
);
/*
* ============================================================
* COMMAND
* ============================================================
*/
module.exports = { module.exports = {
data: data:
new SlashCommandBuilder() new SlashCommandBuilder()
.setName( .setName(
"profileadmin" "profileadmin"
) )
.setDescription( .setDescription(
"Profile and achievement administration." "Administrative profile maintenance tools"
)
.setDefaultMemberPermissions(
PermissionFlagsBits.Administrator
) )
/*
* =================================================
* RECONCILE
* =================================================
*/
.addSubcommand( .addSubcommand(
subcommand => subcommand =>
subcommand subcommand
.setName( .setName(
"reconcile" "reconcile"
) )
.setDescription( .setDescription(
"Re-evaluate stored statistics for achievements." "Backfill database-trackable achievements"
) )
.addUserOption( .addUserOption(
option => option =>
option option
.setName( .setName(
"user" "user"
) )
.setDescription( .setDescription(
"Only reconcile this user's profile." "Only reconcile this user; omit for everyone"
)
.setRequired(
false
) )
) )
.addBooleanOption( .addBooleanOption(
option => option =>
option option
.setName( .setName(
"dry-run" "dry-run"
) )
.setDescription( .setDescription(
"Show what would change without unlocking anything." "Show what would change without writing it"
)
.setRequired(
false
) )
) )
) )
/*
* =================================================
* AUDIT
* =================================================
*/
.addSubcommand( .addSubcommand(
subcommand => subcommand =>
subcommand subcommand
.setName( .setName(
"audit" "audit"
) )
.setDescription( .setDescription(
"Audit the profile and achievement system." "Audit stored profile statistics for inconsistencies"
) )
), ),
/*
* ========================================================
* EXECUTE
* ========================================================
*/
async execute( async execute(
interaction interaction
) { ) {
/*
* Runtime authorization.
*
* This intentionally replaces:
*
* .setDefaultMemberPermissions(
* PermissionFlagsBits.Administrator
* )
*
* so BOT_AUTHOR_ID can also invoke the command.
*/
if (
!await requireAdminAccess(
interaction
)
) {
return;
}
const subcommand = const subcommand =
interaction.options interaction.options.getSubcommand();
.getSubcommand();
switch (
subcommand
) {
case "reconcile":
return runReconcile(
interaction
);
case "audit":
return runAudit(
interaction
);
default:
return interaction.reply({
content:
"Unknown profile administration action.",
await interaction.deferReply({
flags: flags:
MessageFlags.Ephemeral MessageFlags.Ephemeral
}); });
}
}
};
if (
/* subcommand ===
* ============================================================ "reconcile"
* RECONCILE ) {
* ============================================================ const user =
*/
async function runReconcile(
interaction
) {
const target =
interaction.options.getUser( interaction.options.getUser(
"user" "user"
); );
const dryRun = const dryRun =
interaction.options.getBoolean( interaction.options.getBoolean(
"dry-run" "dry-run"
) ) ?? false;
??
false;
if (user) {
/*
* This can touch multiple Mongo documents,
* so acknowledge the interaction first.
*/
await interaction.deferReply({
flags:
MessageFlags.Ephemeral
});
try {
const result = const result =
await reconcileProfileAchievements( await reconcileUserAchievements({
guildId:
interaction.guildId, interaction.guildId,
{
userId: userId:
target?.id user.id,
??
null,
dryRun dryRun
} });
);
const lines = [
dryRun
? "### 🔎 Profile Reconciliation — Dry Run"
: "### ✅ Profile Reconciliation Complete",
"",
target
? `Target: ${target}`
: "Target: **Entire Guild**",
"",
`Profiles checked: **${result.profilesChecked ?? 0}**`,
`Achievement unlocks found: **${result.unlocksFound ?? 0}**`
];
if (
!dryRun
) {
lines.push(
`Achievements unlocked: **${result.unlocksApplied ?? 0}**`
);
}
if (
result.skippedEventOnly !==
undefined
) {
lines.push(
`Event-only checks skipped: **${result.skippedEventOnly}**`
);
}
if (
Array.isArray(
result.details
)
&&
result.details.length >
0
) {
const preview =
result.details
.slice(
0,
15
)
.map(
entry => {
if (
typeof entry ===
"string"
) {
return `• ${entry}`;
}
return (
`• <@${entry.userId}> — ` +
`${entry.achievementName ?? entry.achievementId}`
);
}
);
lines.push(
"",
"### Changes",
...preview
);
if (
result.details.length >
preview.length
) {
lines.push(
"",
`*...and ${result.details.length - preview.length} more.*`
);
}
}
return interaction.editReply({ return interaction.editReply({
content: embeds: [
lines.join( new EmbedBuilder()
"\n" .setTitle(
"🛠️ Profile Reconciliation"
) )
}); .setDescription(
`${dryRun ? "Dry run for" : "Reconciled"} ${user}.`
} catch (error) { )
console.error( .addFields(
"[ProfileAdmin] Reconciliation failed:", {
error name:
); "New unlocks",
value:
`**${result.unlocked}**`,
return interaction.editReply({ inline:
content: true
"Profile reconciliation failed. Check the bot logs for details." },
{
name:
"Definitions checked",
value:
`**${result.checked}**`,
inline:
true
},
{
name:
"Event-only skipped",
value:
`**${result.skippedEventOnly}**`,
inline:
true
}
)
]
}); });
} }
}
const summary =
/* await reconcileAllAchievements({
* ============================================================ guildId:
* AUDIT interaction.guildId,
* ============================================================ dryRun
*/
async function runAudit(
interaction
) {
await interaction.deferReply({
flags:
MessageFlags.Ephemeral
}); });
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle(
"🛠️ Profile Reconciliation"
)
.setDescription(
`${dryRun ? "Dry run completed" : "Reconciliation completed"} for stored profile users.`
)
.addFields(
{
name:
"Users",
value:
`**${summary.users}**`,
inline:
true
},
{
name:
"New unlocks",
value:
`**${summary.unlocked}**`,
inline:
true
},
{
name:
"Event-only checks skipped",
value:
`**${summary.skippedEventOnly}**`,
inline:
true
}
)
]
});
}
try { const audit =
const result = await auditProfileData(
await auditProfileSystem(
interaction.guildId interaction.guildId
); );
const issuePreview =
const lines = [ audit.issues
"### 🧾 Profile System Audit", .slice(0, 10)
"", .join("\n");
`Profile documents: **${result.profileDocuments ?? 0}**`,
`Achievement documents: **${result.achievementDocuments ?? 0}**`,
`Active achievement definitions: **${result.activeAchievements ?? 0}**`,
`Legacy achievement definitions: **${result.legacyAchievements ?? 0}**`,
`Guild badges: **${result.badges ?? 0}**`,
`Claimed badges: **${result.claimedBadges ?? 0}**`,
`Available badges: **${result.availableBadges ?? 0}**`
];
if (
Array.isArray(
result.warnings
)
&&
result.warnings.length >
0
) {
lines.push(
"",
"### ⚠️ Warnings",
...result.warnings.map(
warning =>
`• ${warning}`
)
);
}
else {
lines.push(
"",
"✅ No obvious profile-system issues were found."
);
}
return interaction.editReply({ return interaction.editReply({
content: embeds: [
lines.join( new EmbedBuilder()
"\n" .setTitle(
"🔎 Profile Data Audit"
) )
}); .addFields(
{
} catch (error) { name:
console.error( "Stats documents",
"[ProfileAdmin] Audit failed:", value:
error `**${audit.statDocuments}**`,
); inline:
true
},
return interaction.editReply({ {
content: name:
"Profile audit failed. Check the bot logs for details." "Achievement documents",
value:
`**${audit.achievementDocuments}**`,
inline:
true
},
{
name:
"Active achievements",
value:
`**${audit.activeAchievements}**`,
inline:
true
},
{
name:
"Global badges",
value:
`**${audit.badgeDocuments}** (${audit.claimedBadges} claimed)`,
inline:
true
},
{
name:
"Orphan achievement docs",
value:
`**${audit.orphanAchievementDocs}**`,
inline:
true
},
{
name:
"Issues",
value:
`**${audit.issueCount}**`,
inline:
true
}
)
.setDescription(
issuePreview
? `First issues:\n${issuePreview}`
: "No structural inconsistencies found."
)
]
}); });
} }
} };
+1 -1
View File
@@ -16,7 +16,7 @@ module.exports = {
"records" "records"
) )
.setDescription( .setDescription(
"View Shai Cookie and Crumb Saucer records" "View Olymp Cookie and Crumb Saucer records"
) )
.addStringOption( .addStringOption(
option => option =>
+6 -6
View File
@@ -27,30 +27,30 @@ const HEIST_METHODS = {
baseChance: 0.65, baseChance: 0.65,
minStealPercent: 0.01, minStealPercent: 0.01,
maxStealPercent: 0.03, maxStealPercent: 0.03,
maxStealAmount: 5000, maxStealAmount: 1500,
minPenaltyPercent: 0.01, minPenaltyPercent: 0.01,
maxPenaltyPercent: 0.04, maxPenaltyPercent: 0.04,
maxPenaltyAmount: 1500 maxPenaltyAmount: 750
}, },
Hack: { Hack: {
baseChance: 0.45, baseChance: 0.45,
minStealPercent: 0.03, minStealPercent: 0.03,
maxStealPercent: 0.06, maxStealPercent: 0.06,
maxStealAmount: 12500, maxStealAmount: 3500,
minPenaltyPercent: 0.03, minPenaltyPercent: 0.03,
maxPenaltyPercent: 0.07, maxPenaltyPercent: 0.07,
maxPenaltyAmount: 4000 maxPenaltyAmount: 2000
}, },
Smash: { Smash: {
baseChance: 0.25, baseChance: 0.25,
minStealPercent: 0.06, minStealPercent: 0.06,
maxStealPercent: 0.12, maxStealPercent: 0.12,
maxStealAmount: 25000, maxStealAmount: 7500,
minPenaltyPercent: 0.06, minPenaltyPercent: 0.06,
maxPenaltyPercent: 0.12, maxPenaltyPercent: 0.12,
maxPenaltyAmount: 10000 maxPenaltyAmount: 5000
} }
}; };
+80 -10
View File
@@ -18,7 +18,8 @@ const {
} = require("./cookieEconomy"); } = require("./cookieEconomy");
const { const {
recordGameOutcome recordGameOutcome,
trackProfileEvent
} = require("./profileSystem"); } = require("./profileSystem");
const GAME_COLLECTION = const GAME_COLLECTION =
@@ -112,7 +113,9 @@ async function startBlackjack(
interaction, interaction,
bet, bet,
allowCustomBet = false, allowCustomBet = false,
allIn = false source = "normal",
previousAllIn = false,
previousBet = 0
) { ) {
if ( if (
!allowCustomBet && !allowCustomBet &&
@@ -196,6 +199,9 @@ async function startBlackjack(
getCookieBalance(houseId) getCookieBalance(houseId)
]); ]);
const allIn =
bet === playerBalance;
if (playerBalance < bet) { if (playerBalance < bet) {
return temporaryEphemeralReply( return temporaryEphemeralReply(
interaction, interaction,
@@ -276,6 +282,11 @@ async function startBlackjack(
doubled: doubled:
false, false,
allIn, allIn,
vaultAtBet:
playerBalance,
source,
previousAllIn,
previousBet,
deck, deck,
playerCards, playerCards,
dealerCards, dealerCards,
@@ -285,6 +296,20 @@ async function startBlackjack(
await games.insertOne(game); await games.insertOne(game);
await trackProfileEvent(
interaction,
playerId,
{
type: "game_start",
game: "blackjack",
source,
bet,
allIn,
previousAllIn,
previousBet
}
);
const playerBlackjack = const playerBlackjack =
isBlackjack(playerCards); isBlackjack(playerCards);
@@ -370,7 +395,7 @@ async function startBlackjackAllIn(
interaction, interaction,
balance, balance,
true, true,
true "all_in"
); );
} }
@@ -405,6 +430,9 @@ async function runBlackjackBack(
const bet = const bet =
Number(parts[2]); Number(parts[2]);
const previousAllIn =
parts[3] === "1";
if ( if (
ownerId !== ownerId !==
interaction.user.id interaction.user.id
@@ -435,7 +463,9 @@ async function runBlackjackBack(
interaction, interaction,
bet, bet,
true, true,
false "run_it_back",
previousAllIn,
bet
); );
} }
@@ -803,6 +833,32 @@ async function finishBlackjack(
game, game,
result result
) { ) {
const { db } = getCollections();
const claim = await db
.collection(GAME_COLLECTION)
.updateOne(
{
gameId: game.gameId,
state: "Playing"
},
{
$set: {
state: "Resolving"
}
}
);
if (claim.modifiedCount !== 1) {
return temporaryEphemeralReply(
interaction,
{
content:
"This Blackjack hand is already being resolved."
}
);
}
const houseId = const houseId =
interaction.client.user.id; interaction.client.user.id;
@@ -845,6 +901,23 @@ async function finishBlackjack(
`[Blackjack] House cannot cover payout ${payout} for ${game.userId}` `[Blackjack] House cannot cover payout ${payout} for ${game.userId}`
); );
await db
.collection(GAME_COLLECTION)
.updateOne(
{
gameId: game.gameId,
state: "Resolving"
},
{
$set: {
state: "Finished",
result: "PayoutError",
payout: 0,
finishedAt: getUnixTime()
}
}
);
return interaction.update({ return interaction.update({
embeds: [ embeds: [
new EmbedBuilder() new EmbedBuilder()
@@ -856,7 +929,7 @@ async function finishBlackjack(
) )
.setFooter({ .setFooter({
text: text:
`crumbBlackjackResult:${game.userId}:${game.originalBet}` `crumbBlackjackResult:${game.userId}:${game.originalBet}:${game.allIn ? 1 : 0}`
}) })
], ],
components: components:
@@ -871,9 +944,6 @@ async function finishBlackjack(
); );
} }
const { db } =
getCollections();
await db await db
.collection( .collection(
GAME_COLLECTION GAME_COLLECTION
@@ -883,7 +953,7 @@ async function finishBlackjack(
gameId: gameId:
game.gameId, game.gameId,
state: state:
"Playing" "Resolving"
}, },
{ {
$set: { $set: {
@@ -1010,7 +1080,7 @@ async function finishBlackjack(
) )
.setFooter({ .setFooter({
text: text:
`crumbBlackjackResult:${game.userId}:${game.originalBet}` `crumbBlackjackResult:${game.userId}:${game.originalBet}:${game.allIn ? 1 : 0}`
}); });
return interaction.update({ return interaction.update({
+36 -8
View File
@@ -12,7 +12,8 @@ const {
} = require("./cookieEconomy"); } = require("./cookieEconomy");
const { const {
recordGameOutcome recordGameOutcome,
trackProfileEvent
} = require("./profileSystem"); } = require("./profileSystem");
const ROULETTE_BETS = [ const ROULETTE_BETS = [
@@ -206,7 +207,10 @@ async function startRouletteAllIn(
async function showRouletteChoices( async function showRouletteChoices(
interaction, interaction,
bet, bet,
allIn = false requestedAllIn = false,
source = "normal",
previousAllIn = false,
previousBet = 0
) { ) {
if ( if (
!Number.isSafeInteger(bet) || !Number.isSafeInteger(bet) ||
@@ -262,7 +266,7 @@ async function showRouletteChoices(
}) })
.setFooter({ .setFooter({
text: text:
`crumbRouletteBet:${interaction.user.id}:${bet}:${allIn ? 1 : 0}` `crumbRouletteBet:${interaction.user.id}:${bet}:${requestedAllIn ? 1 : 0}:${source}:${previousAllIn ? 1 : 0}:${previousBet}`
}); });
return interaction.update({ return interaction.update({
@@ -303,6 +307,9 @@ async function runRouletteBack(
const bet = const bet =
Number(parts[2]); Number(parts[2]);
const previousAllIn =
parts[3] === "1";
if ( if (
ownerId !== ownerId !==
interaction.user.id interaction.user.id
@@ -383,8 +390,14 @@ async function playRoulette(
const bet = const bet =
Number(parts[2]); Number(parts[2]);
const allIn = const source =
parts[3] === "1"; parts[4] || "normal";
const previousAllIn =
parts[5] === "1";
const previousBet =
Number(parts[6] ?? 0);
if ( if (
ownerId !== ownerId !==
@@ -476,6 +489,23 @@ async function playRoulette(
throw error; throw error;
} }
const allIn =
bet === playerBalance;
await trackProfileEvent(
interaction,
playerId,
{
type: "game_start",
game: "roulette",
source,
bet,
allIn,
previousAllIn,
previousBet
}
);
await interaction.update({ await interaction.update({
embeds: [ embeds: [
buildSpinEmbed( buildSpinEmbed(
@@ -594,8 +624,6 @@ async function playRoulette(
won && won &&
choiceKey === choiceKey ===
"Zero", "Zero",
allIn:
won &&
allIn allIn
} }
); );
@@ -664,7 +692,7 @@ async function playRoulette(
) )
.setFooter({ .setFooter({
text: text:
`crumbRouletteResult:${playerId}:${bet}` `crumbRouletteResult:${playerId}:${bet}:${allIn ? 1 : 0}`
}); });
return interaction.editReply({ return interaction.editReply({
+21 -3
View File
@@ -13,7 +13,8 @@ const {
} = require("./cookieEconomy"); } = require("./cookieEconomy");
const { const {
recordGameOutcome recordGameOutcome,
trackProfileEvent
} = require("./profileSystem"); } = require("./profileSystem");
const SLOT_BETS = [ const SLOT_BETS = [
@@ -104,7 +105,8 @@ async function showSlots(interaction) {
async function playSlots( async function playSlots(
interaction, interaction,
bet bet,
source = "normal"
) { ) {
const ownerId = const ownerId =
getSlotsSessionOwner( getSlotsSessionOwner(
@@ -197,6 +199,17 @@ async function playSlots(
throw error; throw error;
} }
await trackProfileEvent(
interaction,
playerId,
{
type: "game_start",
game: "slots",
source,
bet
}
);
await interaction.update({ await interaction.update({
embeds: [ embeds: [
buildSpinningEmbed( buildSpinningEmbed(
@@ -321,6 +334,10 @@ async function playSlots(
? "loss" ? "loss"
: "push", : "push",
profit, profit,
triplet:
outcome.type === "triple"
? outcome.symbol
: null,
jackpot: jackpot:
outcome.type === outcome.type ===
"triple" && "triple" &&
@@ -460,7 +477,8 @@ async function runSlotsBack(
return playSlots( return playSlots(
interaction, interaction,
bet bet,
"run_it_back"
); );
} }
+926 -1948
View File
File diff suppressed because it is too large Load Diff