Update
This commit is contained in:
@@ -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,
|
||||
};
|
||||
Reference in New Issue
Block a user