profile update with badges and achievements
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
const {
|
||||
buildStatsEmbed,
|
||||
buildProfileButtons,
|
||||
getProfileTargetId
|
||||
} = require("../../utils/profileSystem");
|
||||
|
||||
module.exports = {
|
||||
name: "profileStats",
|
||||
|
||||
async execute(interaction) {
|
||||
const userId = getProfileTargetId(interaction);
|
||||
if (!userId) return;
|
||||
|
||||
const user = await interaction.client.users.fetch(userId);
|
||||
const embed = await buildStatsEmbed(interaction.guildId, user);
|
||||
|
||||
return interaction.update({
|
||||
embeds: [embed],
|
||||
components: buildProfileButtons()
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -18,6 +18,10 @@ const {
|
||||
formatPercentage
|
||||
} = require("../../utils/cookieEconomy");
|
||||
|
||||
const {
|
||||
trackProfileEvent
|
||||
} = require("../../utils/profileSystem");
|
||||
|
||||
|
||||
const COLLECT_COOLDOWN =
|
||||
60 * 60;
|
||||
@@ -214,6 +218,15 @@ async function collect(interaction) {
|
||||
amount
|
||||
);
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
userId,
|
||||
{
|
||||
type: "cookie_gain",
|
||||
amount
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const nextCollect =
|
||||
await setCooldown(
|
||||
@@ -456,6 +469,44 @@ async function steal(interaction) {
|
||||
}
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
user.id,
|
||||
{
|
||||
type: "steal_success",
|
||||
amount,
|
||||
targetUserId: target.id
|
||||
}
|
||||
);
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
user.id,
|
||||
{
|
||||
type: "cookie_gain",
|
||||
amount
|
||||
}
|
||||
);
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
target.id,
|
||||
{
|
||||
type: "stolen_from_me",
|
||||
amount,
|
||||
thiefUserId: user.id
|
||||
}
|
||||
);
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
target.id,
|
||||
{
|
||||
type: "cookie_loss",
|
||||
amount
|
||||
}
|
||||
);
|
||||
|
||||
const [
|
||||
yourBalanceAfter,
|
||||
targetBalanceAfter
|
||||
@@ -605,6 +656,24 @@ async function steal(interaction) {
|
||||
}
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
user.id,
|
||||
{
|
||||
type: "cookie_loss",
|
||||
amount: penalty
|
||||
}
|
||||
);
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
target.id,
|
||||
{
|
||||
type: "cookie_gain",
|
||||
amount: penalty
|
||||
}
|
||||
);
|
||||
|
||||
const [
|
||||
yourBalanceAfter,
|
||||
targetBalanceAfter
|
||||
@@ -851,6 +920,24 @@ async function give(interaction) {
|
||||
}
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
user.id,
|
||||
{
|
||||
type: "cookies_given",
|
||||
amount
|
||||
}
|
||||
);
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
target.id,
|
||||
{
|
||||
type: "cookie_gain",
|
||||
amount
|
||||
}
|
||||
);
|
||||
|
||||
const [
|
||||
yourBalance,
|
||||
theirBalance
|
||||
|
||||
@@ -14,6 +14,10 @@ const {
|
||||
formatPercentage
|
||||
} = require("./cookieEconomy");
|
||||
|
||||
const {
|
||||
trackProfileEvent
|
||||
} = require("./profileSystem");
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
@@ -394,6 +398,46 @@ async function resolveCookieHeist(
|
||||
100;
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
playerId,
|
||||
{
|
||||
type:
|
||||
"game_result",
|
||||
|
||||
game:
|
||||
"heist",
|
||||
|
||||
result:
|
||||
"win"
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
playerId,
|
||||
{
|
||||
type:
|
||||
"vault_steal",
|
||||
|
||||
amount
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
playerId,
|
||||
{
|
||||
type:
|
||||
"cookie_gain",
|
||||
|
||||
amount
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const embed =
|
||||
new EmbedBuilder()
|
||||
.setTitle(
|
||||
@@ -605,6 +649,35 @@ async function resolveCookieHeist(
|
||||
100;
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
playerId,
|
||||
{
|
||||
type:
|
||||
"game_result",
|
||||
|
||||
game:
|
||||
"heist",
|
||||
|
||||
result:
|
||||
"loss"
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
playerId,
|
||||
{
|
||||
type:
|
||||
"cookie_loss",
|
||||
|
||||
amount:
|
||||
penalty
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const embed =
|
||||
new EmbedBuilder()
|
||||
.setTitle(
|
||||
|
||||
+88
-2
@@ -17,6 +17,10 @@ const {
|
||||
getUnixTime
|
||||
} = require("./cookieEconomy");
|
||||
|
||||
const {
|
||||
trackProfileEvent
|
||||
} = require("./profileSystem");
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
@@ -1277,7 +1281,7 @@ async function finishBlackjack(
|
||||
|
||||
.setFooter({
|
||||
text:
|
||||
`crumbBlackjackResult:${game.userId}:${game.bet}`
|
||||
`crumbBlackjackResult:${game.userId}:${game.originalBet ?? game.bet}`
|
||||
})
|
||||
],
|
||||
|
||||
@@ -1350,6 +1354,88 @@ async function finishBlackjack(
|
||||
game.bet;
|
||||
|
||||
|
||||
let profileResult;
|
||||
|
||||
if (
|
||||
result ===
|
||||
"Push"
|
||||
) {
|
||||
profileResult =
|
||||
"push";
|
||||
}
|
||||
|
||||
else if (
|
||||
[
|
||||
"Win",
|
||||
"DealerBust",
|
||||
"Blackjack"
|
||||
].includes(
|
||||
result
|
||||
)
|
||||
) {
|
||||
profileResult =
|
||||
"win";
|
||||
}
|
||||
|
||||
else {
|
||||
profileResult =
|
||||
"loss";
|
||||
}
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
game.userId,
|
||||
{
|
||||
type:
|
||||
"game_result",
|
||||
|
||||
game:
|
||||
"blackjack",
|
||||
|
||||
result:
|
||||
profileResult
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
if (
|
||||
profit >
|
||||
0
|
||||
) {
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
game.userId,
|
||||
{
|
||||
type:
|
||||
"cookie_gain",
|
||||
|
||||
amount:
|
||||
profit
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
else if (
|
||||
profit <
|
||||
0
|
||||
) {
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
game.userId,
|
||||
{
|
||||
type:
|
||||
"cookie_loss",
|
||||
|
||||
amount:
|
||||
Math.abs(
|
||||
profit
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const description = [
|
||||
"**Dealer**",
|
||||
formatCards(
|
||||
@@ -1439,7 +1525,7 @@ async function finishBlackjack(
|
||||
|
||||
.setFooter({
|
||||
text:
|
||||
`crumbBlackjackResult:${game.userId}:${game.bet}`
|
||||
`crumbBlackjackResult:${game.userId}:${game.originalBet ?? game.bet}`
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ const {
|
||||
temporaryEphemeralReply
|
||||
} = require("./cookieEconomy");
|
||||
|
||||
const {
|
||||
trackProfileEvent
|
||||
} = require("./profileSystem");
|
||||
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
@@ -852,6 +856,63 @@ async function playRoulette(
|
||||
bet;
|
||||
|
||||
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
playerId,
|
||||
{
|
||||
type:
|
||||
"game_result",
|
||||
|
||||
game:
|
||||
"roulette",
|
||||
|
||||
result:
|
||||
profit > 0
|
||||
? "win"
|
||||
: profit < 0
|
||||
? "loss"
|
||||
: "push"
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
if (
|
||||
profit >
|
||||
0
|
||||
) {
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
playerId,
|
||||
{
|
||||
type:
|
||||
"cookie_gain",
|
||||
|
||||
amount:
|
||||
profit
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
else if (
|
||||
profit <
|
||||
0
|
||||
) {
|
||||
await trackProfileEvent(
|
||||
interaction,
|
||||
playerId,
|
||||
{
|
||||
type:
|
||||
"cookie_loss",
|
||||
|
||||
amount:
|
||||
Math.abs(
|
||||
profit
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const resultEmbed =
|
||||
new EmbedBuilder()
|
||||
.setTitle(
|
||||
|
||||
+78
-1415
File diff suppressed because it is too large
Load Diff
+132
-23
@@ -21,6 +21,8 @@ const COLLECTIONS = {
|
||||
achievementConfig: "config_achievements"
|
||||
};
|
||||
|
||||
let profileSystemInitPromise = null;
|
||||
|
||||
const DEFAULT_ACHIEVEMENTS = [
|
||||
{ achievementId: "stolen_1000", name: "Light Fingers", description: "Steal 1,000 Cookies from other players.", requirement: "Steal 1,000 Cookies total.", category: "stealing", stat: "economy.stolenTotal", target: 1000, emoji: "🧤" },
|
||||
{ achievementId: "stolen_10000", name: "Career Criminal", description: "Steal 10,000 Cookies from other players.", requirement: "Steal 10,000 Cookies total.", category: "stealing", stat: "economy.stolenTotal", target: 10000, emoji: "🕵️" },
|
||||
@@ -41,7 +43,15 @@ const DEFAULT_ACHIEVEMENTS = [
|
||||
{ achievementId: "win_streak_3", name: "On a Roll", description: "Win 3 games in a row.", requirement: "Reach a 3-game winning streak.", category: "games", stat: "streaks.bestWin", target: 3, emoji: "🍀" },
|
||||
{ achievementId: "win_streak_10", name: "Can't Stop Won't Stop", description: "Win 10 games in a row.", requirement: "Reach a 10-game winning streak.", category: "games", stat: "streaks.bestWin", target: 10, emoji: "🔥" },
|
||||
{ achievementId: "loss_streak_3", name: "Rough Night", description: "Lose 3 games in a row.", requirement: "Reach a 3-game losing streak.", category: "games", stat: "streaks.bestLoss", target: 3, emoji: "😬" },
|
||||
{ achievementId: "loss_streak_10", name: "Digging Deeper", description: "Lose 10 games in a row.", requirement: "Reach a 10-game losing streak.", category: "games", stat: "streaks.bestLoss", target: 10, emoji: "🕳️" }
|
||||
{ achievementId: "loss_streak_10", name: "Digging Deeper", description: "Lose 10 games in a row.", requirement: "Reach a 10-game losing streak.", category: "games", stat: "streaks.bestLoss", target: 10, emoji: "🕳️" },
|
||||
{ achievementId: "given_10000", name: "Sharing Is Caring", description: "Give 10,000 Cookies to other players.", requirement: "Give 10,000 Cookies to other players total.", category: "economy", stat: "economy.cookiesGivenTotal", target: 10000, emoji: "🎁" },
|
||||
{ achievementId: "given_50000", name: "Community Baker", description: "Give 50,000 Cookies to other players.", requirement: "Give 50,000 Cookies to other players total.", category: "economy", stat: "economy.cookiesGivenTotal", target: 50000, emoji: "🤝" },
|
||||
{ achievementId: "games_won_10", name: "House Regular", description: "Win 10 Crumb Saucer games.", requirement: "Win 10 games total.", category: "games", stat: "games.total.won", target: 10, emoji: "🎲" },
|
||||
{ achievementId: "games_won_50", name: "House Favorite", description: "Win 50 Crumb Saucer games.", requirement: "Win 50 games total.", category: "games", stat: "games.total.won", target: 50, emoji: "🏆" },
|
||||
{ achievementId: "slots_won_10", name: "Reel Deal", description: "Win 10 Slots spins.", requirement: "Win 10 Slots games.", category: "games", stat: "games.slots.won", target: 10, emoji: "🎰" },
|
||||
{ achievementId: "blackjack_won_10", name: "Card Counter-ish", description: "Win 10 Blackjack hands.", requirement: "Win 10 Blackjack games.", category: "games", stat: "games.blackjack.won", target: 10, emoji: "🃏" },
|
||||
{ achievementId: "roulette_won_10", name: "Wheel Watcher", description: "Win 10 Roulette bets.", requirement: "Win 10 Roulette games.", category: "games", stat: "games.roulette.won", target: 10, emoji: "🎡" },
|
||||
{ achievementId: "heist_won_10", name: "Professional", description: "Complete 10 successful Vault Heists.", requirement: "Win 10 Vault Heists.", category: "games", stat: "games.heist.won", target: 10, emoji: "🏦" }
|
||||
];
|
||||
|
||||
const DEFAULT_BADGES = [
|
||||
@@ -63,22 +73,34 @@ function getProfileCollections() {
|
||||
}
|
||||
|
||||
async function ensureProfileSystem() {
|
||||
const { stats, achievements, badges, achievementConfig } = getProfileCollections();
|
||||
await stats.createIndex({ userId: 1, guildId: 1 }, { unique: true });
|
||||
await achievements.createIndex({ userId: 1, guildId: 1 }, { unique: true });
|
||||
await badges.createIndex({ guildId: 1, badgeId: 1 }, { unique: true });
|
||||
await achievementConfig.createIndex({ achievementId: 1 }, { unique: true });
|
||||
if (profileSystemInitPromise) return profileSystemInitPromise;
|
||||
|
||||
for (const achievement of DEFAULT_ACHIEVEMENTS) {
|
||||
await achievementConfig.updateOne(
|
||||
{ achievementId: achievement.achievementId },
|
||||
{ $setOnInsert: achievement },
|
||||
{ upsert: true }
|
||||
);
|
||||
profileSystemInitPromise = (async () => {
|
||||
const { stats, achievements, badges, achievementConfig } = getProfileCollections();
|
||||
await stats.createIndex({ userId: 1, guildId: 1 }, { unique: true });
|
||||
await achievements.createIndex({ userId: 1, guildId: 1 }, { unique: true });
|
||||
await badges.createIndex({ guildId: 1, badgeId: 1 }, { unique: true });
|
||||
await achievementConfig.createIndex({ achievementId: 1 }, { unique: true });
|
||||
|
||||
for (const achievement of DEFAULT_ACHIEVEMENTS) {
|
||||
await achievementConfig.updateOne(
|
||||
{ achievementId: achievement.achievementId },
|
||||
{ $setOnInsert: achievement },
|
||||
{ upsert: true }
|
||||
);
|
||||
}
|
||||
})();
|
||||
|
||||
try {
|
||||
return await profileSystemInitPromise;
|
||||
} catch (error) {
|
||||
profileSystemInitPromise = null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureGuildBadges(guildId) {
|
||||
await ensureProfileSystem();
|
||||
const { badges } = getProfileCollections();
|
||||
for (const badge of DEFAULT_BADGES) {
|
||||
await badges.updateOne(
|
||||
@@ -145,6 +167,7 @@ async function getProfileStats(userId, guildId) {
|
||||
}
|
||||
|
||||
async function trackProfileEvent(interaction, userId, event) {
|
||||
await ensureProfileSystem();
|
||||
const guildId = interaction.guildId;
|
||||
if (!guildId || !userId || !event?.type) return;
|
||||
|
||||
@@ -190,7 +213,7 @@ async function trackProfileEvent(interaction, userId, event) {
|
||||
}
|
||||
|
||||
const updatedStats = await getProfileStats(userId, guildId);
|
||||
await evaluateAchievements(interaction, userId, updatedStats);
|
||||
await evaluateAchievements(interaction, userId, updatedStats, event.type);
|
||||
await evaluateBadges(interaction, userId, updatedStats);
|
||||
return updatedStats;
|
||||
}
|
||||
@@ -244,12 +267,15 @@ async function trackGameResult(userId, guildId, event) {
|
||||
);
|
||||
}
|
||||
|
||||
async function evaluateAchievements(interaction, userId, statsDocument) {
|
||||
async function evaluateAchievements(interaction, userId, statsDocument, eventType = null) {
|
||||
const { achievements, achievementConfig } = getProfileCollections();
|
||||
const guildId = interaction.guildId;
|
||||
await ensureAchievementDocument(userId, guildId);
|
||||
|
||||
const definitions = await achievementConfig.find({}).toArray();
|
||||
const relevantStats = getRelevantAchievementStats(eventType);
|
||||
const definitions = await achievementConfig.find(
|
||||
relevantStats ? { stat: { $in: relevantStats } } : {}
|
||||
).toArray();
|
||||
const unlockedDoc = await achievements.findOne({ userId, guildId });
|
||||
const unlocked = unlockedDoc?.unlocked ?? {};
|
||||
|
||||
@@ -265,7 +291,7 @@ async function evaluateAchievements(interaction, userId, statsDocument) {
|
||||
);
|
||||
|
||||
if (result.modifiedCount === 1) {
|
||||
await sendAchievementNotification(interaction, definition);
|
||||
await sendAchievementNotification(interaction, userId, definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,23 +340,38 @@ async function tryClaimBadge(interaction, userId, badgeId) {
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function sendAchievementNotification(interaction, achievement) {
|
||||
async function sendAchievementNotification(interaction, userId, achievement) {
|
||||
try {
|
||||
await interaction.followUp({
|
||||
await interaction.channel.send({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setTitle("🏆 Achievement Unlocked!")
|
||||
.setDescription([
|
||||
`<@${userId}>`,
|
||||
"",
|
||||
`${achievement.emoji} **${achievement.name}**`,
|
||||
"",
|
||||
achievement.description
|
||||
].join("\n"))
|
||||
],
|
||||
flags: MessageFlags.Ephemeral
|
||||
]
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
|
||||
function getRelevantAchievementStats(eventType) {
|
||||
switch (eventType) {
|
||||
case "cookie_gain": return ["economy.cookiesObtainedTotal"];
|
||||
case "cookie_loss": return ["economy.cookiesLostTotal"];
|
||||
case "cookies_given": return ["economy.cookiesGivenTotal"];
|
||||
case "steal_success": return ["economy.stolenTotal", "unique.playersStolenFrom"];
|
||||
case "stolen_from_me": return ["economy.stolenFromMeTotal", "unique.playersStolenBy"];
|
||||
case "vault_steal": return ["economy.vaultStolenTotal"];
|
||||
case "game_result": return ["streaks.bestWin", "streaks.bestLoss", "games.total.won", "games.slots.won", "games.blackjack.won", "games.roulette.won", "games.heist.won"];
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
function readStatValue(document, definition) {
|
||||
const value = definition.stat
|
||||
.split(".")
|
||||
@@ -344,6 +385,7 @@ function readStatValue(document, definition) {
|
||||
}
|
||||
|
||||
async function buildProfileOverview(guildId, user) {
|
||||
await ensureProfileSystem();
|
||||
const stats = await getProfileStats(user.id, guildId);
|
||||
const balance = await getCookieBalance(user.id);
|
||||
const { achievements, badges, achievementConfig } = getProfileCollections();
|
||||
@@ -386,6 +428,7 @@ async function buildProfileOverview(guildId, user) {
|
||||
}
|
||||
|
||||
async function buildBadgesEmbed(guildId, user) {
|
||||
await ensureProfileSystem();
|
||||
await ensureGuildBadges(guildId);
|
||||
const { badges } = getProfileCollections();
|
||||
const documents = await badges.find({ guildId }).toArray();
|
||||
@@ -416,6 +459,7 @@ async function buildBadgesEmbed(guildId, user) {
|
||||
}
|
||||
|
||||
async function buildAchievementsEmbed(guildId, user) {
|
||||
await ensureProfileSystem();
|
||||
const { achievements, achievementConfig } = getProfileCollections();
|
||||
|
||||
const [unlockedDoc, definitions] = await Promise.all([
|
||||
@@ -424,9 +468,16 @@ async function buildAchievementsEmbed(guildId, user) {
|
||||
]);
|
||||
|
||||
const unlocked = unlockedDoc?.unlocked ?? {};
|
||||
const lines = definitions.map(a =>
|
||||
`${unlocked[a.achievementId] ? "✅" : "⬜"} ${a.emoji} **${a.name}** — ${a.requirement}`
|
||||
);
|
||||
const stats = await getProfileStats(user.id, guildId);
|
||||
const lines = definitions.map(a => {
|
||||
const complete = Boolean(unlocked[a.achievementId]);
|
||||
const current = readStatValue(stats, a);
|
||||
const progress = complete
|
||||
? "Unlocked"
|
||||
: `${Math.min(current, a.target).toLocaleString()} / ${a.target.toLocaleString()}`;
|
||||
|
||||
return `${complete ? "✅" : "⬜"} ${a.emoji} **${a.name}** — ${a.requirement}\n↳ ${progress}`;
|
||||
});
|
||||
|
||||
return new EmbedBuilder()
|
||||
.setTitle(`🏆 ${user.globalName ?? user.username}'s Achievements`)
|
||||
@@ -434,10 +485,67 @@ async function buildAchievementsEmbed(guildId, user) {
|
||||
.setFooter({ text: `profile:${user.id}` });
|
||||
}
|
||||
|
||||
async function buildStatsEmbed(guildId, user) {
|
||||
await ensureProfileSystem();
|
||||
const stats = await getProfileStats(user.id, guildId);
|
||||
const e = stats.economy;
|
||||
const g = stats.games;
|
||||
|
||||
return new EmbedBuilder()
|
||||
.setTitle(`📊 ${user.globalName ?? user.username}'s Statistics`)
|
||||
.setThumbnail(user.displayAvatarURL({ size: 256 }))
|
||||
.addFields(
|
||||
{
|
||||
name: "🍪 Economy",
|
||||
value: [
|
||||
`Obtained: **${e.cookiesObtainedTotal.toLocaleString()}**`,
|
||||
`Lost: **${e.cookiesLostTotal.toLocaleString()}**`,
|
||||
`Given: **${e.cookiesGivenTotal.toLocaleString()}**`,
|
||||
`Stolen: **${e.stolenTotal.toLocaleString()}**`,
|
||||
`Stolen from you: **${e.stolenFromMeTotal.toLocaleString()}**`,
|
||||
`Bot Vault stolen: **${e.vaultStolenTotal.toLocaleString()}**`
|
||||
].join("\n")
|
||||
},
|
||||
{
|
||||
name: "🥷 Theft",
|
||||
value: [
|
||||
`Unique victims: **${stats.unique.playersStolenFrom.length}**`,
|
||||
`Unique thieves: **${stats.unique.playersStolenBy.length}**`
|
||||
].join("\n"),
|
||||
inline: true
|
||||
},
|
||||
{
|
||||
name: "🔥 Streaks",
|
||||
value: [
|
||||
`Current wins: **${stats.streaks.currentWin}**`,
|
||||
`Best wins: **${stats.streaks.bestWin}**`,
|
||||
`Current losses: **${stats.streaks.currentLoss}**`,
|
||||
`Best losses: **${stats.streaks.bestLoss}**`
|
||||
].join("\n"),
|
||||
inline: true
|
||||
},
|
||||
{ name: "🎰 Slots", value: formatGameStats(g.slots), inline: true },
|
||||
{ name: "🃏 Blackjack", value: formatGameStats(g.blackjack), inline: true },
|
||||
{ name: "🎡 Roulette", value: formatGameStats(g.roulette), inline: true },
|
||||
{ name: "🏦 Heist", value: formatGameStats(g.heist), inline: true }
|
||||
)
|
||||
.setFooter({ text: `profile:${user.id}` });
|
||||
}
|
||||
|
||||
function formatGameStats(game) {
|
||||
return [
|
||||
`Played: **${game?.played ?? 0}**`,
|
||||
`Won: **${game?.won ?? 0}**`,
|
||||
`Lost: **${game?.lost ?? 0}**`,
|
||||
`Pushes: **${game?.pushed ?? 0}**`
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function buildProfileButtons() {
|
||||
return [
|
||||
new ActionRowBuilder().addComponents(
|
||||
new ButtonBuilder().setCustomId("profileOverview").setLabel("Overview").setEmoji("👤").setStyle(ButtonStyle.Primary),
|
||||
new ButtonBuilder().setCustomId("profileStats").setLabel("Stats").setEmoji("📊").setStyle(ButtonStyle.Secondary),
|
||||
new ButtonBuilder().setCustomId("profileBadges").setLabel("Badges").setEmoji("🏅").setStyle(ButtonStyle.Secondary),
|
||||
new ButtonBuilder().setCustomId("profileAchievements").setLabel("Achievements").setEmoji("🏆").setStyle(ButtonStyle.Secondary),
|
||||
new ButtonBuilder().setCustomId("abort").setLabel("Close").setEmoji("✖️").setStyle(ButtonStyle.Secondary)
|
||||
@@ -457,6 +565,7 @@ module.exports = {
|
||||
trackProfileEvent,
|
||||
getProfileStats,
|
||||
buildProfileOverview,
|
||||
buildStatsEmbed,
|
||||
buildBadgesEmbed,
|
||||
buildAchievementsEmbed,
|
||||
buildProfileButtons,
|
||||
|
||||
Reference in New Issue
Block a user