Added level system and move commands to categories
This commit is contained in:
parent
23460dfdbf
commit
70f8c23bbf
37
.dockerignore
Normal file
37
.dockerignore
Normal file
@ -0,0 +1,37 @@
|
||||
# Dependencies
|
||||
node_modules
|
||||
npm-debug.log
|
||||
yarn-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Version control
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# IDE and editor files
|
||||
.idea
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Build output
|
||||
dist
|
||||
build
|
||||
coverage
|
||||
|
||||
# Docker files
|
||||
Dockerfile
|
||||
docker-compose.yml
|
||||
.dockerignore
|
||||
|
||||
# Development config
|
||||
botconfig.dev.json
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
/node_modules
|
||||
/.babelrc
|
||||
/yarn.lock
|
||||
/botconfig.json
|
||||
/botconfig.json
|
||||
/botconfig.dev.json
|
||||
27
Dockerfile
Normal file
27
Dockerfile
Normal file
@ -0,0 +1,27 @@
|
||||
# Use Debian Bookworm as the base image
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
# Install Node.js and npm
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
gnupg \
|
||||
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
||||
&& apt-get install -y nodejs \
|
||||
fonts-liberation fonts-dejavu fontconfig \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy package.json and package-lock.json (if available)
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install
|
||||
|
||||
# Copy application code
|
||||
COPY . .
|
||||
|
||||
# Start the application
|
||||
CMD ["npm", "start"]
|
||||
BIN
assets/level_clean.png
Normal file
BIN
assets/level_clean.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 465 KiB |
BIN
assets/progress_fill.png
Normal file
BIN
assets/progress_fill.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 427 B |
92
commands/admin/adjust_xp.js
Normal file
92
commands/admin/adjust_xp.js
Normal file
@ -0,0 +1,92 @@
|
||||
const Embed = require("../../functions/embed")
|
||||
const { updateUserXP, getUserXP } = require("../../models/user");
|
||||
const { xpSystem } = require("../../functions/level/xpSystem");
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
name: "adjustxp",
|
||||
cooldown: 5000,
|
||||
available: true,
|
||||
usage: true,
|
||||
permissions: [],
|
||||
aliases: [],
|
||||
roles: ['staff'],
|
||||
dm: false,
|
||||
},
|
||||
run: async (client, message, args, db) => {
|
||||
if (!args[0]) return message.reply("You must mention a user to adjust their XP", false);
|
||||
if (message.mentionIds && message.mentionIds.length > 0) {
|
||||
let targetUser;
|
||||
try {
|
||||
const server = await client.servers.fetch(message.server.id);
|
||||
const member = await server.fetchMember(message.mentionIds[0]);
|
||||
|
||||
if (!member || !member.id || !member.id.user) {
|
||||
throw new Error("Invalid member structure");
|
||||
}
|
||||
|
||||
// Fetch the user using the user ID from the member object
|
||||
targetUser = await client.users.fetch(member.id.user);
|
||||
|
||||
if (!targetUser || !targetUser.username) {
|
||||
throw new Error("Could not fetch user information");
|
||||
}
|
||||
|
||||
} catch (fetchError) {
|
||||
console.error("Fetch error details:", fetchError.message);
|
||||
return message.reply({
|
||||
embeds: [new Embed()
|
||||
.setDescription("Could not find the mentioned user.")
|
||||
.setColor(`#FF0000`)]
|
||||
}, false);
|
||||
}
|
||||
|
||||
if (!args[1]) return message.reply("You must specify an amount to adjust the XP by. `!adjust_xp @USER +/-<AMOUNT>`", false);
|
||||
|
||||
// Validate the amount is a valid number
|
||||
const amountStr = args[1].replace("+", "").replace("-", "");
|
||||
const amount = parseInt(amountStr);
|
||||
|
||||
if (isNaN(amount)) {
|
||||
return message.reply({
|
||||
embeds: [new Embed()
|
||||
.setDescription("Invalid amount specified. Please provide a valid number.")
|
||||
.setColor(`#FF0000`)]
|
||||
}, false);
|
||||
}
|
||||
|
||||
try {
|
||||
const userDoc = await getUserXP(targetUser.id);
|
||||
const currentXP = userDoc.xp || 0;
|
||||
const newXP = args[1].includes("+") ? currentXP + amount : currentXP - amount;
|
||||
|
||||
// Ensure the new XP value is not negative
|
||||
if (newXP < 0) {
|
||||
return message.reply({
|
||||
embeds: [new Embed()
|
||||
.setDescription("Cannot set XP below 0.")
|
||||
.setColor(`#FF0000`)]
|
||||
}, false);
|
||||
}
|
||||
|
||||
await updateUserXP(targetUser, newXP);
|
||||
const adjusted_amount = args[1].includes("+") ? `+${amount}` : `-${amount}`;
|
||||
await xpSystem(client, message);
|
||||
return message.reply({
|
||||
embeds: [new Embed()
|
||||
.setDescription(`XP adjusted for ${targetUser.username} by ${adjusted_amount}`)
|
||||
.setColor(`#00FF00`)]
|
||||
}, false);
|
||||
} catch (error) {
|
||||
console.error("Error updating XP:", error);
|
||||
return message.reply({
|
||||
embeds: [new Embed()
|
||||
.setDescription("An error occurred while updating the XP.")
|
||||
.setColor(`#FF0000`)]
|
||||
}, false);
|
||||
}
|
||||
} else {
|
||||
return message.reply("You must mention a user to adjust their XP", false);
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
const Embed = require("../functions/embed")
|
||||
const Embed = require("../../functions/embed")
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
@ -1,10 +1,25 @@
|
||||
const axios = require(`axios`);
|
||||
const path = require('path');
|
||||
const botConfig = require(path.join(__dirname, '../botconfig.json'));
|
||||
const { generateUniqueId } = require(path.join(__dirname, '../functions/randomStr'));
|
||||
const botConfig = require(path.join(__dirname, '../../botconfig.json'));
|
||||
const { generateUniqueId } = require(path.join(__dirname, '../../functions/randomStr'));
|
||||
const https = require('https');
|
||||
const Invites = require(path.join(__dirname, '../models/registerInvite'));
|
||||
const Embed = require(path.join(__dirname, '../functions/embed'));
|
||||
const Invites = require(path.join(__dirname, '../../models/registerInvite'));
|
||||
const Embed = require(path.join(__dirname, '../../functions/embed'));
|
||||
const DELAY = '5m';
|
||||
|
||||
// Helper function to parse time string to milliseconds
|
||||
const parseTimeToMs = (timeStr) => {
|
||||
const unit = timeStr.slice(-1).toLowerCase();
|
||||
const value = parseInt(timeStr.slice(0, -1));
|
||||
|
||||
switch(unit) {
|
||||
case 's': return value * 1000; // seconds
|
||||
case 'm': return value * 60 * 1000; // minutes
|
||||
case 'h': return value * 60 * 60 * 1000; // hours
|
||||
case 'd': return value * 24 * 60 * 60 * 1000; // days
|
||||
default: return 300000; // default 5 minutes if invalid format
|
||||
}
|
||||
};
|
||||
|
||||
// Create axios instance outside of module.exports
|
||||
const makeRequest = axios.create({
|
||||
@ -17,6 +32,16 @@ const makeRequest = axios.create({
|
||||
})
|
||||
});
|
||||
|
||||
// Helper function to delete messages after delay
|
||||
const deleteAfterDelay = async (message, delay = parseTimeToMs(DELAY)) => {
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
await message.delete().catch(() => {});
|
||||
} catch (error) {
|
||||
console.error('Error deleting message:', error);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
name: `register`,
|
||||
@ -29,24 +54,41 @@ module.exports = {
|
||||
dm: true
|
||||
},
|
||||
run: async (client, message, args, db) => {
|
||||
console.log('[Register Command] Command started with args:', {
|
||||
args: args,
|
||||
channelType: message.channel.type,
|
||||
author: message.author.username,
|
||||
guild: message.server?.name || 'DM'
|
||||
});
|
||||
try {
|
||||
// If not in DM, check for permissions and roles
|
||||
if (message.channel.type !== 'DirectMessage') {
|
||||
console.log('[Register Command] Not in DM, checking permissions');
|
||||
// Get allowed role IDs from config
|
||||
const allowedRoleIds = module.exports.config.roles
|
||||
.map(roleName => botConfig.roles[0][roleName])
|
||||
.filter(Boolean);
|
||||
console.log('[Register Command] Allowed role IDs:', allowedRoleIds);
|
||||
console.log('[Register Command] User roles:', message.member.roles);
|
||||
console.log('[Register Command] Bot config roles:', botConfig.roles[0]);
|
||||
|
||||
const hasRequiredRole = message.member.roles.some(roleId => allowedRoleIds.includes(roleId));
|
||||
console.log('[Register Command] Has required role:', hasRequiredRole);
|
||||
console.log('[Register Command] Is owner:', client.config.owners.includes(message.authorId));
|
||||
|
||||
if (!hasRequiredRole && !client.config.owners.includes(message.authorId)) {
|
||||
return message.reply({
|
||||
console.log('[Register Command] User lacks required permissions');
|
||||
const reply = await message.reply({
|
||||
embeds: [
|
||||
new Embed()
|
||||
.setColor("#FF0000")
|
||||
.setDescription(`You don't have the required roles to use this command.`)
|
||||
]
|
||||
});
|
||||
// Delete both messages after 5 minutes
|
||||
deleteAfterDelay(message);
|
||||
deleteAfterDelay(reply);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,41 +122,46 @@ module.exports = {
|
||||
|
||||
await registerInvite.save();
|
||||
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `Run this command in a DM to the bot and use this invite code: \`${inviteCode}\`\n
|
||||
**Usage:** \`!register ${inviteCode} <username> <email> <f95zone profile url>\`\n
|
||||
**Note: This invite code will expire in 10 minutes.**`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const [invite, username, email, profileUrl] = args;
|
||||
|
||||
if (!invite || !username || !email || !profileUrl) {
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG3] Please provide a invite code, username, email, and f95zone profile url. \n\n**Usage:** \`${client.prefix}register <invite> <username> <email> <f95zone profile url>\``
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// DM flow - Use client.database instead of direct model
|
||||
const registerInvite = await Invites.findOne({ invite: invite });
|
||||
|
||||
if (!registerInvite) {
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG1] You don't have an invite code. Please run the command outside of DMs.`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (registerInvite.createdAt + 10 * 60 * 1000 < Date.now()) {
|
||||
await registerInvite.deleteOne({ invite: invite });
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG2] Your invite code has expired. Please run the command outside of DMs.`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (invite !== registerInvite.invite) {
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG4] Invalid invite code. Please run the command outside of DMs.`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let f95zoneId = profileUrl.split('/')[4];
|
||||
@ -134,40 +181,49 @@ module.exports = {
|
||||
|
||||
if (data.status === 'success') {
|
||||
await registerInvite.deleteOne({ invite: invite });
|
||||
return message.reply({
|
||||
content: `[REG5] You have been registered. Please check your email for verification.`
|
||||
const reply = await message.reply({
|
||||
content: `[REG5] You have been registered. Please check your email for verification.\n
|
||||
**If you do not receive email in 5 minutes. Please check your spam or trash for email.**`
|
||||
});
|
||||
return;
|
||||
} else if (data.status === 'invalid_email') {
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG5.1] An error occurred during registration. ${data.msg}`
|
||||
});
|
||||
return;
|
||||
} else if (data.status === 'username_exists') {
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG5.2] An error occurred during registration. ${data.msg}`
|
||||
});
|
||||
return;
|
||||
} else if (data.status === 'invalid_f95_id') {
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG5.3] An error occurred during registration. ${data.msg}`
|
||||
});
|
||||
return;
|
||||
} else if (data.status === 'email_exists') {
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG5.4] An error occurred during registration. ${data.msg}`
|
||||
});
|
||||
return;
|
||||
} else if (data.status === 'error') {
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG5.5] An error occurred during registration. ${data.msg}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
} catch (apiError) {
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG6] An error occurred during registration. Please try again later.\n\`${apiError}\``
|
||||
});
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Registration Error:', error);
|
||||
return message.reply({
|
||||
const reply = await message.reply({
|
||||
content: `[REG7] An unexpected error occurred. Please try again later.\n\`${error}\``
|
||||
});
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
const Reload = require("../functions/reload")
|
||||
const Reload = require("../../functions/reload")
|
||||
module.exports = {
|
||||
config: {
|
||||
name: "reload",
|
||||
@ -1,6 +1,6 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const Embed = require("../functions/embed")
|
||||
const Embed = require("../../functions/embed")
|
||||
const Uploader = require("revolt-uploader");
|
||||
|
||||
module.exports = {
|
||||
@ -1,12 +1,12 @@
|
||||
const Embed = require("../functions/embed")
|
||||
const Embed = require("../../functions/embed")
|
||||
const fetch = require('node-fetch-commonjs')
|
||||
const config = require('../config')
|
||||
const config = require('../../config')
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
name: "gif",
|
||||
usage: true,
|
||||
cooldown: 5000,
|
||||
cooldown: 10000,
|
||||
available: true,
|
||||
permissions: [],
|
||||
roles: [],
|
||||
@ -1,4 +1,4 @@
|
||||
const Embed = require("../functions/embed");
|
||||
const Embed = require("../../functions/embed");
|
||||
const axios = require('axios');
|
||||
|
||||
module.exports = {
|
||||
@ -1,6 +1,6 @@
|
||||
const Embed = require("../functions/embed")
|
||||
const CommandsDB = require('../models/commands');
|
||||
const { random } = require('../functions/randomStr');
|
||||
const Embed = require("../../functions/embed")
|
||||
const CommandsDB = require('../../models/commands');
|
||||
const { random } = require('../../functions/randomStr');
|
||||
const moment = require('moment');
|
||||
|
||||
module.exports = {
|
||||
@ -1,8 +1,8 @@
|
||||
const Embed = require(`../functions/embed`)
|
||||
const Polls = require(`../functions/poll`)
|
||||
const dhms = require(`../functions/dhms`);
|
||||
const PollDB = require("../models/polls");
|
||||
const SavedPolls = require(`../models/savedPolls`)
|
||||
const Embed = require(`../../functions/embed`)
|
||||
const Polls = require(`../../functions/poll`)
|
||||
const dhms = require(`../../functions/dhms`);
|
||||
const PollDB = require("../../models/polls");
|
||||
const SavedPolls = require(`../../models/savedPolls`)
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
@ -1,8 +1,8 @@
|
||||
const Embed = require(`../functions/embed`)
|
||||
const Polls = require(`../functions/poll`)
|
||||
const dhms = require(`../functions/dhms`);
|
||||
const PollDB = require("../models/rule7");
|
||||
const SavedPolls = require(`../models/savedPolls`)
|
||||
const Embed = require(`../../functions/embed`)
|
||||
const Polls = require(`../../functions/poll`)
|
||||
const dhms = require(`../../functions/dhms`);
|
||||
const PollDB = require("../../models/rule7");
|
||||
const SavedPolls = require(`../../models/savedPolls`)
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
@ -1,4 +1,4 @@
|
||||
const Embed = require("../functions/embed")
|
||||
const Embed = require("../../functions/embed")
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
@ -1,4 +1,4 @@
|
||||
const Embed = require("../functions/embed")
|
||||
const Embed = require("../../functions/embed")
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
@ -1,7 +1,7 @@
|
||||
const Embed = require("../functions/embed");
|
||||
const Giveaway = require("../models/giveaways");
|
||||
const SavedPolls = require("../models/savedPolls");
|
||||
const { dependencies } = require("../package.json");
|
||||
const Embed = require("../../functions/embed");
|
||||
const Giveaway = require("../../models/giveaways");
|
||||
const SavedPolls = require("../../models/savedPolls");
|
||||
const { dependencies } = require("../../package.json");
|
||||
module.exports = {
|
||||
config: {
|
||||
name: "info",
|
||||
46
commands/utility/level.js
Normal file
46
commands/utility/level.js
Normal file
@ -0,0 +1,46 @@
|
||||
const { getUserXP } = require("../../models/user");
|
||||
const generateLevelCard = require("../../functions/level/generate_level_card");
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
name: "level",
|
||||
usage: true,
|
||||
cooldown: 5000,
|
||||
available: true,
|
||||
permissions: [],
|
||||
roles: [],
|
||||
dm: false,
|
||||
aliases: ['lvl']
|
||||
},
|
||||
run: async (client, message, args, db) => {
|
||||
try {
|
||||
const user = await getUserXP(message.author.id);
|
||||
const levelCardBuffer = await generateLevelCard(user);
|
||||
|
||||
// Create a temporary file path
|
||||
const tempFilePath = path.join(os.tmpdir(), `level_card_${message.author.id}.png`);
|
||||
|
||||
// Save the buffer to the temporary file
|
||||
await fs.writeFile(tempFilePath, levelCardBuffer);
|
||||
|
||||
// Upload the file
|
||||
const attachment = await client.Uploader.uploadFile(tempFilePath, "level_card.png");
|
||||
|
||||
// Send the message with the attachment
|
||||
await message.channel.sendMessage({
|
||||
attachments: [attachment]
|
||||
});
|
||||
|
||||
// Clean up the temporary file
|
||||
await fs.unlink(tempFilePath).catch(console.error);
|
||||
} catch (error) {
|
||||
console.error('Error in level command:', error);
|
||||
await message.channel.sendMessage({
|
||||
content: "❌ An error occurred while generating your level card. Please try again later."
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
42
docker-compose.yml
Normal file
42
docker-compose.yml
Normal file
@ -0,0 +1,42 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
container_name: zonies-bot
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- MONGODB_URI=mongodb://mongodb:27017/zonies
|
||||
volumes:
|
||||
- ./assets:/usr/src/app/assets
|
||||
- ./botconfig.json:/usr/src/app/botconfig.json
|
||||
depends_on:
|
||||
- mongodb
|
||||
networks:
|
||||
- app-network
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2'
|
||||
memory: 4G
|
||||
reservations:
|
||||
cpus: '1'
|
||||
memory: 2G
|
||||
|
||||
mongodb:
|
||||
image: mongo:6.0
|
||||
container_name: zonies-mongodb
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "27017:27017"
|
||||
volumes:
|
||||
- mongodb_data:/data/db
|
||||
networks:
|
||||
- app-network
|
||||
|
||||
networks:
|
||||
app-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
mongodb_data:
|
||||
@ -5,6 +5,7 @@ const EditCollector = require(path.join(__dirname, "../functions/messageEdit"));
|
||||
const CommandDB = require(path.join(__dirname, "../models/commands"));
|
||||
const { isJson } = require(path.join(__dirname, "../functions/randomStr"));
|
||||
const botConfig = require(path.join(__dirname, "../botconfig.json"));
|
||||
const {xpSystem} = require(path.join(__dirname, "../functions/level/xpSystem"));
|
||||
|
||||
module.exports = async (client, message) => {
|
||||
// Early return checks
|
||||
@ -13,12 +14,18 @@ module.exports = async (client, message) => {
|
||||
const isDM = message.channel.type === "DirectMessage";
|
||||
|
||||
// Get guild settings (if not DM)
|
||||
const db = isDM ? { prefix: client.botConfig.prefix, language: 'en' } : await client.database.getGuild(message.server.id, true);
|
||||
const db = isDM ? { prefix: client.config.prefix, language: 'en' } : await client.database.getGuild(message.server.id, true);
|
||||
|
||||
if (!isDM) {
|
||||
await xpSystem(client, message);
|
||||
}
|
||||
|
||||
// Check if message starts with prefix
|
||||
if (!message.content.startsWith(db.prefix)) {
|
||||
|
||||
// Handle bot mention
|
||||
if (message.content && (new RegExp(`^(<@!?${client.user.id}>)`)).test(message.content)) {
|
||||
console.log('[MessageCreate] Bot was mentioned');
|
||||
const mention = new Embed()
|
||||
.setColor("#A52F05")
|
||||
.setTitle(client.user.username)
|
||||
@ -41,6 +48,7 @@ module.exports = async (client, message) => {
|
||||
// Handle custom commands
|
||||
let check = await CommandDB.findOne({ name: cmd }).select("name").lean();
|
||||
if (check) {
|
||||
console.log('[MessageCreate] Custom command found:', cmd);
|
||||
CommandDB.findOne({ name: cmd }).then((data) => {
|
||||
if (isJson(data.content)) {
|
||||
let items = JSON.parse(data.content);
|
||||
@ -53,6 +61,7 @@ module.exports = async (client, message) => {
|
||||
|
||||
// Command handling
|
||||
let commandfile = client.commands.get(cmd) || client.commands.get(client.aliases.get(cmd));
|
||||
|
||||
if (commandfile) {
|
||||
// DM Check - if command doesn't allow DMs and we're in a DM, return
|
||||
if (isDM && !commandfile.config.dm) {
|
||||
|
||||
88
functions/level/generate_level_card.js
Normal file
88
functions/level/generate_level_card.js
Normal file
@ -0,0 +1,88 @@
|
||||
const { createCanvas, loadImage } = require('canvas');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Calculates the XP required for the next level
|
||||
* @param {number} currentLevel - Current user level
|
||||
* @returns {number} XP required for next level
|
||||
*/
|
||||
function calculateNextLevelXP(currentLevel) {
|
||||
// Using the inverse of the level calculation formula from xpSystem.js
|
||||
// level = 0.47 * sqrt(xp)
|
||||
// Therefore, xp = (level/0.47)^2
|
||||
return Math.ceil(Math.pow((currentLevel + 1) / 0.47, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a level card image for a user
|
||||
* @param {Object} user - User object containing id, username, xp, and level
|
||||
* @returns {Promise<Buffer>} - Returns a buffer containing the generated image
|
||||
*/
|
||||
async function generateLevelCard(user) {
|
||||
// Create canvas with dimensions matching the background image
|
||||
const canvas = createCanvas(1516, 662);
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
try {
|
||||
// Load background image
|
||||
const background = await loadImage(path.join(__dirname, '../../assets/level_clean.png'));
|
||||
ctx.drawImage(background, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Load progress bar fill image
|
||||
const progressFill = await loadImage(path.join(__dirname, '../../assets/progress_fill.png'));
|
||||
|
||||
// Calculate XP progress using the same formula as xpSystem.js
|
||||
const currentLevelXP = Math.floor(Math.pow(user.level / 0.47, 2));
|
||||
const nextLevelXP = Math.floor(calculateNextLevelXP(user.level));
|
||||
const xpInLevel = user.xp - currentLevelXP;
|
||||
const xpForLevel = nextLevelXP - currentLevelXP;
|
||||
// Clamp progress between 0 and 1
|
||||
const progress = Math.max(0, Math.min(1, xpInLevel / xpForLevel));
|
||||
// Clamp displayed XP to not exceed xpForLevel
|
||||
const displayXP = Math.min(Math.max(0, xpInLevel), xpForLevel);
|
||||
|
||||
// Draw username
|
||||
ctx.font = 'bold 60px Arial';
|
||||
ctx.fillStyle = '#FFFFFF';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText(user.username, 420, 250);
|
||||
|
||||
// Draw level
|
||||
ctx.font = 'bold 48px Arial';
|
||||
ctx.fillStyle = '#FFD700'; // Gold color for level
|
||||
ctx.fillText(`Level ${user.level}`, 420, 330);
|
||||
|
||||
// Progress bar dimensions and position
|
||||
const progressBarX = 472;
|
||||
const progressBarY = 388;
|
||||
const progressBarWidth = 800;
|
||||
const progressBarHeight = 60;
|
||||
|
||||
// Draw progress bar fill
|
||||
ctx.drawImage(
|
||||
progressFill,
|
||||
progressBarX,
|
||||
progressBarY,
|
||||
progressBarWidth * progress,
|
||||
progressBarHeight
|
||||
);
|
||||
|
||||
// Draw XP progress text inside the bar, right-aligned
|
||||
ctx.font = 'bold 36px Arial';
|
||||
ctx.fillStyle = '#FFFFFF';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(
|
||||
`${displayXP}/${xpForLevel} XP`,
|
||||
progressBarX + progressBarWidth / 2,
|
||||
progressBarY + progressBarHeight / 2 + 12 // adjust as needed
|
||||
);
|
||||
|
||||
// Convert canvas to buffer
|
||||
return canvas.toBuffer('image/png');
|
||||
} catch (error) {
|
||||
console.error('Error generating level card:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = generateLevelCard;
|
||||
84
functions/level/xpSystem.js
Normal file
84
functions/level/xpSystem.js
Normal file
@ -0,0 +1,84 @@
|
||||
const Embed = require("../embed");
|
||||
const { User, getUserXP, checkUser, updateUserMessageCount, updateUserXPAndLevel } = require("../../models/user");
|
||||
const { XPSetting, getXPSettings } = require("../../models/xp_setting");
|
||||
const logger = require("../logger");
|
||||
|
||||
const self = module.exports = {
|
||||
xpSystem: async (client, message) => {
|
||||
try {
|
||||
// Check if message is from a server
|
||||
if (!message.server) {
|
||||
return; // Skip XP for DMs
|
||||
}
|
||||
|
||||
await checkUser(message.author);
|
||||
const user = await getUserXP(message.author.id);
|
||||
const settings = await getXPSettings(message.server.id);
|
||||
|
||||
// If no settings exist for this server, create default settings
|
||||
if (!settings) {
|
||||
const defaultSettings = {
|
||||
serverId: message.server.id,
|
||||
messages_per_xp: 3,
|
||||
min_xp_per_gain: 2,
|
||||
max_xp_per_gain: 12,
|
||||
weekend_multiplier: 2,
|
||||
weekend_days: "sat,sun",
|
||||
double_xp_enabled: false,
|
||||
level_up_enabled: true,
|
||||
level_up_channel: '01HF7B18Z864E10XSF22F9RFZQ'
|
||||
};
|
||||
await XPSetting.create(defaultSettings);
|
||||
return; // Skip this message, will work from next message
|
||||
}
|
||||
|
||||
user.message_count++;
|
||||
|
||||
if (user.message_count >= settings.messages_per_xp) {
|
||||
user.message_count = 0;
|
||||
let xpGain = Math.floor(Math.random() * (settings.max_xp_per_gain - settings.min_xp_per_gain + 1)) + settings.min_xp_per_gain;
|
||||
|
||||
if (settings.double_xp_enabled || self.isWeekend(settings.weekend_days)) {
|
||||
xpGain *= settings.weekend_multiplier;
|
||||
}
|
||||
|
||||
user.xp += xpGain;
|
||||
|
||||
const newLevel = self.calculateLevel(user.xp);
|
||||
if (newLevel > user.level) {
|
||||
user.level = newLevel;
|
||||
if (settings.level_up_enabled) {
|
||||
const channel = client.channels.get(settings.level_up_channel);
|
||||
if (channel) {
|
||||
await self.sendLevelUpMessage(channel, message.author, newLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await updateUserXPAndLevel(message.author.id, user.xp, user.level, user.message_count);
|
||||
logger.info('XP SYSTEM', `${message.author.username} gained ${xpGain} XP and is now level ${user.level}`);
|
||||
} else {
|
||||
await updateUserMessageCount(message.author.id, user.message_count);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('XP SYSTEM', error);
|
||||
}
|
||||
},
|
||||
|
||||
isWeekend: (weekendDays) => {
|
||||
const today = new Date().toLocaleDateString('en-US', { weekday: 'short' }).toLowerCase();
|
||||
return weekendDays.split(',').includes(today);
|
||||
},
|
||||
|
||||
calculateLevel: (xp) => Math.floor(0.47 * Math.sqrt(xp)),
|
||||
|
||||
sendLevelUpMessage: async (channel, user, newLevel) => {
|
||||
const embed = {
|
||||
title: 'Level Up!',
|
||||
description: `Congratulations ${user.username}! You've reached level ${newLevel}!`,
|
||||
colour: '#00FF00'
|
||||
};
|
||||
|
||||
await channel.sendMessage({ embeds: [embed] });
|
||||
}
|
||||
};
|
||||
@ -1,7 +1,30 @@
|
||||
const { readdirSync } = require("fs")
|
||||
const { readdirSync, statSync } = require("fs")
|
||||
const { join } = require("path")
|
||||
const color = require("../functions/colorCodes")
|
||||
|
||||
/**
|
||||
* Recursively gets all command files from a directory
|
||||
* @param {string} dir - Directory to scan
|
||||
* @returns {string[]} Array of command file paths
|
||||
*/
|
||||
function getCommandFiles(dir) {
|
||||
const files = []
|
||||
const items = readdirSync(dir)
|
||||
|
||||
for (const item of items) {
|
||||
const path = join(dir, item)
|
||||
const stat = statSync(path)
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
files.push(...getCommandFiles(path))
|
||||
} else if (item.endsWith('.js')) {
|
||||
files.push(path)
|
||||
}
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and registers all command files from the commands directory
|
||||
* @param {Object} client - The Discord client instance
|
||||
@ -10,14 +33,14 @@ const color = require("../functions/colorCodes")
|
||||
module.exports = async (client) => {
|
||||
try {
|
||||
const commandsPath = join(__dirname, "..", "commands")
|
||||
const commandFiles = readdirSync(commandsPath).filter(file => file.endsWith(".js"))
|
||||
|
||||
const commandFiles = getCommandFiles(commandsPath)
|
||||
|
||||
let loadedCommands = 0
|
||||
let failedCommands = 0
|
||||
|
||||
for (const file of commandFiles) {
|
||||
try {
|
||||
const command = require(join(commandsPath, file))
|
||||
const command = require(file)
|
||||
|
||||
// Validate command structure
|
||||
if (!command.config?.name) {
|
||||
@ -26,6 +49,8 @@ module.exports = async (client) => {
|
||||
continue
|
||||
}
|
||||
|
||||
console.log(color("%", `%b[Command_Handler]%7 :: Loading %e${command.config.name}%7 command`))
|
||||
|
||||
// Register command and aliases
|
||||
client.commands.set(command.config.name, command)
|
||||
if (command.config.aliases?.length) {
|
||||
|
||||
17
index.js
17
index.js
@ -1,12 +1,27 @@
|
||||
const { Client } = require("revolt.js");
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const { token, mongoDB, api } = require("./botconfig.json");
|
||||
const logger = require('./functions/logger');
|
||||
const checkPolls = require('./functions/checkPolls');
|
||||
const color = require("./functions/colorCodes");
|
||||
const Uploader = require("revolt-uploader");
|
||||
const TranslationHandler = require('./handlers/translation');
|
||||
const DatabaseHandler = require('./handlers/database');
|
||||
// let config;
|
||||
|
||||
// if (process.env.NODE_ENV === "development") {
|
||||
// config = require("./botconfig.dev.json");
|
||||
// } else {
|
||||
// config = require("./botconfig.json");
|
||||
// }
|
||||
const config = require("./botconfig.json");
|
||||
|
||||
// Validate required configuration
|
||||
if (!config || !config.token || !config.mongoDB || !config.api) {
|
||||
throw new Error('Missing required configuration. Please check your botconfig.json file.');
|
||||
}
|
||||
|
||||
const { token, mongoDB, api } = config;
|
||||
console.log(mongoDB)
|
||||
|
||||
class Bot {
|
||||
constructor(config) {
|
||||
|
||||
BIN
level_card.png
Normal file
BIN
level_card.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 458 KiB |
@ -2,7 +2,7 @@ const { Schema, model } = require("mongoose");
|
||||
|
||||
const guilds = new Schema({
|
||||
id: { type: String },
|
||||
prefix: { type: String, default: "f!" },
|
||||
prefix: { type: String, default: "!" },
|
||||
language: { type: String, default: "en_EN" },
|
||||
joined: { type: String, default: Date.now() / 1000 | 0 },
|
||||
dm: { type: Boolean, default: true },
|
||||
|
||||
118
models/user.js
Normal file
118
models/user.js
Normal file
@ -0,0 +1,118 @@
|
||||
const { Schema, model } = require("mongoose");
|
||||
|
||||
const user = new Schema({
|
||||
id: { type: String },
|
||||
username: { type: String },
|
||||
xp: { type: Number, default: 0 },
|
||||
level: { type: Number, default: 1 },
|
||||
message_count: { type: Number, default: 0 }
|
||||
});
|
||||
|
||||
async function checkUser(user) {
|
||||
const userId = user.id;
|
||||
const username = user.username;
|
||||
|
||||
// Find user by id
|
||||
const existingUser = await User.findOne({ id: userId });
|
||||
|
||||
// If user doesn't exist, create new user
|
||||
if (!existingUser) {
|
||||
await User.create({
|
||||
id: userId,
|
||||
username: username,
|
||||
xp: 0,
|
||||
level: 1,
|
||||
message_count: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function getUserXP(userId) {
|
||||
let userDoc = await User.findOne({ id: userId });
|
||||
|
||||
// If user doesn't exist, create new user
|
||||
if (!userDoc) {
|
||||
userDoc = await User.create({
|
||||
id: userId,
|
||||
xp: 0,
|
||||
level: 1,
|
||||
message_count: 0
|
||||
});
|
||||
}
|
||||
|
||||
return userDoc;
|
||||
}
|
||||
|
||||
async function updateUserXP(user, xp) {
|
||||
const userId = user.id;
|
||||
const userDoc = await User.findOne({ id: userId });
|
||||
userDoc.xp = xp;
|
||||
await userDoc.save();
|
||||
}
|
||||
|
||||
async function updateUserLevel(user, level) {
|
||||
const userId = user.id;
|
||||
const userDoc = await User.findOne({ id: userId });
|
||||
userDoc.level = level;
|
||||
await userDoc.save();
|
||||
}
|
||||
|
||||
async function updateUserXPAndLevel(userId, xp, level, message_count) {
|
||||
const userDoc = await User.findOne({ id: userId });
|
||||
if (!userDoc) {
|
||||
return await User.create({
|
||||
id: userId,
|
||||
xp: xp,
|
||||
level: level,
|
||||
message_count: message_count
|
||||
});
|
||||
}
|
||||
userDoc.xp = xp;
|
||||
userDoc.level = level;
|
||||
userDoc.message_count = message_count;
|
||||
await userDoc.save();
|
||||
}
|
||||
|
||||
async function updateUserMessageCount(userId, message_count) {
|
||||
const userDoc = await User.findOne({ id: userId });
|
||||
if (!userDoc) {
|
||||
return await User.create({
|
||||
id: userId,
|
||||
xp: 0,
|
||||
level: 1,
|
||||
message_count: message_count
|
||||
});
|
||||
}
|
||||
userDoc.message_count = message_count;
|
||||
await userDoc.save();
|
||||
}
|
||||
/**
|
||||
* Retrieves the top users sorted by XP
|
||||
* @param {number} limit - Maximum number of users to return (default: 10)
|
||||
* @returns {Promise<Array>} Array of user objects containing id, username, xp, and level
|
||||
*/
|
||||
async function getLeaderboard(limit = 10) {
|
||||
const users = await User.find()
|
||||
.sort({ xp: -1 })
|
||||
.limit(limit)
|
||||
.select('id username xp level');
|
||||
|
||||
return users.map(user => ({
|
||||
user_id: user.id,
|
||||
username: user.username,
|
||||
xp: user.xp,
|
||||
level: user.level
|
||||
}));
|
||||
}
|
||||
|
||||
const User = model("user", user);
|
||||
module.exports = {
|
||||
checkUser,
|
||||
getUserXP,
|
||||
updateUserXP,
|
||||
updateUserLevel,
|
||||
updateUserXPAndLevel,
|
||||
getLeaderboard,
|
||||
updateUserMessageCount,
|
||||
User
|
||||
};
|
||||
30
models/xp_setting.js
Normal file
30
models/xp_setting.js
Normal file
@ -0,0 +1,30 @@
|
||||
const { Schema, model } = require("mongoose");
|
||||
|
||||
const xpSetting = new Schema({
|
||||
messages_per_xp: { type: Number },
|
||||
min_xp_per_gain: { type: Number },
|
||||
max_xp_per_gain: { type: Number },
|
||||
weekend_multiplier: { type: Number },
|
||||
weekend_days: { type: String },
|
||||
double_xp_enabled: { type: Boolean },
|
||||
serverId: { type: String },
|
||||
level_up_channel: { type: String },
|
||||
level_up_enabled: { type: Boolean }
|
||||
});
|
||||
|
||||
async function getXPSettings(serverId) {
|
||||
const settings = await XPSetting.findOne({ serverId: serverId });
|
||||
return settings;
|
||||
}
|
||||
|
||||
async function updateXPSettings(serverId, settings) {
|
||||
await XPSetting.updateOne({ serverId: serverId }, { $set: settings });
|
||||
}
|
||||
|
||||
const XPSetting = model("xpSetting", xpSetting);
|
||||
|
||||
module.exports = {
|
||||
getXPSettings,
|
||||
updateXPSettings,
|
||||
XPSetting
|
||||
};
|
||||
93
package-lock.json
generated
93
package-lock.json
generated
@ -21,6 +21,9 @@
|
||||
"revolt.js": "npm:revolt.js-update@^7.0.0-beta.9",
|
||||
"screen": "^0.2.10",
|
||||
"wumpfetch": "^0.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^7.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/collection": {
|
||||
@ -385,6 +388,40 @@
|
||||
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"cross-env": "src/bin/cross-env.js",
|
||||
"cross-env-shell": "src/bin/cross-env-shell.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||
@ -674,6 +711,13 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/isomorphic-ws": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
|
||||
@ -1171,6 +1215,16 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
||||
@ -1359,6 +1413,29 @@
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shiki": {
|
||||
"version": "0.14.4",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz",
|
||||
@ -1655,6 +1732,22 @@
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"node-which": "bin/node-which"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/wide-align": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
{
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
"start": "node index.js",
|
||||
"dev": "cross-env NODE_ENV=development node index.js"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -26,5 +27,8 @@
|
||||
"Discord": "ainzooalgown",
|
||||
"Revolt": "Ryahn#1337",
|
||||
"GitHub": "https://github.com/Ryahn/zonies"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^7.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
10
test.js
10
test.js
@ -15,13 +15,11 @@
|
||||
// })
|
||||
(async () => {
|
||||
|
||||
const axios = require("axios");
|
||||
const query = 'yeet'
|
||||
const url = ('https://api.urbandictionary.com/v0/define?term=' + query)
|
||||
const response = await axios.get(url);
|
||||
const data = response.data;
|
||||
const def = data.list[0];
|
||||
const xp = Math.floor(0.47 * Math.sqrt(12345632346));
|
||||
const level = Math.floor(xp / 100);
|
||||
|
||||
console.log(xp);
|
||||
console.log(level);
|
||||
|
||||
|
||||
})();
|
||||
Loading…
x
Reference in New Issue
Block a user