diff --git a/app/commands/countingAdd.js b/app/commands/countingAdd.js
new file mode 100644
index 0000000..a9ce403
--- /dev/null
+++ b/app/commands/countingAdd.js
@@ -0,0 +1,122 @@
+const addCommand = require("../fonctions/addCommand");
+const { EmbedBuilder, PermissionFlagsBits } = require("discord.js");
+const db = require("../db");
+
+module.exports = addCommand({
+ name: "counting-add",
+ description: "Ajoute un nombre au compteur actuel.",
+ aliases: ["countadd", "addcount"],
+ permissions: [PermissionFlagsBits.ManageGuild],
+ botOwnerOnly: false,
+ dm: false,
+ scope: "guild",
+
+ guildCondition: async (guildId) => {
+ return new Promise((resolve) => {
+ db.get(
+ "SELECT enabled FROM counting_config WHERE guild_id = ?",
+ [guildId],
+ (err, row) => {
+ if (err) {
+ console.error(`DB error in guildCondition for guild ${guildId}`, err);
+ return resolve(false);
+ }
+ resolve(!!row?.enabled);
+ }
+ );
+ });
+ },
+
+ slashOptions: [
+ {
+ type: "INTEGER",
+ name: "nombre",
+ description: "Le nombre à ajouter au compteur",
+ required: true,
+ },
+ ],
+
+ executePrefix: async (client, message, args) => {
+ const number = parseInt(args[0], 10);
+ if (isNaN(number) || number <= 0) {
+ return message.reply({
+ embeds: [new EmbedBuilder().setColor(0xED4245).setDescription("❌ Veuillez spécifier un nombre valide (> 0).")]
+ });
+ }
+
+ await addCount(message.guild, number, message.author, message);
+ },
+
+ executeSlash: async (client, interaction) => {
+ const number = interaction.options.getInteger("nombre");
+ if (number <= 0) {
+ return interaction.reply({
+ embeds: [new EmbedBuilder().setColor(0xED4245).setDescription("❌ Le nombre doit être supérieur à 0.")],
+ ephemeral: true
+ });
+ }
+
+ await addCount(interaction.guild, number, interaction.user, interaction);
+ },
+});
+
+async function addCount(guild, amount, moderator, context) {
+ try {
+ const config = await db.getAsync(
+ "SELECT enabled, channel_id, current_count FROM counting_config WHERE guild_id = ?",
+ [guild.id]
+ );
+
+ if (!config || !config.enabled) {
+ const embed = new EmbedBuilder()
+ .setColor(0xED4245)
+ .setDescription("❌ Le système de comptage n'est pas activé sur ce serveur.");
+ return context.reply({ embeds: [embed], ephemeral: true });
+ }
+
+ const oldCount = config.current_count || 0;
+ const newCount = oldCount + amount;
+
+ // Mettre à jour le compteur
+ await new Promise((resolve, reject) => {
+ db.run(
+ "UPDATE counting_config SET current_count = ?, last_user_id = NULL WHERE guild_id = ?",
+ [newCount, guild.id],
+ (err) => {
+ if (err) reject(err);
+ else resolve();
+ }
+ );
+ });
+
+ const embed = new EmbedBuilder()
+ .setColor(0x57F287)
+ .setTitle("🔢 Compteur augmenté")
+ .setDescription(`**+${amount}** ajouté au compteur !`)
+ .addFields(
+ { name: "📊 Ancien", value: `${oldCount}`, inline: true },
+ { name: "📊 Nouveau", value: `${newCount}`, inline: true },
+ { name: "➡️ Prochain", value: `${newCount + 1}`, inline: true }
+ )
+ .setFooter({ text: `Modifié par ${moderator.username}`, iconURL: moderator.displayAvatarURL({ dynamic: true }) })
+ .setTimestamp();
+
+ await context.reply({ embeds: [embed] });
+
+ // Envoyer un message dans le salon de comptage
+ if (config.channel_id) {
+ const channel = guild.channels.cache.get(config.channel_id);
+ if (channel) {
+ const announceEmbed = new EmbedBuilder()
+ .setColor(0x57F287)
+ .setDescription(`🔢 Un administrateur a ajouté **+${amount}** au compteur !\n\n📊 Compteur actuel : **${newCount}**\n➡️ Le prochain nombre est **${newCount + 1}**`);
+
+ await channel.send({ embeds: [announceEmbed] });
+ }
+ }
+ } catch (error) {
+ console.error(error);
+ const errorEmbed = new EmbedBuilder().setColor(0xED4245).setDescription("❌ Une erreur est survenue.");
+ await context.reply({ embeds: [errorEmbed], ephemeral: true });
+ }
+}
diff --git a/app/commands/countingRemove.js b/app/commands/countingRemove.js
new file mode 100644
index 0000000..69e3a40
--- /dev/null
+++ b/app/commands/countingRemove.js
@@ -0,0 +1,122 @@
+const addCommand = require("../fonctions/addCommand");
+const { EmbedBuilder, PermissionFlagsBits } = require("discord.js");
+const db = require("../db");
+
+module.exports = addCommand({
+ name: "counting-remove",
+ description: "Retire un nombre du compteur actuel.",
+ aliases: ["countremove", "removecount"],
+ permissions: [PermissionFlagsBits.ManageGuild],
+ botOwnerOnly: false,
+ dm: false,
+ scope: "guild",
+
+ guildCondition: async (guildId) => {
+ return new Promise((resolve) => {
+ db.get(
+ "SELECT enabled FROM counting_config WHERE guild_id = ?",
+ [guildId],
+ (err, row) => {
+ if (err) {
+ console.error(`DB error in guildCondition for guild ${guildId}`, err);
+ return resolve(false);
+ }
+ resolve(!!row?.enabled);
+ }
+ );
+ });
+ },
+
+ slashOptions: [
+ {
+ type: "INTEGER",
+ name: "nombre",
+ description: "Le nombre à retirer du compteur",
+ required: true,
+ },
+ ],
+
+ executePrefix: async (client, message, args) => {
+ const number = parseInt(args[0], 10);
+ if (isNaN(number) || number <= 0) {
+ return message.reply({
+ embeds: [new EmbedBuilder().setColor(0xED4245).setDescription("❌ Veuillez spécifier un nombre valide (> 0).")]
+ });
+ }
+
+ await removeCount(message.guild, number, message.author, message);
+ },
+
+ executeSlash: async (client, interaction) => {
+ const number = interaction.options.getInteger("nombre");
+ if (number <= 0) {
+ return interaction.reply({
+ embeds: [new EmbedBuilder().setColor(0xED4245).setDescription("❌ Le nombre doit être supérieur à 0.")],
+ ephemeral: true
+ });
+ }
+
+ await removeCount(interaction.guild, number, interaction.user, interaction);
+ },
+});
+
+async function removeCount(guild, amount, moderator, context) {
+ try {
+ const config = await db.getAsync(
+ "SELECT enabled, channel_id, current_count FROM counting_config WHERE guild_id = ?",
+ [guild.id]
+ );
+
+ if (!config || !config.enabled) {
+ const embed = new EmbedBuilder()
+ .setColor(0xED4245)
+ .setDescription("❌ Le système de comptage n'est pas activé sur ce serveur.");
+ return context.reply({ embeds: [embed], ephemeral: true });
+ }
+
+ const oldCount = config.current_count || 0;
+ const newCount = Math.max(0, oldCount - amount); // Ne pas aller en dessous de 0
+
+ // Mettre à jour le compteur
+ await new Promise((resolve, reject) => {
+ db.run(
+ "UPDATE counting_config SET current_count = ?, last_user_id = NULL WHERE guild_id = ?",
+ [newCount, guild.id],
+ (err) => {
+ if (err) reject(err);
+ else resolve();
+ }
+ );
+ });
+
+ const embed = new EmbedBuilder()
+ .setColor(0xFEE75C)
+ .setTitle("🔢 Compteur diminué")
+ .setDescription(`**-${amount}** retiré du compteur !`)
+ .addFields(
+ { name: "📊 Ancien", value: `${oldCount}`, inline: true },
+ { name: "📊 Nouveau", value: `${newCount}`, inline: true },
+ { name: "➡️ Prochain", value: `${newCount + 1}`, inline: true }
+ )
+ .setFooter({ text: `Modifié par ${moderator.username}`, iconURL: moderator.displayAvatarURL({ dynamic: true }) })
+ .setTimestamp();
+
+ await context.reply({ embeds: [embed] });
+
+ // Envoyer un message dans le salon de comptage
+ if (config.channel_id) {
+ const channel = guild.channels.cache.get(config.channel_id);
+ if (channel) {
+ const announceEmbed = new EmbedBuilder()
+ .setColor(0xFEE75C)
+ .setDescription(`🔢 Un administrateur a retiré **-${amount}** du compteur !\n\n📊 Compteur actuel : **${newCount}**\n➡️ Le prochain nombre est **${newCount + 1}**`);
+
+ await channel.send({ embeds: [announceEmbed] });
+ }
+ }
+ } catch (error) {
+ console.error(error);
+ const errorEmbed = new EmbedBuilder().setColor(0xED4245).setDescription("❌ Une erreur est survenue.");
+ await context.reply({ embeds: [errorEmbed], ephemeral: true });
+ }
+}
diff --git a/app/commands/countingSet.js b/app/commands/countingSet.js
new file mode 100644
index 0000000..eb5331d
--- /dev/null
+++ b/app/commands/countingSet.js
@@ -0,0 +1,118 @@
+const addCommand = require("../fonctions/addCommand");
+const { EmbedBuilder, PermissionFlagsBits } = require("discord.js");
+const db = require("../db");
+
+module.exports = addCommand({
+ name: "counting-set",
+ description: "Définit le compteur à une valeur spécifique.",
+ aliases: ["countset", "setcount"],
+ permissions: [PermissionFlagsBits.ManageGuild],
+ botOwnerOnly: false,
+ dm: false,
+ scope: "guild",
+
+ guildCondition: async (guildId) => {
+ return new Promise((resolve) => {
+ db.get(
+ "SELECT enabled FROM counting_config WHERE guild_id = ?",
+ [guildId],
+ (err, row) => {
+ if (err) {
+ console.error(`DB error in guildCondition for guild ${guildId}`, err);
+ return resolve(false);
+ }
+ resolve(!!row?.enabled);
+ }
+ );
+ });
+ },
+
+ slashOptions: [
+ {
+ type: "INTEGER",
+ name: "nombre",
+ description: "La nouvelle valeur du compteur",
+ required: true,
+ },
+ ],
+
+ executePrefix: async (client, message, args) => {
+ const number = parseInt(args[0], 10);
+ if (isNaN(number) || number < 0) {
+ return message.reply({
+ embeds: [new EmbedBuilder().setColor(0xED4245).setDescription("❌ Veuillez spécifier un nombre valide (>= 0).")]
+ });
+ }
+
+ await setCount(message.guild, number, message.author, message);
+ },
+
+ executeSlash: async (client, interaction) => {
+ const number = interaction.options.getInteger("nombre");
+ if (number < 0) {
+ return interaction.reply({
+ embeds: [new EmbedBuilder().setColor(0xED4245).setDescription("❌ Le nombre doit être supérieur ou égal à 0.")],
+ ephemeral: true
+ });
+ }
+
+ await setCount(interaction.guild, number, interaction.user, interaction);
+ },
+});
+
+async function setCount(guild, number, moderator, context) {
+ try {
+ const config = await db.getAsync(
+ "SELECT enabled, channel_id FROM counting_config WHERE guild_id = ?",
+ [guild.id]
+ );
+
+ if (!config || !config.enabled) {
+ const embed = new EmbedBuilder()
+ .setColor(0xED4245)
+ .setDescription("❌ Le système de comptage n'est pas activé sur ce serveur.");
+ return context.reply({ embeds: [embed], ephemeral: true });
+ }
+
+ // Mettre à jour le compteur
+ await new Promise((resolve, reject) => {
+ db.run(
+ "UPDATE counting_config SET current_count = ?, last_user_id = NULL WHERE guild_id = ?",
+ [number, guild.id],
+ (err) => {
+ if (err) reject(err);
+ else resolve();
+ }
+ );
+ });
+
+ const embed = new EmbedBuilder()
+ .setColor(0x57F287)
+ .setTitle("🔢 Compteur modifié")
+ .setDescription(`Le compteur a été défini à **${number}**.`)
+ .addFields(
+ { name: "👮 Modérateur", value: moderator.tag, inline: true },
+ { name: "➡️ Prochain nombre", value: `${number + 1}`, inline: true }
+ )
+ .setFooter({ text: `Modifié par ${moderator.username}`, iconURL: moderator.displayAvatarURL({ dynamic: true }) })
+ .setTimestamp();
+
+ await context.reply({ embeds: [embed] });
+
+ // Envoyer un message dans le salon de comptage
+ if (config.channel_id) {
+ const channel = guild.channels.cache.get(config.channel_id);
+ if (channel) {
+ const announceEmbed = new EmbedBuilder()
+ .setColor(0x5865F2)
+ .setDescription(`🔢 Le compteur a été défini à **${number}** par un administrateur.\n\n➡️ Le prochain nombre est **${number + 1}**`);
+
+ await channel.send({ embeds: [announceEmbed] });
+ }
+ }
+ } catch (error) {
+ console.error(error);
+ const errorEmbed = new EmbedBuilder().setColor(0xED4245).setDescription("❌ Une erreur est survenue.");
+ await context.reply({ embeds: [errorEmbed], ephemeral: true });
+ }
+}
diff --git a/app/db.js b/app/db.js
index 111c4a7..88a8466 100644
--- a/app/db.js
+++ b/app/db.js
@@ -176,6 +176,14 @@ db.exec(`
owner_id TEXT NOT NULL,
created_at INTEGER NOT NULL
);
+
+ CREATE TABLE IF NOT EXISTS counting_config (
+ guild_id TEXT PRIMARY KEY,
+ enabled INTEGER NOT NULL DEFAULT 0,
+ channel_id TEXT,
+ current_count INTEGER NOT NULL DEFAULT 0,
+ last_user_id TEXT
+ );
`);
module.exports = db;
diff --git a/app/events/messageCreate.js b/app/events/messageCreate.js
index 3cf78dc..2f97bb4 100644
--- a/app/events/messageCreate.js
+++ b/app/events/messageCreate.js
@@ -193,5 +193,70 @@ module.exports = {
);
}
);
+
+ // ===== COUNTING SYSTEM =====
+ handleCounting(message, guildId);
},
};
+
+// ===== COUNTING HANDLER =====
+async function handleCounting(message, guildId) {
+ try {
+ const config = await db.getAsync(
+ "SELECT enabled, channel_id, current_count, last_user_id FROM counting_config WHERE guild_id = ?",
+ [guildId]
+ );
+
+ if (!config || !config.enabled || config.channel_id !== message.channel.id) return;
+
+ const content = message.content.trim();
+ const number = parseInt(content, 10);
+
+ // Supprimer les messages qui ne sont pas des nombres valides
+ if (isNaN(number) || content !== number.toString()) {
+ await message.delete().catch(() => {});
+ return;
+ }
+
+ const expectedNumber = config.current_count + 1;
+
+ // Vérifier que l'utilisateur n'est pas le même que le précédent
+ if (config.last_user_id === message.author.id) {
+ await message.delete().catch(() => {});
+ const errorMsg = await message.channel.send({
+ content: `❌ **${message.author.username}**, tu ne peux pas compter deux fois de suite ! Le prochain nombre est toujours **${expectedNumber}**.`
+ });
+ setTimeout(() => errorMsg.delete().catch(() => {}), 5000);
+ return;
+ }
+
+ // Vérifier que le nombre est correct
+ if (number !== expectedNumber) {
+ await message.delete().catch(() => {});
+ const errorMsg = await message.channel.send({
+ content: `❌ **${message.author.username}**, mauvais nombre ! Le prochain nombre est **${expectedNumber}**.`
+ });
+ setTimeout(() => errorMsg.delete().catch(() => {}), 5000);
+ return;
+ }
+
+ // Nombre correct !
+ await message.react("✅");
+
+ // Mettre à jour le compteur
+ db.run(
+ "UPDATE counting_config SET current_count = ?, last_user_id = ? WHERE guild_id = ?",
+ [number, message.author.id, guildId]
+ );
+
+ // Milestones pour les nombres ronds
+ if (number % 100 === 0) {
+ await message.reply({
+ content: `🎉 **${number}** atteint ! Bien joué à tous !`,
+ allowedMentions: { repliedUser: false }
+ });
+ }
+ } catch (err) {
+ console.error("Erreur counting:", err);
+ }
+}
diff --git a/app/public/guild.html b/app/public/guild.html
index 4876129..f2576be 100644
--- a/app/public/guild.html
+++ b/app/public/guild.html
@@ -54,6 +54,10 @@
🔊
Salons temporaires
+
+ 🔢
+ Comptage
+
@@ -655,6 +659,45 @@
+
+
+
+
+
+ 🔢
+
Système de comptage
+
+
+
+
+
+ 💡 Comment ça marche ?
+ Les membres comptent à l'infini dans le salon dédié. Un membre ne peut pas compter deux fois de suite,
+ ils doivent alterner. Si quelqu'un se trompe, le compteur repart à 0 !
+
+
+
+
+ Le salon textuel où les membres peuvent compter
+
+
+
+
+
+
+ Utilisez les commandes /counting-set, /counting-add, /counting-remove pour modifier
+