AeThex-Bot-Master/aethex-bot/commands/prestige.js
sirpiglr c2a34f398e Add server mode configuration and dynamic status updates
Introduces a new server mode configuration system (Federation/Standalone) with associated command changes, dynamic status rotation for the bot, and adds new commands and features.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: b08e6ba5-7498-4b9f-b1c9-7dc11b362ddd
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/R9PkDi8
Replit-Helium-Checkpoint-Created: true
2025-12-09 23:26:33 +00:00

486 lines
18 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
const { getServerMode, EMBED_COLORS } = require('../utils/modeHelper');
const { getStandaloneXp, prestigeStandalone, calculateLevel } = require('../utils/standaloneXp');
module.exports = {
data: new SlashCommandBuilder()
.setName('prestige')
.setDescription('Prestige system - reset your level for permanent rewards')
.addSubcommand(sub =>
sub.setName('view')
.setDescription('View your prestige status and rewards')
.addUserOption(opt =>
opt.setName('user')
.setDescription('User to check')
.setRequired(false)
)
)
.addSubcommand(sub =>
sub.setName('up')
.setDescription('Prestige up! Reset your XP for permanent rewards')
)
.addSubcommand(sub =>
sub.setName('rewards')
.setDescription('View all prestige rewards')
),
async execute(interaction, supabase, client) {
if (!supabase) {
return interaction.reply({ content: 'Database not configured.', ephemeral: true });
}
const sub = interaction.options.getSubcommand();
const mode = await getServerMode(supabase, interaction.guildId);
if (sub === 'view') {
return viewPrestige(interaction, supabase, mode);
} else if (sub === 'up') {
return prestigeUp(interaction, supabase, client, mode);
} else if (sub === 'rewards') {
return viewRewards(interaction, mode);
}
},
};
async function viewPrestige(interaction, supabase, mode) {
const target = interaction.options.getUser('user') || interaction.user;
await interaction.deferReply();
try {
if (mode === 'standalone') {
const data = await getStandaloneXp(supabase, target.id, interaction.guildId);
if (!data) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(EMBED_COLORS.standalone)
.setDescription(`${target.id === interaction.user.id ? 'You have' : `${target.tag} has`} no XP data yet.`)
]
});
}
const prestige = data.prestige_level || 0;
const currentXp = data.xp || 0;
const totalXpEarned = data.total_xp_earned || currentXp;
const level = calculateLevel(currentXp, 'normal');
const prestigeInfo = getPrestigeInfo(prestige);
const canPrestige = level >= 50;
const embed = new EmbedBuilder()
.setColor(prestigeInfo.color)
.setTitle(`${prestigeInfo.icon} ${target.tag}'s Prestige`)
.setThumbnail(target.displayAvatarURL({ size: 256 }))
.addFields(
{ name: 'Prestige Level', value: `**${prestigeInfo.name}** (${prestige})`, inline: true },
{ name: 'XP Bonus', value: `+${prestige * 5}%`, inline: true },
{ name: 'Current Level', value: `${level}`, inline: true },
{ name: 'Total XP Earned', value: totalXpEarned.toLocaleString(), inline: true },
{ name: 'Current XP', value: currentXp.toLocaleString(), inline: true },
{ name: 'Can Prestige?', value: canPrestige ? 'Yes (Level 50+)' : `Need Level 50 (${level}/50)`, inline: true }
)
.setFooter({ text: `🏠 Standalone Mode • ${interaction.guild.name}` })
.setTimestamp();
if (prestige > 0) {
embed.addFields({
name: 'Prestige Rewards Unlocked',
value: getUnlockedRewards(prestige).join('\n') || 'None yet',
inline: false
});
}
return interaction.editReply({ embeds: [embed] });
}
const { data: link } = await supabase
.from('discord_links')
.select('user_id')
.eq('discord_id', target.id)
.single();
if (!link) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(0xff6b6b)
.setDescription(`${target.id === interaction.user.id ? 'You are' : `${target.tag} is`} not linked to AeThex.`)
]
});
}
const { data: profile } = await supabase
.from('user_profiles')
.select('username, xp, prestige_level, total_xp_earned')
.eq('id', link.user_id)
.single();
const prestige = profile?.prestige_level || 0;
const totalXpEarned = profile?.total_xp_earned || profile?.xp || 0;
const currentXp = profile?.xp || 0;
const level = Math.floor(Math.sqrt(currentXp / 100));
const prestigeInfo = getPrestigeInfo(prestige);
const canPrestige = level >= 50;
const embed = new EmbedBuilder()
.setColor(prestigeInfo.color)
.setTitle(`${prestigeInfo.icon} ${profile?.username || target.tag}'s Prestige`)
.setThumbnail(target.displayAvatarURL({ size: 256 }))
.addFields(
{ name: 'Prestige Level', value: `**${prestigeInfo.name}** (${prestige})`, inline: true },
{ name: 'XP Bonus', value: `+${prestige * 5}%`, inline: true },
{ name: 'Current Level', value: `${level}`, inline: true },
{ name: 'Total XP Earned', value: totalXpEarned.toLocaleString(), inline: true },
{ name: 'Current XP', value: currentXp.toLocaleString(), inline: true },
{ name: 'Can Prestige?', value: canPrestige ? 'Yes (Level 50+)' : `Need Level 50 (${level}/50)`, inline: true }
)
.setFooter({ text: `🌐 Federation • Next prestige requirement: Level 50` })
.setTimestamp();
if (prestige > 0) {
embed.addFields({
name: 'Prestige Rewards Unlocked',
value: getUnlockedRewards(prestige).join('\n') || 'None yet',
inline: false
});
}
await interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error('Prestige view error:', error);
await interaction.editReply({ content: 'Failed to fetch prestige data.' });
}
}
async function prestigeUp(interaction, supabase, client, mode) {
await interaction.deferReply();
try {
if (mode === 'standalone') {
const data = await getStandaloneXp(supabase, interaction.user.id, interaction.guildId);
if (!data) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(EMBED_COLORS.error)
.setDescription('You have no XP data yet. Start chatting to earn XP!')
]
});
}
const currentXp = data.xp || 0;
const level = calculateLevel(currentXp, 'normal');
const prestige = data.prestige_level || 0;
if (level < 50) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(EMBED_COLORS.error)
.setTitle('Cannot Prestige')
.setDescription(`You need to reach **Level 50** to prestige.\nCurrent level: **${level}**/50`)
]
});
}
if (prestige >= 10) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(0xffd700)
.setTitle('Maximum Prestige!')
.setDescription('You have reached the maximum prestige level!')
]
});
}
const newPrestige = prestige + 1;
const newPrestigeInfo = getPrestigeInfo(newPrestige);
const confirmEmbed = new EmbedBuilder()
.setColor(EMBED_COLORS.warning)
.setTitle('Confirm Prestige')
.setDescription(`Are you sure you want to prestige?\n\n**What will happen:**\n• Your XP will reset to **0**\n• Your level will reset to **0**\n• You gain **Prestige ${newPrestige}** (${newPrestigeInfo.name})\n• You get a permanent **+${newPrestige * 5}%** XP bonus\n\n**Current Stats:**\n• Level: ${level}\n• XP: ${currentXp.toLocaleString()}`)
.setFooter({ text: 'This action cannot be undone!' });
const row = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('prestige_confirm_standalone')
.setLabel('Prestige Up!')
.setStyle(ButtonStyle.Success),
new ButtonBuilder()
.setCustomId('prestige_cancel_standalone')
.setLabel('Cancel')
.setStyle(ButtonStyle.Secondary)
);
const response = await interaction.editReply({ embeds: [confirmEmbed], components: [row] });
try {
const confirmation = await response.awaitMessageComponent({
filter: i => i.user.id === interaction.user.id,
time: 60000
});
if (confirmation.customId === 'prestige_confirm_standalone') {
const result = await prestigeStandalone(supabase, interaction.user.id, interaction.guildId);
if (!result.success) {
return confirmation.update({
embeds: [
new EmbedBuilder()
.setColor(EMBED_COLORS.error)
.setDescription(result.message)
],
components: []
});
}
const successEmbed = new EmbedBuilder()
.setColor(newPrestigeInfo.color)
.setTitle(`${newPrestigeInfo.icon} Prestige ${result.newPrestige} Achieved!`)
.setDescription(`Congratulations! You are now **${newPrestigeInfo.name}**!`)
.addFields(
{ name: 'XP Bonus', value: `+${result.bonus}%`, inline: true }
)
.setThumbnail(interaction.user.displayAvatarURL({ size: 256 }))
.setFooter({ text: '🏠 Standalone Mode' })
.setTimestamp();
await confirmation.update({ embeds: [successEmbed], components: [] });
} else {
await confirmation.update({
embeds: [
new EmbedBuilder()
.setColor(EMBED_COLORS.standalone)
.setDescription('Prestige cancelled.')
],
components: []
});
}
} catch (e) {
await interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(EMBED_COLORS.standalone)
.setDescription('Prestige request timed out.')
],
components: []
});
}
return;
}
const { data: link } = await supabase
.from('discord_links')
.select('user_id')
.eq('discord_id', interaction.user.id)
.single();
if (!link) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(0xff6b6b)
.setDescription('You must link your Discord to AeThex first. Use `/verify` to link.')
]
});
}
const { data: profile } = await supabase
.from('user_profiles')
.select('username, xp, prestige_level, total_xp_earned')
.eq('id', link.user_id)
.single();
const currentXp = profile?.xp || 0;
const level = Math.floor(Math.sqrt(currentXp / 100));
const prestige = profile?.prestige_level || 0;
const totalEarned = profile?.total_xp_earned || currentXp;
if (level < 50) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(0xff6b6b)
.setTitle('Cannot Prestige')
.setDescription(`You need to reach **Level 50** to prestige.\nCurrent level: **${level}**/50`)
]
});
}
if (prestige >= 10) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(0xffd700)
.setTitle('Maximum Prestige!')
.setDescription('You have reached the maximum prestige level! You are a true legend.')
]
});
}
const newPrestige = prestige + 1;
const newPrestigeInfo = getPrestigeInfo(newPrestige);
const xpBonus = newPrestige * 5;
const confirmEmbed = new EmbedBuilder()
.setColor(0xf59e0b)
.setTitle('Confirm Prestige')
.setDescription(`Are you sure you want to prestige?\n\n**What will happen:**\n• Your XP will reset to **0**\n• Your level will reset to **0**\n• You gain **Prestige ${newPrestige}** (${newPrestigeInfo.name})\n• You get a permanent **+${xpBonus}%** XP bonus\n• You unlock new **prestige rewards**\n\n**Current Stats:**\n• Level: ${level}\n• XP: ${currentXp.toLocaleString()}`)
.setFooter({ text: 'This action cannot be undone!' });
const row = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('prestige_confirm')
.setLabel('Prestige Up!')
.setStyle(ButtonStyle.Success),
new ButtonBuilder()
.setCustomId('prestige_cancel')
.setLabel('Cancel')
.setStyle(ButtonStyle.Secondary)
);
const response = await interaction.editReply({ embeds: [confirmEmbed], components: [row] });
try {
const confirmation = await response.awaitMessageComponent({
filter: i => i.user.id === interaction.user.id,
time: 60000
});
if (confirmation.customId === 'prestige_confirm') {
const { error } = await supabase
.from('user_profiles')
.update({
xp: 0,
prestige_level: newPrestige
})
.eq('id', link.user_id);
if (error) {
console.error('Prestige update error:', error);
return confirmation.update({
embeds: [
new EmbedBuilder()
.setColor(0xff0000)
.setDescription('Failed to prestige. Please try again.')
],
components: []
});
}
const successEmbed = new EmbedBuilder()
.setColor(newPrestigeInfo.color)
.setTitle(`${newPrestigeInfo.icon} Prestige ${newPrestige} Achieved!`)
.setDescription(`Congratulations! You are now **${newPrestigeInfo.name}**!\n\n**Rewards Unlocked:**\n${getNewRewards(newPrestige).join('\n')}`)
.addFields(
{ name: 'XP Bonus', value: `+${xpBonus}%`, inline: true },
{ name: 'Total XP Earned (All Time)', value: totalEarned.toLocaleString(), inline: true }
)
.setThumbnail(interaction.user.displayAvatarURL({ size: 256 }))
.setFooter({ text: '🌐 Federation' })
.setTimestamp();
await confirmation.update({ embeds: [successEmbed], components: [] });
} else {
await confirmation.update({
embeds: [
new EmbedBuilder()
.setColor(0x6b7280)
.setDescription('Prestige cancelled.')
],
components: []
});
}
} catch (e) {
await interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(0x6b7280)
.setDescription('Prestige request timed out.')
],
components: []
});
}
} catch (error) {
console.error('Prestige up error:', error);
await interaction.editReply({ content: 'Failed to process prestige.' });
}
}
async function viewRewards(interaction, mode) {
const embed = new EmbedBuilder()
.setColor(mode === 'standalone' ? EMBED_COLORS.standalone : 0x7c3aed)
.setTitle('Prestige Rewards')
.setDescription('Each prestige level grants permanent rewards!\n\n**Requirements:** Level 50 to prestige')
.addFields(
{ name: 'Prestige 1 - Bronze', value: '+5% XP bonus\nBronze Prestige badge', inline: true },
{ name: 'Prestige 2 - Silver', value: '+10% XP bonus\nSilver Prestige badge', inline: true },
{ name: 'Prestige 3 - Gold', value: '+15% XP bonus\nGold Prestige badge', inline: true },
{ name: 'Prestige 4 - Platinum', value: '+20% XP bonus\nPlatinum badge\nBonus daily XP', inline: true },
{ name: 'Prestige 5 - Diamond', value: '+25% XP bonus\nDiamond badge\nReduced cooldowns', inline: true },
{ name: 'Prestige 6 - Master', value: '+30% XP bonus\nMaster badge\nXP milestone rewards', inline: true },
{ name: 'Prestige 7 - Grandmaster', value: '+35% XP bonus\nGrandmaster badge\nSpecial profile effects', inline: true },
{ name: 'Prestige 8 - Champion', value: '+40% XP bonus\nChampion badge\nLeaderboard priority', inline: true },
{ name: 'Prestige 9 - Legend', value: '+45% XP bonus\nLegend badge\nLegendary profile aura', inline: true },
{ name: 'Prestige 10 - Mythic', value: '+50% XP bonus\nMythic badge\nAll prestige perks!', inline: true }
)
.setFooter({ text: `${mode === 'standalone' ? '🏠 Standalone' : '🌐 Federation'} • Use /prestige up when you reach Level 50!` })
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
function getPrestigeInfo(level) {
const prestiges = [
{ name: 'Unprestiged', icon: '', color: 0x6b7280 },
{ name: 'Bronze', icon: '', color: 0xcd7f32 },
{ name: 'Silver', icon: '', color: 0xc0c0c0 },
{ name: 'Gold', icon: '', color: 0xffd700 },
{ name: 'Platinum', icon: '', color: 0xe5e4e2 },
{ name: 'Diamond', icon: '', color: 0xb9f2ff },
{ name: 'Master', icon: '', color: 0xff4500 },
{ name: 'Grandmaster', icon: '', color: 0x9400d3 },
{ name: 'Champion', icon: '', color: 0xffd700 },
{ name: 'Legend', icon: '', color: 0xff69b4 },
{ name: 'Mythic', icon: '', color: 0x7c3aed }
];
return prestiges[Math.min(level, 10)] || prestiges[0];
}
function getUnlockedRewards(prestige) {
const rewards = [];
if (prestige >= 1) rewards.push('Bronze Prestige badge');
if (prestige >= 2) rewards.push('Silver Prestige badge');
if (prestige >= 3) rewards.push('Gold Prestige badge');
if (prestige >= 4) rewards.push('Platinum badge + Bonus daily XP');
if (prestige >= 5) rewards.push('Diamond badge + Reduced cooldowns');
if (prestige >= 6) rewards.push('Master badge + XP milestones');
if (prestige >= 7) rewards.push('Grandmaster badge + Profile effects');
if (prestige >= 8) rewards.push('Champion badge + Leaderboard priority');
if (prestige >= 9) rewards.push('Legend badge + Legendary aura');
if (prestige >= 10) rewards.push('Mythic badge + All perks unlocked');
return rewards;
}
function getNewRewards(prestige) {
const rewardMap = {
1: ['Bronze Prestige badge', '+5% XP bonus on all XP gains'],
2: ['Silver Prestige badge', '+10% XP bonus on all XP gains'],
3: ['Gold Prestige badge', '+15% XP bonus on all XP gains'],
4: ['Platinum badge', '+20% XP bonus', '+25 bonus daily XP'],
5: ['Diamond badge', '+25% XP bonus', '10% reduced XP cooldowns'],
6: ['Master badge', '+30% XP bonus', 'XP milestone rewards'],
7: ['Grandmaster badge', '+35% XP bonus', 'Special profile effects'],
8: ['Champion badge', '+40% XP bonus', 'Leaderboard priority display'],
9: ['Legend badge', '+45% XP bonus', 'Legendary profile aura'],
10: ['Mythic badge', '+50% XP bonus', 'All prestige perks unlocked!']
};
return rewardMap[prestige] || [];
}