updated badges
This commit is contained in:
@@ -1,22 +1,54 @@
|
|||||||
const {
|
const {
|
||||||
buildAchievementsEmbed,
|
buildAchievementsEmbed,
|
||||||
buildProfileButtons,
|
buildProfileButtons,
|
||||||
getProfileTargetId
|
getProfileContextFromFooter,
|
||||||
} = require("../../utils/profileSystem");
|
requireProfileOwner
|
||||||
|
} = require(
|
||||||
|
"../../utils/profileSystem"
|
||||||
|
);
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "profileAchievements",
|
name:
|
||||||
|
"profileAchievements",
|
||||||
|
|
||||||
async execute(interaction) {
|
async execute(
|
||||||
const userId = getProfileTargetId(interaction);
|
interaction
|
||||||
if (!userId) return;
|
) {
|
||||||
|
const context =
|
||||||
|
await requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
const user = await interaction.client.users.fetch(userId);
|
if (!context) {
|
||||||
const embed = await buildAchievementsEmbed(interaction.guildId, user);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user =
|
||||||
|
await interaction.client.users.fetch(
|
||||||
|
context.profileUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
await buildAchievementsEmbed(
|
||||||
|
interaction.guildId,
|
||||||
|
user,
|
||||||
|
context.sessionOwnerId,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const pageContext =
|
||||||
|
getProfileContextFromFooter(
|
||||||
|
embed.data.footer?.text
|
||||||
|
);
|
||||||
|
|
||||||
return interaction.update({
|
return interaction.update({
|
||||||
embeds: [embed],
|
embeds: [embed],
|
||||||
components: buildProfileButtons()
|
components:
|
||||||
|
buildProfileButtons(
|
||||||
|
"achievements",
|
||||||
|
pageContext?.page ?? 0,
|
||||||
|
pageContext?.pageCount ?? 1
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
const {
|
||||||
|
buildAchievementsEmbed,
|
||||||
|
buildProfileButtons,
|
||||||
|
getProfileContextFromFooter,
|
||||||
|
requireProfileOwner
|
||||||
|
} = require(
|
||||||
|
"../../utils/profileSystem"
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"profileAchievementsLeft",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const context =
|
||||||
|
await requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user =
|
||||||
|
await interaction.client.users.fetch(
|
||||||
|
context.profileUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
await buildAchievementsEmbed(
|
||||||
|
interaction.guildId,
|
||||||
|
user,
|
||||||
|
context.sessionOwnerId,
|
||||||
|
context.page - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
const pageContext =
|
||||||
|
getProfileContextFromFooter(
|
||||||
|
embed.data.footer?.text
|
||||||
|
);
|
||||||
|
|
||||||
|
return interaction.update({
|
||||||
|
embeds: [embed],
|
||||||
|
components:
|
||||||
|
buildProfileButtons(
|
||||||
|
"achievements",
|
||||||
|
pageContext?.page ?? 0,
|
||||||
|
pageContext?.pageCount ?? 1
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
const {
|
||||||
|
buildAchievementsEmbed,
|
||||||
|
buildProfileButtons,
|
||||||
|
getProfileContextFromFooter,
|
||||||
|
requireProfileOwner
|
||||||
|
} = require(
|
||||||
|
"../../utils/profileSystem"
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"profileAchievementsRight",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const context =
|
||||||
|
await requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user =
|
||||||
|
await interaction.client.users.fetch(
|
||||||
|
context.profileUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
await buildAchievementsEmbed(
|
||||||
|
interaction.guildId,
|
||||||
|
user,
|
||||||
|
context.sessionOwnerId,
|
||||||
|
context.page + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
const pageContext =
|
||||||
|
getProfileContextFromFooter(
|
||||||
|
embed.data.footer?.text
|
||||||
|
);
|
||||||
|
|
||||||
|
return interaction.update({
|
||||||
|
embeds: [embed],
|
||||||
|
components:
|
||||||
|
buildProfileButtons(
|
||||||
|
"achievements",
|
||||||
|
pageContext?.page ?? 0,
|
||||||
|
pageContext?.pageCount ?? 1
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,22 +1,54 @@
|
|||||||
const {
|
const {
|
||||||
buildBadgesEmbed,
|
buildBadgesEmbed,
|
||||||
buildProfileButtons,
|
buildProfileButtons,
|
||||||
getProfileTargetId
|
getProfileContextFromFooter,
|
||||||
} = require("../../utils/profileSystem");
|
requireProfileOwner
|
||||||
|
} = require(
|
||||||
|
"../../utils/profileSystem"
|
||||||
|
);
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "profileBadges",
|
name:
|
||||||
|
"profileBadges",
|
||||||
|
|
||||||
async execute(interaction) {
|
async execute(
|
||||||
const userId = getProfileTargetId(interaction);
|
interaction
|
||||||
if (!userId) return;
|
) {
|
||||||
|
const context =
|
||||||
|
await requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
const user = await interaction.client.users.fetch(userId);
|
if (!context) {
|
||||||
const embed = await buildBadgesEmbed(interaction.guildId, user);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user =
|
||||||
|
await interaction.client.users.fetch(
|
||||||
|
context.profileUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
await buildBadgesEmbed(
|
||||||
|
interaction.guildId,
|
||||||
|
user,
|
||||||
|
context.sessionOwnerId,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const pageContext =
|
||||||
|
getProfileContextFromFooter(
|
||||||
|
embed.data.footer?.text
|
||||||
|
);
|
||||||
|
|
||||||
return interaction.update({
|
return interaction.update({
|
||||||
embeds: [embed],
|
embeds: [embed],
|
||||||
components: buildProfileButtons()
|
components:
|
||||||
|
buildProfileButtons(
|
||||||
|
"badges",
|
||||||
|
pageContext?.page ?? 0,
|
||||||
|
pageContext?.pageCount ?? 1
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
const {
|
||||||
|
buildBadgesEmbed,
|
||||||
|
buildProfileButtons,
|
||||||
|
getProfileContextFromFooter,
|
||||||
|
requireProfileOwner
|
||||||
|
} = require(
|
||||||
|
"../../utils/profileSystem"
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"profileBadgesLeft",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const context =
|
||||||
|
await requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user =
|
||||||
|
await interaction.client.users.fetch(
|
||||||
|
context.profileUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
await buildBadgesEmbed(
|
||||||
|
interaction.guildId,
|
||||||
|
user,
|
||||||
|
context.sessionOwnerId,
|
||||||
|
context.page - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
const pageContext =
|
||||||
|
getProfileContextFromFooter(
|
||||||
|
embed.data.footer?.text
|
||||||
|
);
|
||||||
|
|
||||||
|
return interaction.update({
|
||||||
|
embeds: [embed],
|
||||||
|
components:
|
||||||
|
buildProfileButtons(
|
||||||
|
"badges",
|
||||||
|
pageContext?.page ?? 0,
|
||||||
|
pageContext?.pageCount ?? 1
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
const {
|
||||||
|
buildBadgesEmbed,
|
||||||
|
buildProfileButtons,
|
||||||
|
getProfileContextFromFooter,
|
||||||
|
requireProfileOwner
|
||||||
|
} = require(
|
||||||
|
"../../utils/profileSystem"
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"profileBadgesRight",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const context =
|
||||||
|
await requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user =
|
||||||
|
await interaction.client.users.fetch(
|
||||||
|
context.profileUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
await buildBadgesEmbed(
|
||||||
|
interaction.guildId,
|
||||||
|
user,
|
||||||
|
context.sessionOwnerId,
|
||||||
|
context.page + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
const pageContext =
|
||||||
|
getProfileContextFromFooter(
|
||||||
|
embed.data.footer?.text
|
||||||
|
);
|
||||||
|
|
||||||
|
return interaction.update({
|
||||||
|
embeds: [embed],
|
||||||
|
components:
|
||||||
|
buildProfileButtons(
|
||||||
|
"badges",
|
||||||
|
pageContext?.page ?? 0,
|
||||||
|
pageContext?.pageCount ?? 1
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
const {
|
||||||
|
EmbedBuilder
|
||||||
|
} = require(
|
||||||
|
"discord.js"
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
requireProfileOwner
|
||||||
|
} = require(
|
||||||
|
"../../utils/profileSystem"
|
||||||
|
);
|
||||||
|
|
||||||
|
function delay(
|
||||||
|
ms
|
||||||
|
) {
|
||||||
|
return new Promise(
|
||||||
|
resolve =>
|
||||||
|
setTimeout(
|
||||||
|
resolve,
|
||||||
|
ms
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"profileClose",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const context =
|
||||||
|
await requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.update({
|
||||||
|
embeds: [
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"Profile Closed"
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
"Closing profile..."
|
||||||
|
)
|
||||||
|
],
|
||||||
|
components: []
|
||||||
|
});
|
||||||
|
|
||||||
|
await delay(1200);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await interaction.deleteReply();
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,22 +1,47 @@
|
|||||||
const {
|
const {
|
||||||
buildProfileOverview,
|
buildProfileOverview,
|
||||||
buildProfileButtons,
|
buildProfileButtons,
|
||||||
getProfileTargetId
|
requireProfileOwner
|
||||||
} = require("../../utils/profileSystem");
|
} = require(
|
||||||
|
"../../utils/profileSystem"
|
||||||
|
);
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "profileOverview",
|
name:
|
||||||
|
"profileOverview",
|
||||||
|
|
||||||
async execute(interaction) {
|
async execute(
|
||||||
const userId = getProfileTargetId(interaction);
|
interaction
|
||||||
if (!userId) return;
|
) {
|
||||||
|
const context =
|
||||||
|
await requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
const user = await interaction.client.users.fetch(userId);
|
if (!context) {
|
||||||
const embed = await buildProfileOverview(interaction.guildId, user);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user =
|
||||||
|
await interaction.client.users.fetch(
|
||||||
|
context.profileUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
await buildProfileOverview(
|
||||||
|
interaction.guildId,
|
||||||
|
user,
|
||||||
|
context.sessionOwnerId
|
||||||
|
);
|
||||||
|
|
||||||
return interaction.update({
|
return interaction.update({
|
||||||
embeds: [embed],
|
embeds: [embed],
|
||||||
components: buildProfileButtons()
|
components:
|
||||||
|
buildProfileButtons(
|
||||||
|
"overview",
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,22 +1,47 @@
|
|||||||
const {
|
const {
|
||||||
buildStatsEmbed,
|
buildStatsEmbed,
|
||||||
buildProfileButtons,
|
buildProfileButtons,
|
||||||
getProfileTargetId
|
requireProfileOwner
|
||||||
} = require("../../utils/profileSystem");
|
} = require(
|
||||||
|
"../../utils/profileSystem"
|
||||||
|
);
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "profileStats",
|
name:
|
||||||
|
"profileStats",
|
||||||
|
|
||||||
async execute(interaction) {
|
async execute(
|
||||||
const userId = getProfileTargetId(interaction);
|
interaction
|
||||||
if (!userId) return;
|
) {
|
||||||
|
const context =
|
||||||
|
await requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
const user = await interaction.client.users.fetch(userId);
|
if (!context) {
|
||||||
const embed = await buildStatsEmbed(interaction.guildId, user);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user =
|
||||||
|
await interaction.client.users.fetch(
|
||||||
|
context.profileUserId
|
||||||
|
);
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
await buildStatsEmbed(
|
||||||
|
interaction.guildId,
|
||||||
|
user,
|
||||||
|
context.sessionOwnerId
|
||||||
|
);
|
||||||
|
|
||||||
return interaction.update({
|
return interaction.update({
|
||||||
embeds: [embed],
|
embeds: [embed],
|
||||||
components: buildProfileButtons()
|
components:
|
||||||
|
buildProfileButtons(
|
||||||
|
"stats",
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ const {
|
|||||||
"../../utils/profileSystem"
|
"../../utils/profileSystem"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
data:
|
data:
|
||||||
new SlashCommandBuilder()
|
new SlashCommandBuilder()
|
||||||
@@ -32,32 +31,33 @@ module.exports = {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
async execute(
|
async execute(
|
||||||
interaction
|
interaction
|
||||||
) {
|
) {
|
||||||
const user =
|
const user =
|
||||||
interaction.options.getUser(
|
interaction.options.getUser(
|
||||||
"user"
|
"user"
|
||||||
)
|
) ??
|
||||||
??
|
|
||||||
interaction.user;
|
interaction.user;
|
||||||
|
|
||||||
|
const sessionOwnerId =
|
||||||
|
interaction.user.id;
|
||||||
|
|
||||||
const embed =
|
const embed =
|
||||||
await buildProfileOverview(
|
await buildProfileOverview(
|
||||||
interaction.guildId,
|
interaction.guildId,
|
||||||
user
|
user,
|
||||||
|
sessionOwnerId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
embeds: [
|
embeds: [embed],
|
||||||
embed
|
|
||||||
],
|
|
||||||
|
|
||||||
components:
|
components:
|
||||||
buildProfileButtons()
|
buildProfileButtons(
|
||||||
|
"overview",
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
+609
-213
@@ -654,9 +654,7 @@ async function sendAchievementNotification(
|
|||||||
achievement.description
|
achievement.description
|
||||||
].join("\n")
|
].join("\n")
|
||||||
)
|
)
|
||||||
],
|
]
|
||||||
flags:
|
|
||||||
MessageFlags.Ephemeral
|
|
||||||
});
|
});
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
@@ -1020,7 +1018,8 @@ async function tryClaimBadge(
|
|||||||
|
|
||||||
async function buildProfileOverview(
|
async function buildProfileOverview(
|
||||||
guildId,
|
guildId,
|
||||||
user
|
user,
|
||||||
|
sessionOwnerId = user.id
|
||||||
) {
|
) {
|
||||||
const stats =
|
const stats =
|
||||||
await getProfileStats(
|
await getProfileStats(
|
||||||
@@ -1115,13 +1114,102 @@ async function buildProfileOverview(
|
|||||||
)
|
)
|
||||||
.setFooter({
|
.setFooter({
|
||||||
text:
|
text:
|
||||||
`profile:${user.id}`
|
buildProfileFooter(
|
||||||
|
sessionOwnerId,
|
||||||
|
user.id,
|
||||||
|
"overview",
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildStatsEmbed(
|
||||||
|
guildId,
|
||||||
|
user,
|
||||||
|
sessionOwnerId = user.id
|
||||||
|
) {
|
||||||
|
const stats =
|
||||||
|
await getProfileStats(
|
||||||
|
user.id,
|
||||||
|
guildId
|
||||||
|
);
|
||||||
|
|
||||||
|
const gameLines = [
|
||||||
|
["🎰 Slots", stats.games.slots],
|
||||||
|
["🃏 Blackjack", stats.games.blackjack],
|
||||||
|
["🎡 Roulette", stats.games.roulette],
|
||||||
|
["🏦 Heist", stats.games.heist]
|
||||||
|
].map(
|
||||||
|
([name, game]) => [
|
||||||
|
`**${name}**`,
|
||||||
|
`Played ${game?.played ?? 0} • Won ${game?.won ?? 0} • Lost ${game?.lost ?? 0} • Push ${game?.pushed ?? 0}`,
|
||||||
|
`Net tracked: **+${(game?.cookiesWon ?? 0).toLocaleString()} / -${(game?.cookiesLost ?? 0).toLocaleString()} 🍪**`
|
||||||
|
].join("\n")
|
||||||
|
);
|
||||||
|
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
`📊 ${user.globalName ?? user.username}'s Stats`
|
||||||
|
)
|
||||||
|
.setThumbnail(
|
||||||
|
user.displayAvatarURL({
|
||||||
|
size: 256
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.addFields(
|
||||||
|
{
|
||||||
|
name: "🍪 Economy",
|
||||||
|
value: [
|
||||||
|
`Obtained: **${(stats.economy?.cookiesObtainedTotal ?? 0).toLocaleString()} 🍪**`,
|
||||||
|
`Lost: **${(stats.economy?.cookiesLostTotal ?? 0).toLocaleString()} 🍪**`,
|
||||||
|
`Given: **${(stats.economy?.cookiesGivenTotal ?? 0).toLocaleString()} 🍪**`,
|
||||||
|
`Stolen: **${(stats.economy?.stolenTotal ?? 0).toLocaleString()} 🍪**`,
|
||||||
|
`Stolen from you: **${(stats.economy?.stolenFromMeTotal ?? 0).toLocaleString()} 🍪**`,
|
||||||
|
`Vault stolen: **${(stats.economy?.vaultStolenTotal ?? 0).toLocaleString()} 🍪**`
|
||||||
|
].join("\n")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "🥷 Unique Players",
|
||||||
|
value: [
|
||||||
|
`Stolen from: **${stats.unique?.playersStolenFrom?.length ?? 0}**`,
|
||||||
|
`Stolen by: **${stats.unique?.playersStolenBy?.length ?? 0}**`
|
||||||
|
].join("\n"),
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "🔥 Streaks",
|
||||||
|
value: [
|
||||||
|
`Current wins: **${stats.streaks?.currentWin ?? 0}**`,
|
||||||
|
`Best wins: **${stats.streaks?.bestWin ?? 0}**`,
|
||||||
|
`Current losses: **${stats.streaks?.currentLoss ?? 0}**`,
|
||||||
|
`Best losses: **${stats.streaks?.bestLoss ?? 0}**`
|
||||||
|
].join("\n"),
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "🎮 Per Game",
|
||||||
|
value:
|
||||||
|
gameLines.join("\n\n")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
buildProfileFooter(
|
||||||
|
sessionOwnerId,
|
||||||
|
user.id,
|
||||||
|
"stats",
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildBadgesEmbed(
|
async function buildBadgesEmbed(
|
||||||
guildId,
|
guildId,
|
||||||
user
|
user,
|
||||||
|
sessionOwnerId = user.id,
|
||||||
|
page = 0
|
||||||
) {
|
) {
|
||||||
const { badges } =
|
const { badges } =
|
||||||
getProfileCollections();
|
getProfileCollections();
|
||||||
@@ -1129,6 +1217,9 @@ async function buildBadgesEmbed(
|
|||||||
const documents =
|
const documents =
|
||||||
await badges.find({
|
await badges.find({
|
||||||
guildId
|
guildId
|
||||||
|
}).sort({
|
||||||
|
category: 1,
|
||||||
|
name: 1
|
||||||
}).toArray();
|
}).toArray();
|
||||||
|
|
||||||
const owned =
|
const owned =
|
||||||
@@ -1138,117 +1229,177 @@ async function buildBadgesEmbed(
|
|||||||
user.id
|
user.id
|
||||||
);
|
);
|
||||||
|
|
||||||
const claimedByOthers =
|
const pages = [];
|
||||||
documents.filter(
|
|
||||||
badge =>
|
pages.push({
|
||||||
badge.ownerId &&
|
title: "Owned",
|
||||||
badge.ownerId !==
|
content:
|
||||||
user.id
|
owned.length
|
||||||
|
? owned.map(
|
||||||
|
badge =>
|
||||||
|
formatBadgeLine(
|
||||||
|
badge,
|
||||||
|
user.id,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
).join("\n\n")
|
||||||
|
: "*No unique badges yet.*"
|
||||||
|
});
|
||||||
|
|
||||||
|
const categoryOrder = [
|
||||||
|
"economy",
|
||||||
|
"stealing",
|
||||||
|
"slots",
|
||||||
|
"blackjack",
|
||||||
|
"roulette",
|
||||||
|
"heist",
|
||||||
|
"collector"
|
||||||
|
];
|
||||||
|
|
||||||
|
const categories =
|
||||||
|
[...new Set(
|
||||||
|
documents.map(
|
||||||
|
badge =>
|
||||||
|
badge.category ??
|
||||||
|
"other"
|
||||||
|
)
|
||||||
|
)].sort(
|
||||||
|
(a, b) => {
|
||||||
|
const ai =
|
||||||
|
categoryOrder.indexOf(a);
|
||||||
|
const bi =
|
||||||
|
categoryOrder.indexOf(b);
|
||||||
|
|
||||||
|
if (
|
||||||
|
ai === -1 &&
|
||||||
|
bi === -1
|
||||||
|
) {
|
||||||
|
return a.localeCompare(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ai === -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bi === -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ai - bi;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const unclaimed =
|
for (const category of categories) {
|
||||||
documents.filter(
|
const categoryBadges =
|
||||||
badge =>
|
documents.filter(
|
||||||
!badge.ownerId
|
badge =>
|
||||||
|
(badge.category ?? "other") ===
|
||||||
|
category
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!categoryBadges.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chunks =
|
||||||
|
paginateLines(
|
||||||
|
categoryBadges.map(
|
||||||
|
badge =>
|
||||||
|
formatBadgeLine(
|
||||||
|
badge,
|
||||||
|
user.id,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
),
|
||||||
|
3200,
|
||||||
|
"\n\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (
|
||||||
|
let index = 0;
|
||||||
|
index < chunks.length;
|
||||||
|
index++
|
||||||
|
) {
|
||||||
|
pages.push({
|
||||||
|
title:
|
||||||
|
`${formatCategoryName(category)}${chunks.length > 1 ? ` ${index + 1}/${chunks.length}` : ""}`,
|
||||||
|
content:
|
||||||
|
chunks[index]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const safePage =
|
||||||
|
clampPage(
|
||||||
|
page,
|
||||||
|
pages.length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const selected =
|
||||||
|
pages[safePage] ?? {
|
||||||
|
title: "Badges",
|
||||||
|
content:
|
||||||
|
"No badges configured."
|
||||||
|
};
|
||||||
|
|
||||||
return new EmbedBuilder()
|
return new EmbedBuilder()
|
||||||
.setTitle(
|
.setTitle(
|
||||||
`🏅 ${user.globalName ?? user.username}'s Badges`
|
`🏅 ${user.globalName ?? user.username}'s Badges`
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
[
|
[
|
||||||
"### Owned",
|
`### ${selected.title}`,
|
||||||
owned.length
|
selected.content
|
||||||
? owned.map(
|
|
||||||
badge =>
|
|
||||||
`${badge.emoji} **${badge.name}**\n${badge.description}`
|
|
||||||
).join("\n\n")
|
|
||||||
: "*No unique badges yet.*",
|
|
||||||
"",
|
|
||||||
"### Claimed by Others",
|
|
||||||
claimedByOthers.length
|
|
||||||
? claimedByOthers.map(
|
|
||||||
badge =>
|
|
||||||
`${badge.emoji} **${badge.name}** — <@${badge.ownerId}>`
|
|
||||||
).join("\n")
|
|
||||||
: "*None yet.*",
|
|
||||||
"",
|
|
||||||
"### Still Available",
|
|
||||||
unclaimed.length
|
|
||||||
? unclaimed.map(
|
|
||||||
badge =>
|
|
||||||
`${badge.emoji} **${badge.name}**\n${badge.description}`
|
|
||||||
).join("\n\n")
|
|
||||||
: "*All unique badges have been claimed.*"
|
|
||||||
].join("\n")
|
].join("\n")
|
||||||
)
|
)
|
||||||
.setFooter({
|
.setFooter({
|
||||||
text:
|
text:
|
||||||
`profile:${user.id}`
|
buildProfileFooter(
|
||||||
|
sessionOwnerId,
|
||||||
|
user.id,
|
||||||
|
"badges",
|
||||||
|
safePage,
|
||||||
|
pages.length
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildAchievementsEmbed(
|
async function buildAchievementsEmbed(
|
||||||
guildId,
|
guildId,
|
||||||
user,
|
user,
|
||||||
|
sessionOwnerId = user.id,
|
||||||
page = 0
|
page = 0
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
achievements,
|
achievements,
|
||||||
achievementConfig
|
achievementConfig
|
||||||
} =
|
} = getProfileCollections();
|
||||||
getProfileCollections();
|
|
||||||
|
|
||||||
|
|
||||||
const [
|
const [
|
||||||
unlockedDoc,
|
unlockedDoc,
|
||||||
definitions
|
definitions
|
||||||
] =
|
] = await Promise.all([
|
||||||
await Promise.all([
|
achievements.findOne({
|
||||||
achievements.findOne({
|
userId: user.id,
|
||||||
userId:
|
guildId
|
||||||
user.id,
|
}),
|
||||||
|
|
||||||
guildId
|
|
||||||
}),
|
|
||||||
|
|
||||||
achievementConfig
|
|
||||||
.find({
|
|
||||||
active: {
|
|
||||||
$ne:
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.sort({
|
|
||||||
category:
|
|
||||||
1,
|
|
||||||
|
|
||||||
target:
|
|
||||||
1
|
|
||||||
})
|
|
||||||
.toArray()
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
achievementConfig
|
||||||
|
.find({
|
||||||
|
active: {
|
||||||
|
$ne: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sort({
|
||||||
|
category: 1,
|
||||||
|
target: 1,
|
||||||
|
name: 1
|
||||||
|
})
|
||||||
|
.toArray()
|
||||||
|
]);
|
||||||
|
|
||||||
const unlocked =
|
const unlocked =
|
||||||
unlockedDoc?.unlocked ??
|
unlockedDoc?.unlocked ?? {};
|
||||||
{};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Keep pages comfortably below Discord's
|
|
||||||
* 4096-character description limit.
|
|
||||||
*
|
|
||||||
* Using a character limit instead of a fixed
|
|
||||||
* number of achievements also protects us
|
|
||||||
* against achievements with long names or
|
|
||||||
* requirements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const MAX_PAGE_LENGTH =
|
|
||||||
3500;
|
|
||||||
|
|
||||||
|
|
||||||
const lines =
|
const lines =
|
||||||
definitions.map(
|
definitions.map(
|
||||||
@@ -1256,171 +1407,83 @@ async function buildAchievementsEmbed(
|
|||||||
const complete =
|
const complete =
|
||||||
Boolean(
|
Boolean(
|
||||||
unlocked[
|
unlocked[
|
||||||
achievement
|
achievement.achievementId
|
||||||
.achievementId
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
complete
|
complete ? "✅" : "⬜",
|
||||||
? "✅"
|
|
||||||
: "⬜",
|
|
||||||
|
|
||||||
" ",
|
" ",
|
||||||
|
achievement.emoji ?? "🏆",
|
||||||
achievement.emoji ??
|
|
||||||
"🏆",
|
|
||||||
|
|
||||||
" **",
|
" **",
|
||||||
|
|
||||||
achievement.name,
|
achievement.name,
|
||||||
|
|
||||||
"** — ",
|
"** — ",
|
||||||
|
achievement.requirement ??
|
||||||
achievement.requirement
|
achievement.description ??
|
||||||
??
|
|
||||||
achievement.description
|
|
||||||
??
|
|
||||||
"Requirement unavailable."
|
"Requirement unavailable."
|
||||||
].join("");
|
].join("");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Build pages dynamically.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const pages =
|
const pages =
|
||||||
[];
|
paginateLines(
|
||||||
|
lines,
|
||||||
let currentPage =
|
3400,
|
||||||
[];
|
"\n"
|
||||||
|
|
||||||
|
|
||||||
for (
|
|
||||||
const line
|
|
||||||
of lines
|
|
||||||
) {
|
|
||||||
const test =
|
|
||||||
[
|
|
||||||
...currentPage,
|
|
||||||
line
|
|
||||||
].join(
|
|
||||||
"\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
test.length >
|
|
||||||
MAX_PAGE_LENGTH
|
|
||||||
&&
|
|
||||||
currentPage.length >
|
|
||||||
0
|
|
||||||
) {
|
|
||||||
pages.push(
|
|
||||||
currentPage.join(
|
|
||||||
"\n"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
currentPage =
|
|
||||||
[
|
|
||||||
line
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
currentPage.push(
|
|
||||||
line
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
currentPage.length >
|
|
||||||
0
|
|
||||||
) {
|
|
||||||
pages.push(
|
|
||||||
currentPage.join(
|
|
||||||
"\n"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!pages.length) {
|
||||||
/*
|
|
||||||
* No achievements configured.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (
|
|
||||||
pages.length ===
|
|
||||||
0
|
|
||||||
) {
|
|
||||||
pages.push(
|
pages.push(
|
||||||
"No achievements configured."
|
"No achievements configured."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clamp page so old buttons can't request
|
|
||||||
* a page that no longer exists after DB
|
|
||||||
* changes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const safePage =
|
const safePage =
|
||||||
Math.max(
|
clampPage(
|
||||||
0,
|
page,
|
||||||
|
pages.length
|
||||||
Math.min(
|
|
||||||
Number(page) || 0,
|
|
||||||
pages.length - 1
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const unlockedCount =
|
const unlockedCount =
|
||||||
definitions.filter(
|
definitions.filter(
|
||||||
achievement =>
|
achievement =>
|
||||||
Boolean(
|
Boolean(
|
||||||
unlocked[
|
unlocked[
|
||||||
achievement
|
achievement.achievementId
|
||||||
.achievementId
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
|
|
||||||
return new EmbedBuilder()
|
return new EmbedBuilder()
|
||||||
.setTitle(
|
.setTitle(
|
||||||
`🏆 ${user.globalName ?? user.username}'s Achievements`
|
`🏆 ${user.globalName ?? user.username}'s Achievements`
|
||||||
)
|
)
|
||||||
|
|
||||||
.setDescription(
|
.setDescription(
|
||||||
pages[
|
pages[safePage]
|
||||||
safePage
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
.addFields({
|
.addFields({
|
||||||
name:
|
name: "Progress",
|
||||||
"Progress",
|
|
||||||
|
|
||||||
value:
|
value:
|
||||||
`**${unlockedCount} / ${definitions.length}** achievements unlocked`
|
`**${unlockedCount} / ${definitions.length}** achievements unlocked`
|
||||||
})
|
})
|
||||||
|
|
||||||
.setFooter({
|
.setFooter({
|
||||||
text:
|
text:
|
||||||
`profile:${user.id}:achievements:${safePage}:${pages.length}`
|
buildProfileFooter(
|
||||||
|
sessionOwnerId,
|
||||||
|
user.id,
|
||||||
|
"achievements",
|
||||||
|
safePage,
|
||||||
|
pages.length
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildProfileButtons() {
|
function buildProfileButtons(
|
||||||
return [
|
section = "overview",
|
||||||
|
page = 0,
|
||||||
|
pageCount = 1
|
||||||
|
) {
|
||||||
|
const rows = [
|
||||||
new ActionRowBuilder()
|
new ActionRowBuilder()
|
||||||
.addComponents(
|
.addComponents(
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
@@ -1434,7 +1497,25 @@ function buildProfileButtons() {
|
|||||||
"👤"
|
"👤"
|
||||||
)
|
)
|
||||||
.setStyle(
|
.setStyle(
|
||||||
ButtonStyle.Primary
|
section === "overview"
|
||||||
|
? ButtonStyle.Primary
|
||||||
|
: ButtonStyle.Secondary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"profileStats"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Stats"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"📊"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
section === "stats"
|
||||||
|
? ButtonStyle.Primary
|
||||||
|
: ButtonStyle.Secondary
|
||||||
),
|
),
|
||||||
|
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
@@ -1448,7 +1529,9 @@ function buildProfileButtons() {
|
|||||||
"🏅"
|
"🏅"
|
||||||
)
|
)
|
||||||
.setStyle(
|
.setStyle(
|
||||||
ButtonStyle.Secondary
|
section === "badges"
|
||||||
|
? ButtonStyle.Primary
|
||||||
|
: ButtonStyle.Secondary
|
||||||
),
|
),
|
||||||
|
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
@@ -1462,12 +1545,14 @@ function buildProfileButtons() {
|
|||||||
"🏆"
|
"🏆"
|
||||||
)
|
)
|
||||||
.setStyle(
|
.setStyle(
|
||||||
ButtonStyle.Secondary
|
section === "achievements"
|
||||||
|
? ButtonStyle.Primary
|
||||||
|
: ButtonStyle.Secondary
|
||||||
),
|
),
|
||||||
|
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
.setCustomId(
|
.setCustomId(
|
||||||
"abort"
|
"profileClose"
|
||||||
)
|
)
|
||||||
.setLabel(
|
.setLabel(
|
||||||
"Close"
|
"Close"
|
||||||
@@ -1476,13 +1561,99 @@ function buildProfileButtons() {
|
|||||||
"✖️"
|
"✖️"
|
||||||
)
|
)
|
||||||
.setStyle(
|
.setStyle(
|
||||||
ButtonStyle.Secondary
|
ButtonStyle.Danger
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
"badges",
|
||||||
|
"achievements"
|
||||||
|
].includes(section) &&
|
||||||
|
pageCount > 1
|
||||||
|
) {
|
||||||
|
const prefix =
|
||||||
|
section === "badges"
|
||||||
|
? "profileBadges"
|
||||||
|
: "profileAchievements";
|
||||||
|
|
||||||
|
rows.push(
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
`${prefix}Left`
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Previous"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"◀️"
|
||||||
|
)
|
||||||
|
.setDisabled(
|
||||||
|
page <= 0
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
`${prefix}Page`
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
`${page + 1} / ${pageCount}`
|
||||||
|
)
|
||||||
|
.setDisabled(
|
||||||
|
true
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
`${prefix}Right`
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Next"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"▶️"
|
||||||
|
)
|
||||||
|
.setDisabled(
|
||||||
|
page >=
|
||||||
|
pageCount - 1
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProfileTargetId(
|
function buildProfileFooter(
|
||||||
|
sessionOwnerId,
|
||||||
|
profileUserId,
|
||||||
|
section,
|
||||||
|
page,
|
||||||
|
pageCount
|
||||||
|
) {
|
||||||
|
return [
|
||||||
|
"profile",
|
||||||
|
sessionOwnerId,
|
||||||
|
profileUserId,
|
||||||
|
section,
|
||||||
|
page,
|
||||||
|
pageCount
|
||||||
|
].join(":");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProfileContext(
|
||||||
interaction
|
interaction
|
||||||
) {
|
) {
|
||||||
const footer =
|
const footer =
|
||||||
@@ -1491,23 +1662,248 @@ function getProfileTargetId(
|
|||||||
?.footer
|
?.footer
|
||||||
?.text;
|
?.text;
|
||||||
|
|
||||||
|
return getProfileContextFromFooter(
|
||||||
|
footer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProfileContextFromFooter(
|
||||||
|
footer
|
||||||
|
) {
|
||||||
const [
|
const [
|
||||||
type,
|
type,
|
||||||
userId
|
sessionOwnerId,
|
||||||
|
profileUserId,
|
||||||
|
section = "overview",
|
||||||
|
rawPage = "0",
|
||||||
|
rawPageCount = "1"
|
||||||
] = footer?.split(":") ?? [];
|
] = footer?.split(":") ?? [];
|
||||||
|
|
||||||
return type === "profile"
|
if (
|
||||||
? userId
|
type !== "profile" ||
|
||||||
: null;
|
!sessionOwnerId ||
|
||||||
|
!profileUserId
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sessionOwnerId,
|
||||||
|
profileUserId,
|
||||||
|
section,
|
||||||
|
page:
|
||||||
|
Number(rawPage) || 0,
|
||||||
|
pageCount:
|
||||||
|
Math.max(
|
||||||
|
1,
|
||||||
|
Number(rawPageCount) || 1
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProfileTargetId(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return getProfileContext(
|
||||||
|
interaction
|
||||||
|
)?.profileUserId ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function requireProfileOwner(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const context =
|
||||||
|
getProfileContext(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
await replyProfileError(
|
||||||
|
interaction,
|
||||||
|
"This profile session is no longer valid."
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
context.sessionOwnerId !==
|
||||||
|
interaction.user.id
|
||||||
|
) {
|
||||||
|
await replyProfileError(
|
||||||
|
interaction,
|
||||||
|
"This isn't your profile session."
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function replyProfileError(
|
||||||
|
interaction,
|
||||||
|
content
|
||||||
|
) {
|
||||||
|
const payload = {
|
||||||
|
content,
|
||||||
|
flags:
|
||||||
|
MessageFlags.Ephemeral
|
||||||
|
};
|
||||||
|
|
||||||
|
if (
|
||||||
|
interaction.replied ||
|
||||||
|
interaction.deferred
|
||||||
|
) {
|
||||||
|
return interaction.followUp(
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return interaction.reply(
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function paginateLines(
|
||||||
|
lines,
|
||||||
|
maxLength = 3400,
|
||||||
|
separator = "\n"
|
||||||
|
) {
|
||||||
|
const pages = [];
|
||||||
|
let current = [];
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const candidate =
|
||||||
|
[...current, line].join(
|
||||||
|
separator
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
candidate.length >
|
||||||
|
maxLength &&
|
||||||
|
current.length
|
||||||
|
) {
|
||||||
|
pages.push(
|
||||||
|
current.join(
|
||||||
|
separator
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
current = [line];
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
current.push(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current.length) {
|
||||||
|
pages.push(
|
||||||
|
current.join(
|
||||||
|
separator
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clampPage(
|
||||||
|
page,
|
||||||
|
pageCount
|
||||||
|
) {
|
||||||
|
return Math.max(
|
||||||
|
0,
|
||||||
|
Math.min(
|
||||||
|
Number(page) || 0,
|
||||||
|
Math.max(
|
||||||
|
0,
|
||||||
|
pageCount - 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCategoryName(
|
||||||
|
category
|
||||||
|
) {
|
||||||
|
const labels = {
|
||||||
|
economy:
|
||||||
|
"🍪 Economy",
|
||||||
|
stealing:
|
||||||
|
"🥷 Stealing",
|
||||||
|
slots:
|
||||||
|
"🎰 Slots",
|
||||||
|
blackjack:
|
||||||
|
"🃏 Blackjack",
|
||||||
|
roulette:
|
||||||
|
"🎡 Roulette",
|
||||||
|
heist:
|
||||||
|
"🏦 Heist",
|
||||||
|
collector:
|
||||||
|
"🏆 Collector",
|
||||||
|
other:
|
||||||
|
"🏅 Other"
|
||||||
|
};
|
||||||
|
|
||||||
|
return labels[category] ??
|
||||||
|
`🏅 ${category.charAt(0).toUpperCase()}${category.slice(1)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatBadgeLine(
|
||||||
|
badge,
|
||||||
|
profileUserId,
|
||||||
|
ownedPage
|
||||||
|
) {
|
||||||
|
const emoji =
|
||||||
|
badge.emoji ?? "🏅";
|
||||||
|
|
||||||
|
const description =
|
||||||
|
badge.description ??
|
||||||
|
"No description available.";
|
||||||
|
|
||||||
|
if (ownedPage) {
|
||||||
|
return `${emoji} **${badge.name}**\n${description}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let status;
|
||||||
|
|
||||||
|
if (
|
||||||
|
badge.ownerId ===
|
||||||
|
profileUserId
|
||||||
|
) {
|
||||||
|
status = "✅ **Owned by this player**";
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (badge.ownerId) {
|
||||||
|
status = `🔒 Claimed by <@${badge.ownerId}>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
status = "🟢 **Available**";
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
`${emoji} **${badge.name}**`,
|
||||||
|
description,
|
||||||
|
status
|
||||||
|
].join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
ensureProfileSystem,
|
ensureProfileSystem,
|
||||||
trackProfileEvent,
|
trackProfileEvent,
|
||||||
getProfileStats,
|
getProfileStats,
|
||||||
|
|
||||||
buildProfileOverview,
|
buildProfileOverview,
|
||||||
|
buildStatsEmbed,
|
||||||
buildBadgesEmbed,
|
buildBadgesEmbed,
|
||||||
buildAchievementsEmbed,
|
buildAchievementsEmbed,
|
||||||
buildProfileButtons,
|
buildProfileButtons,
|
||||||
getProfileTargetId
|
|
||||||
|
getProfileContext,
|
||||||
|
getProfileContextFromFooter,
|
||||||
|
getProfileTargetId,
|
||||||
|
requireProfileOwner
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user