@thenekros/discord-xp-economy
v1.0.9
Published
Paquete para gestión de XP y Economía para apps de Discord
Readme
@thenekros/discord-xp-economy · v1.0.9
Sistema de niveles (XP) + economía para bots de Discord, con MongoDB/Mongoose.
Inspirado en paquetes como discord-xp, pero con tienda, inventario y trabajo incluidos.
✨ XP usa firma
(userId, guildId, ...)
💰 Economía (desde v1.0.6) también usa(userId, guildId, ...)en sus métodos principales (add,remove,set,fetchBalance,deposit,withdraw,transfer).
🚀 Instalación
npm i @thenekros/discord-xp-economyRequiere Node 16+ (recomendado) y MongoDB.
⚙️ Conexión a Mongo
Usa una URL o una instancia existente de Mongoose.
const Levels = require('@thenekros/discord-xp-economy');
// Opción A: URL directa
await Levels.setURL(process.env.MONGO_URI /*, { dbName: 'miDB' }*/);
// Opción B: si ya conectaste Mongoose
// Levels.setMongoInstance(mongoose.connection);Helpers disponibles:
Levels.xpFor(level); // XP total requerido para alcanzar 'level'
Levels.levelFor(totalXp); // Nivel alcanzado para un XP total🧪 Uso rápido
const Levels = require('@thenekros/discord-xp-economy');
// ids
const userId = message.author.id;
const guildId = message.guild.id;
// 1) Otorga XP
const leveledUp = await Levels.appendXp(userId, guildId, 15);
if (leveledUp) {
const data = await Levels.fetch(userId, guildId); // { xp, level, ... }
const newLevel = data.level;
// 2) Recompensa económica simple por nivel
const coins = 10 * newLevel; // ejemplo de fórmula base
await Levels.add(userId, guildId, coins, 'levelUp'); // ← (userId, guildId)
message.channel.send(
`🎉 ¡${message.author} subió a **nivel ${newLevel}** y ganó **${coins}** monedas!`
);
}📚 API de XP (firma (userId, guildId, ...))
await Levels.appendXp(userId, guildId, amount); // true solo si subió de nivel
await Levels.subtractXp(userId, guildId, amount);
await Levels.setXp(userId, guildId, amount);
await Levels.appendLevel(userId, guildId, amount);
await Levels.subtractLevel(userId, guildId, amount);
await Levels.setLevel(userId, guildId, level);
const data = await Levels.fetch(userId, guildId); // { userId, guildId, xp, level, ... }
const lb = await Levels.fetchLeaderboard(guildId, 10);
const rows = await Levels.computeLeaderboard(client, lb, true);
// rows => [{ position, userID, guildID, xp, level, username?, discriminator?, globalName? }, ...]
await Levels.deleteUser(userId, guildId);
await Levels.deleteGuild(guildId);Notas
appendXphace upsert e incrementa XP. Devuelvetruesolo cuando el nuevo XP cruza el umbral para subir de nivel.- Fórmula por defecto (estilo
discord-xp):xpFor(L) = floor(L^2 * 100).
💰 API de Economía (desde v1.0.6 firma (userId, guildId, ...))
Antes de v1.0.6, algunos proyectos podían usar
(guildId, userId, ...).
A partir de 1.0.6 la firma se unifica: primerouserId, luegoguildId.
Dinero básico
await Levels.add(userId, guildId, amount, reason /*='ADD'*/); // +balance
await Levels.remove(userId, guildId, amount, reason /*='REMOVE'*/); // -balance
await Levels.set(userId, guildId, amount); // balance = amount (>=0)
const { balance, bank } = await Levels.fetchBalance(userId, guildId);Banco
await Levels.deposit(userId, guildId, amount); // balance -> bank (requiere fondos)
await Levels.withdraw(userId, guildId, amount); // bank -> balance (requiere fondos)
await Levels.transfer(userIdFrom, guildId, userIdTo, amount); // balance de from -> toTienda & Inventario
// Tienda por servidor
await Levels.Shop.addItem(guildId, 'sword', 'Espada', 250, { atk: 5 });
const items = await Levels.Shop.listItems(guildId); // [{ itemId, name, price, data }, ...]
// Comprar y listar inventario
await Levels.Shop.buy(guildId, userId, 'sword', 1);
const inv = await Levels.Shop.listInventory(guildId, userId);
// inv => [{ itemId, name, qty }, ...]Trabajo (cooldown)
// Firma actual: Work.work(guildId, userId, opts?)
// (cooldown aprox. 1 hora por usuario/servidor)
const res = await Levels.Work.work(guildId, userId, { min: 20, max: 50, reason: 'work' });
if (res.ok) {
console.log(`Ganaste ${res.amount} monedas`);
} else {
console.log(`Vuelve en ${res.retryAfter} segundos`);
}Detalles
Work.workaplica cooldown porguildId/userId.- Rango por defecto:
min=20,max=50(puedes pasarlos enopts). - Todas las operaciones económicas registran transacciones en
economy_txs.
🗃️ Esquemas y Colecciones (Mongoose)
Levels:
levels{ guildId, userId, xp, level, lastMessageAt }— índice único{ guildId, userId }.Economy Users:
economy_users{ guildId, userId, balance, bank }— índice único{ guildId, userId }.Transacciones:
economy_txs{ guildId, type, fromId?, toId?, itemId?, amount, meta }.Cooldowns:
economy_cooldowns{ guildId, userId, action, readyAt }— índice único{ guildId, userId, action }.Inventario:
economy_inventory{ guildId, userId, itemId, qty }— índice único{ guildId, userId, itemId }.Tienda:
shop_items{ guildId, itemId, name, price, data }— índice único{ guildId, itemId }.
Variables de entorno (colecciones) opcionales
LEVELS_COLLECTION(default:levels)ECON_USERS_COLLECTION(economy_users)ECON_TX_COLLECTION(economy_txs)ECON_CD_COLLECTION(economy_cooldowns)ECON_INV_COLLECTION(economy_inventory)ECON_SHOP_COLLECTION(shop_items)
🧩 Ejemplo de leaderboard (Discord.js)
const lb = await Levels.fetchLeaderboard(guildId, 10);
const rows = await Levels.computeLeaderboard(client, lb, true);
const lines = rows.map(r => `#${r.position} — <@${r.userID}> · Lvl ${r.level} · ${r.xp} XP`);
message.channel.send(lines.join('\n'));🔁 Patrón sugerido: pagar al subir de nivel
const leveled = await Levels.appendXp(userId, guildId, 10);
if (leveled) {
const { level } = await Levels.fetch(userId, guildId);
// base simple: 10 x nivel
const coins = 10 * level;
await Levels.add(userId, guildId, coins, 'levelUp');
}Si además pagas por rol ascendido, calcula el
tierde tu ladder y suma al monto (p. ej.coins += tier * 10).
❓ FAQ
¿appendXp devuelve el nuevo nivel?
No; devuelve true/false. Para leer el nivel, usa await Levels.fetch(userId, guildId).
¿Puedo usar mi conexión de Mongoose?
Sí: Levels.setMongoInstance(mongoose.connection).
¿Se pueden cambiar los nombres de colecciones?
Sí, con las variables de entorno de arriba.
📝 Licencia
MIT © thenekros
