This commit is contained in:
2026-03-15 12:22:42 +01:00
parent cd99275933
commit 311ba5e7f3
558 changed files with 55182 additions and 22981 deletions

View File

@@ -5,217 +5,173 @@
const db = require('../database/db.js');
// Formule de calcul de l'XP nécessaire pour atteindre un niveau
// XP total nécessaire = 5 * (level^2) + (50 * level) + 100
// Exemples :
// - Niveau 1 : 5 * 1^2 + 50 * 1 + 100 = 155 XP total
// - Niveau 2 : 5 * 2^2 + 50 * 2 + 100 = 220 XP total
// - Niveau 3 : 5 * 3^2 + 50 * 3 + 100 = 295 XP total
function getXPForLevel(level) {
if (level <= 0) return 0;
return Math.floor(5 * Math.pow(level, 2) + 50 * level + 100);
if (level <= 0) return 0;
return Math.floor(5 * Math.pow(level, 2) + 50 * level + 100);
}
// Calculer le niveau à partir de l'XP total
function getLevelFromXP(xp) {
if (xp < 0) return 0;
let level = 0;
let requiredXP = getXPForLevel(level + 1);
// Trouver le niveau en vérifiant l'XP nécessaire
while (xp >= requiredXP) {
level++;
requiredXP = getXPForLevel(level + 1);
}
return level;
if (xp < 0) return 0;
let level = 0;
let requiredXP = getXPForLevel(level + 1);
while (xp >= requiredXP) {
level++;
requiredXP = getXPForLevel(level + 1);
}
return level;
}
// Calculer l'XP nécessaire pour le prochain niveau
function getXPForNextLevel(level) {
return getXPForLevel(level + 1);
return getXPForLevel(level + 1);
}
// Calculer l'XP progress dans le niveau actuel
function getXPProgress(xp, level) {
// XP nécessaire pour atteindre le niveau actuel
const xpForCurrentLevel = getXPForLevel(level);
// XP nécessaire pour atteindre le prochain niveau
const xpForNextLevel = getXPForLevel(level + 1);
// XP dans le niveau actuel (différence entre l'XP total et l'XP du niveau actuel)
const xpInLevel = Math.max(0, xp - xpForCurrentLevel);
// XP nécessaire pour passer au niveau suivant
const xpNeeded = xpForNextLevel - xpForCurrentLevel;
// Éviter la division par zéro
if (xpNeeded <= 0) {
return {
current: xpInLevel,
needed: 100,
percentage: 0
};
}
const percentage = Math.max(0, Math.min(100, Math.floor((xpInLevel / xpNeeded) * 100)));
return {
current: xpInLevel,
needed: xpNeeded,
percentage: percentage
};
const xpForCurrentLevel = getXPForLevel(level);
const xpForNextLevel = getXPForLevel(level + 1);
const xpInLevel = Math.max(0, xp - xpForCurrentLevel);
const xpNeeded = xpForNextLevel - xpForCurrentLevel;
if (xpNeeded <= 0) {
return { current: xpInLevel, needed: 100, percentage: 0 };
}
const percentage = Math.max(0, Math.min(100, Math.floor((xpInLevel / xpNeeded) * 100)));
return { current: xpInLevel, needed: xpNeeded, percentage };
}
// Obtenir ou créer un utilisateur dans la table XP
async function getUserXP(userId, guildId) {
try {
const [rows] = await db.query(
'SELECT * FROM user_xp WHERE userId = ? AND guildId = ?',
[userId, guildId]
);
if (rows.length === 0) {
// Créer l'utilisateur avec 0 XP
await db.query(
'INSERT INTO user_xp (userId, guildId, xp, level) VALUES (?, ?, 0, 0)',
[userId, guildId]
);
return {
userId,
guildId,
xp: 0,
level: 0,
lastMessageTime: 0,
totalMessages: 0,
totalVoiceTime: 0,
lastVoiceJoin: 0,
lastBumpTime: 0
};
}
return rows[0];
} catch (err) {
console.error('Erreur lors de la récupération de l\'XP:', err);
return null;
}
try {
const [rows] = await db.query(
'SELECT * FROM user_xp WHERE userId = ? AND guildId = ?',
[userId, guildId]
);
if (rows.length === 0) {
await db.query(
'INSERT INTO user_xp (userId, guildId, xp, level) VALUES (?, ?, 0, 0)',
[userId, guildId]
);
return {
userId, guildId, xp: 0, level: 0,
lastMessageTime: 0, totalMessages: 0,
totalVoiceTime: 0, lastVoiceJoin: 0, lastBumpTime: 0
};
}
return rows[0];
} catch (err) {
console.error('Erreur getUserXP:', err);
return null;
}
}
// Ajouter de l'XP à un utilisateur
async function addXP(userId, guildId, xpGained, source = 'message', multiplier = 1.0) {
try {
const userXP = await getUserXP(userId, guildId);
if (!userXP) return null;
const finalXP = Math.floor(xpGained * multiplier);
const newXP = userXP.xp + finalXP;
const newLevel = getLevelFromXP(newXP);
// Mettre à jour l'XP et le niveau
await db.query(
'UPDATE user_xp SET xp = ?, level = ? WHERE userId = ? AND guildId = ?',
[newXP, newLevel, userId, guildId]
);
// Logger le gain d'XP (optionnel, pour debugging)
try {
await db.query(
'INSERT INTO xp_logs (userId, guildId, xpGained, source, multiplier, timestamp) VALUES (?, ?, ?, ?, ?, ?)',
[userId, guildId, finalXP, source, multiplier, Date.now()]
);
} catch (logErr) {
// Ignorer les erreurs de log
}
return {
oldXP: userXP.xp,
newXP,
oldLevel: userXP.level,
newLevel,
xpGained: finalXP,
levelUp: newLevel > userXP.level
};
} catch (err) {
console.error('Erreur lors de l\'ajout d\'XP:', err);
return null;
}
try {
const userXP = await getUserXP(userId, guildId);
if (!userXP) return null;
const finalXP = Math.floor(xpGained * multiplier);
const newXP = userXP.xp + finalXP;
const newLevel = getLevelFromXP(newXP);
await db.query(
'UPDATE user_xp SET xp = ?, level = ? WHERE userId = ? AND guildId = ?',
[newXP, newLevel, userId, guildId]
);
try {
await db.query(
'INSERT INTO xp_logs (userId, guildId, xpGained, source, multiplier, timestamp) VALUES (?, ?, ?, ?, ?, ?)',
[userId, guildId, finalXP, source, multiplier, Date.now()]
);
} catch {}
return {
oldXP: userXP.xp,
newXP,
oldLevel: userXP.level,
newLevel,
xpGained: finalXP,
levelUp: newLevel > userXP.level
};
} catch (err) {
console.error('Erreur addXP:', err);
return null;
}
}
// Vérifier si un salon est exclus de l'XP
async function isChannelExcluded(channelId, guildId) {
try {
const [rows] = await db.query(
'SELECT * FROM xp_excluded_channels WHERE channelId = ? AND guildId = ?',
[channelId, guildId]
);
return rows.length > 0;
} catch (err) {
console.error('Erreur lors de la vérification de l\'exclusion:', err);
return false;
}
try {
const [rows] = await db.query(
'SELECT * FROM xp_excluded_channels WHERE channelId = ? AND guildId = ?',
[channelId, guildId]
);
return rows.length > 0;
} catch (err) {
console.error('Erreur isChannelExcluded:', err);
return false;
}
}
// Obtenir le multiplicateur XP d'un utilisateur (booster, vocal, etc.)
// Obtenir le multiplicateur XP d'un utilisateur
function getXPMultiplier(member, source = 'message') {
let multiplier = 1.0;
// Vérifier si l'utilisateur est booster (1.2x)
if (member.premiumSince) {
multiplier *= 1.2;
}
// Multiplicateur vocal : 1.0x après 5 minutes de vocal (selon Issue #11)
// Note: Cette fonction est appelée toutes les 10 minutes, donc on applique déjà le bonus
if (source === 'voice') {
// Le bonus vocal est déjà appliqué car on gagne de l'XP toutes les 10 minutes
// Donc on considère qu'on a déjà passé plus de 5 minutes
multiplier *= 1.0; // Pas de changement, mais on pourrait ajouter un bonus ici
}
return multiplier;
let multiplier = 1.0;
if (member.premiumSince) multiplier *= 1.2;
return multiplier;
}
// Obtenir le classement des utilisateurs par XP
async function getLeaderboard(guildId, limit = 10) {
try {
const [rows] = await db.query(
'SELECT * FROM user_xp WHERE guildId = ? ORDER BY xp DESC LIMIT ?',
[guildId, limit]
);
return rows;
} catch (err) {
console.error('Erreur lors de la récupération du classement:', err);
return [];
}
try {
const [rows] = await db.query(
'SELECT * FROM user_xp WHERE guildId = ? ORDER BY xp DESC LIMIT ?',
[guildId, limit]
);
return rows;
} catch (err) {
console.error('Erreur getLeaderboard:', err);
return [];
}
}
// Obtenir la position d'un utilisateur dans le classement
async function getUserRank(userId, guildId) {
try {
const userXP = await getUserXP(userId, guildId);
if (!userXP) return 0;
const [rows] = await db.query(
'SELECT COUNT(*) as count FROM user_xp WHERE guildId = ? AND xp > ?',
[guildId, userXP.xp]
);
return (rows[0]?.count || 0) + 1;
} catch (err) {
console.error('Erreur lors de la récupération du rang:', err);
return 0;
}
try {
const userXP = await getUserXP(userId, guildId);
if (!userXP) return 0;
const [rows] = await db.query(
'SELECT COUNT(*) as count FROM user_xp WHERE guildId = ? AND xp > ?',
[guildId, userXP.xp]
);
return (rows[0]?.count || 0) + 1;
} catch (err) {
console.error('Erreur getUserRank:', err);
return 0;
}
}
module.exports = {
getXPForLevel,
getLevelFromXP,
getXPForNextLevel,
getXPProgress,
getUserXP,
addXP,
isChannelExcluded,
getXPMultiplier,
getLeaderboard,
getUserRank,
};
getXPForLevel,
getLevelFromXP,
getXPForNextLevel,
getXPProgress,
getUserXP,
addXP,
isChannelExcluded,
getXPMultiplier,
getLeaderboard,
getUserRank,
};