AeThex-Bot-Master/aethex-bot/commands/daily.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

199 lines
6.6 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { checkAchievements } = require('./achievements');
const { getUserStats, calculateLevel, updateQuestProgress } = require('../listeners/xpTracker');
const { getServerMode, EMBED_COLORS } = require('../utils/modeHelper');
const { claimStandaloneDaily, getStandaloneXp, calculateLevel: calcStandaloneLevel } = require('../utils/standaloneXp');
const DAILY_XP = 50;
const STREAK_BONUS = 10;
const MAX_STREAK_BONUS = 100;
module.exports = {
data: new SlashCommandBuilder()
.setName('daily')
.setDescription('Claim your daily XP bonus'),
async execute(interaction, supabase, client) {
if (!supabase) {
return interaction.reply({ content: 'Database not configured.', ephemeral: true });
}
await interaction.deferReply();
try {
const mode = await getServerMode(supabase, interaction.guildId);
if (mode === 'standalone') {
return handleStandaloneDaily(interaction, supabase);
} else {
return handleFederatedDaily(interaction, supabase, client);
}
} catch (error) {
console.error('Daily error:', error);
await interaction.editReply({ content: 'Failed to claim daily reward.' });
}
},
};
async function handleStandaloneDaily(interaction, supabase) {
const result = await claimStandaloneDaily(
supabase,
interaction.user.id,
interaction.guildId,
interaction.user.username
);
if (!result.success) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(EMBED_COLORS.warning)
.setTitle('Already Claimed!')
.setDescription(result.message)
]
});
}
const level = calcStandaloneLevel(result.totalXp, 'normal');
const embed = new EmbedBuilder()
.setColor(EMBED_COLORS.success)
.setTitle('Daily Reward Claimed!')
.setDescription(`You received **+${result.xpGained} XP**!`)
.addFields(
{ name: 'Base XP', value: `+50`, inline: true },
{ name: 'Streak Bonus', value: `+${Math.min((result.streak - 1) * 5, 100)}`, inline: true },
{ name: 'Current Streak', value: `${result.streak} days`, inline: true },
{ name: 'Total XP', value: result.totalXp.toLocaleString(), inline: true },
{ name: 'Level', value: `${level}`, inline: true }
)
.setFooter({ text: `🏠 Standalone Mode • Come back tomorrow!` })
.setTimestamp();
await interaction.editReply({ embeds: [embed] });
}
async function handleFederatedDaily(interaction, supabase, client) {
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 need to link your account first! Use `/verify` to get started.')
]
});
}
const { data: profile } = await supabase
.from('user_profiles')
.select('xp, daily_streak, last_daily, prestige_level, total_xp_earned')
.eq('id', link.user_id)
.single();
const now = new Date();
const lastDaily = profile?.last_daily ? new Date(profile.last_daily) : null;
const currentXp = profile?.xp || 0;
const prestige = profile?.prestige_level || 0;
let streak = profile?.daily_streak || 0;
if (lastDaily) {
const hoursSince = (now - lastDaily) / (1000 * 60 * 60);
if (hoursSince < 20) {
const nextClaim = new Date(lastDaily.getTime() + 20 * 60 * 60 * 1000);
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(0xfbbf24)
.setTitle('Already Claimed!')
.setDescription(`You've already claimed your daily XP.\nNext claim: <t:${Math.floor(nextClaim.getTime() / 1000)}:R>`)
.addFields({ name: 'Current Streak', value: `${streak} days` })
]
});
}
if (hoursSince > 48) {
streak = 0;
}
}
streak += 1;
const streakBonus = Math.min(streak * STREAK_BONUS, MAX_STREAK_BONUS);
const prestigeDailyBonus = prestige >= 4 ? 25 : 0;
let totalXp = DAILY_XP + streakBonus + prestigeDailyBonus;
if (prestige > 0) {
const prestigeMultiplier = 1 + (prestige * 0.05);
totalXp = Math.floor(totalXp * prestigeMultiplier);
}
const newXp = currentXp + totalXp;
const totalEarned = (profile?.total_xp_earned || currentXp) + totalXp;
await supabase
.from('user_profiles')
.update({
xp: newXp,
daily_streak: streak,
last_daily: now.toISOString(),
total_xp_earned: totalEarned
})
.eq('id', link.user_id);
const newLevel = Math.floor(Math.sqrt(newXp / 100));
const oldLevel = Math.floor(Math.sqrt(currentXp / 100));
const embed = new EmbedBuilder()
.setColor(prestige > 0 ? getPrestigeColor(prestige) : 0x00ff00)
.setTitle('Daily Reward Claimed!')
.setDescription(`You received **+${totalXp} XP**!${prestige > 0 ? ` *(includes P${prestige} bonus)*` : ''}`)
.addFields(
{ name: 'Base XP', value: `+${DAILY_XP}`, inline: true },
{ name: 'Streak Bonus', value: `+${streakBonus}`, inline: true },
{ name: 'Current Streak', value: `${streak} days`, inline: true },
{ name: 'Total XP', value: newXp.toLocaleString(), inline: true },
{ name: 'Level', value: `${newLevel}`, inline: true }
);
if (prestige > 0) {
embed.addFields({ name: 'Prestige Bonus', value: `+${prestige * 5}% XP${prestigeDailyBonus > 0 ? ` + ${prestigeDailyBonus} daily bonus` : ''}`, inline: true });
}
embed.setFooter({ text: '🌐 Federation • Come back tomorrow to keep your streak!' })
.setTimestamp();
if (newLevel > oldLevel) {
embed.addFields({ name: 'Level Up!', value: `You reached level ${newLevel}!` });
}
await interaction.editReply({ embeds: [embed] });
const guildId = interaction.guildId;
const stats = await getUserStats(supabase, link.user_id, guildId);
stats.level = newLevel;
stats.prestige = prestige;
stats.totalXp = totalEarned;
stats.dailyStreak = streak;
await checkAchievements(link.user_id, interaction.member, stats, supabase, guildId, client);
await updateQuestProgress(supabase, link.user_id, guildId, 'daily_claims', 1);
await updateQuestProgress(supabase, link.user_id, guildId, 'xp_earned', totalXp);
if (newLevel > oldLevel) {
await updateQuestProgress(supabase, link.user_id, guildId, 'level_ups', 1);
}
}
function getPrestigeColor(level) {
const colors = [0x6b7280, 0xcd7f32, 0xc0c0c0, 0xffd700, 0xe5e4e2, 0xb9f2ff, 0xff4500, 0x9400d3, 0xffd700, 0xff69b4, 0x7c3aed];
return colors[Math.min(level, 10)] || 0x00ff00;
}