K9 is up again baybee
parent
ce23cf9250
commit
8310a28a8a
|
@ -1,7 +1,7 @@
|
|||
# Data folder & out folder
|
||||
out/
|
||||
data/
|
||||
build/
|
||||
conf.toml
|
||||
|
||||
# Logs
|
||||
logs
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 24 KiB |
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
assets/test.jpg
BIN
assets/test.jpg
Binary file not shown.
Before Width: | Height: | Size: 321 KiB |
12
src/Bot.ts
12
src/Bot.ts
|
@ -69,7 +69,9 @@ export default class Bot {
|
|||
|
||||
constructor(config: BotConfig) {
|
||||
this.config = config;
|
||||
this.client = new Discord.Client();
|
||||
const intents = new Discord.Intents(Discord.Intents.NON_PRIVILEGED);
|
||||
intents.add('GUILD_MEMBERS');
|
||||
this.client = new Discord.Client({ ws: { intents: intents }});
|
||||
// this.storage = new BotStorage(config);
|
||||
|
||||
// const adapter = new FileSync('./data/db.json');
|
||||
|
@ -144,8 +146,12 @@ export default class Bot {
|
|||
const command = full.substr(0, full.indexOf(' ') === -1 ? full.length : full.indexOf(' ')).toLowerCase().trimLeft();
|
||||
const args = full.substr(command.length).trimLeft().split(' ');
|
||||
const cmd = this.commands[command];
|
||||
if (typeof cmd === 'function') cmd(msg, command, args);
|
||||
else if (typeof cmd === 'object') cmd.trigger(msg, command, args);
|
||||
|
||||
if (cmd != undefined) {
|
||||
if (this.config.options.delete_triggers) msg.delete();
|
||||
if (typeof cmd === 'function') cmd(msg, command, args);
|
||||
else if (typeof cmd === 'object') cmd.trigger(msg, command, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ export default function Help(msg: Discord.Message) {
|
|||
'Hi, I\'m k9! I\'m a user level tracking bot made by Auri#1311. ' +
|
||||
'I assign users levels and automagically grants users roles once they reach certain level thresholds. ' +
|
||||
'I also have a few simple commands available to interact with me.')
|
||||
.setFooter(`Requested by ${(msg.member) ? msg.member.displayName : msg.author.username}`, msg.author.avatarURL({ size: 32 })!)
|
||||
.setFooter(`${(msg.member) ? msg.member.displayName : msg.author.username}`, msg.author.avatarURL({ size: 32 })!)
|
||||
.setTimestamp()
|
||||
|
||||
.addField('`k9 help`', '⠀Sends this message.')
|
||||
|
|
|
@ -2,14 +2,14 @@ import { promises as fs } from 'fs';
|
|||
|
||||
import log4js from 'log4js';
|
||||
import { parse } from 'toml';
|
||||
import Bot, { BotConfig } from "./Bot";
|
||||
import Bot, { BotConfig } from './Bot';
|
||||
|
||||
const logger = log4js.getLogger();
|
||||
logger.level = 'debug';
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const conf = parse((await fs.readFile('./data/conf.toml')).toString()) as BotConfig;
|
||||
const conf = parse((await fs.readFile('./conf.toml')).toString()) as BotConfig;
|
||||
await new Bot(conf).init();
|
||||
}
|
||||
catch (e) {
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import JIMP from 'jimp';
|
||||
|
||||
const IMAGE_PATH = 'assets/levelup.png';
|
||||
const IMAGE_PATH = 'assets/levelup_image.png';
|
||||
|
||||
export default async function buildLevelImage(name: string, level: number, filename: string) {
|
||||
let image = await JIMP.read(IMAGE_PATH);
|
||||
|
||||
let name_font = await JIMP.loadFont(JIMP.FONT_SANS_64_WHITE);
|
||||
await image.print(name_font, 10, 200 - (115 + 20) - 10, { text: name,
|
||||
alignmentX: JIMP.HORIZONTAL_ALIGN_CENTER, alignmentY: JIMP.VERTICAL_ALIGN_MIDDLE }, 766, 92);
|
||||
await image.print(name_font, 0, 48, { text: name,
|
||||
alignmentX: JIMP.HORIZONTAL_ALIGN_CENTER, alignmentY: JIMP.VERTICAL_ALIGN_MIDDLE }, 760, 92);
|
||||
|
||||
let level_font = await JIMP.loadFont(JIMP.FONT_SANS_32_WHITE);
|
||||
await image.print(level_font, 540, 200 - (54 + 20) - 10, { text: level.toString(10) + "!",
|
||||
alignmentX: JIMP.HORIZONTAL_ALIGN_CENTER, alignmentY: JIMP.VERTICAL_ALIGN_MIDDLE }, 780, 92);
|
||||
await image.print(level_font, 530, 106, { text: level.toString(10) + '!',
|
||||
alignmentX: JIMP.HORIZONTAL_ALIGN_LEFT, alignmentY: JIMP.VERTICAL_ALIGN_MIDDLE }, 780, 92);
|
||||
|
||||
let outPath = `out/${filename}.png`;
|
||||
let outPath = `./${filename}.png`;
|
||||
await image.quality(100).write(outPath);
|
||||
return outPath;
|
||||
}
|
||||
|
|
|
@ -1,64 +1,55 @@
|
|||
import { ExperienceConfig, LevelRole } from './LevelPlugin';
|
||||
import { LevelPluginConfig } from './LevelPlugin';
|
||||
|
||||
// Calculations: https://www.desmos.com/calculator/idluw8zexx
|
||||
|
||||
/**
|
||||
* Returns the level the provided XP reaches.
|
||||
*
|
||||
* @param {ExperienceConfig} config - The experience config to use for the calculations.
|
||||
* @param {LevelPluginConfig} config - The experience config to use for the calculations.
|
||||
* @param {number} experience - The experience to do the calculation for.
|
||||
*/
|
||||
|
||||
export function xpToLevel(config: ExperienceConfig, experience: number) {
|
||||
if (experience < config.offset) return 0;
|
||||
let level = 1;
|
||||
experience -= config.offset;
|
||||
while ((experience -= config.base * Math.sqrt(config.multiplier * level)) >= 0) level++;
|
||||
return level;
|
||||
export function xpToLevel(config: LevelPluginConfig, experience: number) {
|
||||
if (experience < config.experience.a) return 0;
|
||||
return Math.floor(Math.pow(experience - config.experience.a, 1 / config.experience.c) / config.experience.b) + 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the amount of XP required to go from level 0 to this level.
|
||||
*
|
||||
* @param {ExperienceConfig} config - The experience config to use for the calculations.
|
||||
* @param {LevelPluginConfig} config - The experience config to use for the calculations.
|
||||
* @param {number} level - The level to do the calculation for.
|
||||
*/
|
||||
|
||||
export function levelToXp(config: ExperienceConfig, level: number) {
|
||||
if (level == 0) return 0;
|
||||
let experience = config.offset;
|
||||
level--;
|
||||
while (level > 0) {
|
||||
experience += config.base * Math.sqrt(config.multiplier * level--);
|
||||
}
|
||||
return experience;
|
||||
export function levelToXp(config: LevelPluginConfig, level: number) {
|
||||
if (level <= 0) return 0;
|
||||
return config.experience.a + Math.pow((level - 1) * config.experience.b, config.experience.c);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the amount of XP required to go from this level to the level above.
|
||||
*
|
||||
* @param {ExperienceConfig} config - The experience config to use for the calculations.
|
||||
* @param {LevelPluginConfig} config - The experience config to use for the calculations.
|
||||
* @param {number} level - The level to do the calculation for.
|
||||
*/
|
||||
|
||||
export function xpInLevel(config: ExperienceConfig, level: number) {
|
||||
if (level < 0) return 0;
|
||||
if (level == 0) return config.offset;
|
||||
return config.base * Math.sqrt(config.multiplier * level);
|
||||
export function xpInLevel(config: LevelPluginConfig, level: number) {
|
||||
return levelToXp(config, level) - levelToXp(config, level - 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the role for the XP provided.
|
||||
*
|
||||
* @param {ExperienceConfig} config - The experience config to use for the calculations.
|
||||
* @param {LevelPluginConfig} config - The experience config to use for the calculations.
|
||||
* @param {LevelRole[]} roles - The roles to use for the calculations.
|
||||
* @param {number} experience - The experience to do the calculation for.
|
||||
*/
|
||||
|
||||
export function xpToRole(config: ExperienceConfig, roles: LevelRole[], experience: number) {
|
||||
return levelToRole(roles, xpToLevel(config, experience));
|
||||
export function xpToRole(config: LevelPluginConfig, experience: number) {
|
||||
return levelToRole(config, xpToLevel(config, experience));
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,10 +60,10 @@ export function xpToRole(config: ExperienceConfig, roles: LevelRole[], experienc
|
|||
* @param {number} level - The level to do the calculation for.
|
||||
*/
|
||||
|
||||
export function levelToRole(roles: LevelRole[], level: number) {
|
||||
export function levelToRole(config: LevelPluginConfig, level: number) {
|
||||
let roleID: string | undefined = undefined;
|
||||
for (let role of roles) {
|
||||
if (role.level <= level) roleID = role.id;
|
||||
for (let role of config.roles) {
|
||||
if (role.level <= level) roleID = role.role;
|
||||
else break;
|
||||
}
|
||||
return roleID;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { promises as fs } from 'fs';
|
||||
import * as Discord from 'discord.js';
|
||||
|
||||
import buildLevelImage from './BuildLevelImage';
|
||||
import { LevelPluginGuild, LevelPluginUser } from './LevelPlugin';
|
||||
|
||||
const MAX_XP = 1000000;
|
||||
|
||||
export default async function SetExperience(msg: Discord.Message, _: string, args: string[]) {
|
||||
export async function SetExperience(msg: Discord.Message, _: string, args: string[]) {
|
||||
let xp = Number.parseInt(args[0]);
|
||||
if (Number.isNaN(xp) || xp < 0 || xp > MAX_XP) return;
|
||||
|
||||
|
@ -16,3 +18,9 @@ export default async function SetExperience(msg: Discord.Message, _: string, arg
|
|||
user.experience = xp;
|
||||
await user.save();
|
||||
}
|
||||
|
||||
export async function UpImage(msg: Discord.Message) {
|
||||
let image = await buildLevelImage(msg.member!.displayName, 10, msg.author.id);
|
||||
await msg.channel.send('', { files: [ image ] });
|
||||
await fs.unlink(image);
|
||||
}
|
|
@ -1,32 +1,32 @@
|
|||
import * as Discord from 'discord.js';
|
||||
|
||||
import * as Calc from './Calc';
|
||||
import { LevelPluginGuild, LevelPluginUser, ExperienceConfig } from './LevelPlugin';
|
||||
import { LevelPluginGuild, LevelPluginUser, LevelPluginConfig } from './LevelPlugin';
|
||||
|
||||
export default class LevelCommand {
|
||||
constructor(private experience: ExperienceConfig) {}
|
||||
constructor(private config: LevelPluginConfig) {}
|
||||
|
||||
async trigger(msg: Discord.Message) {
|
||||
if (!msg.guild) return;
|
||||
const guild = await LevelPluginGuild.findOne({ id: msg.guild.id });
|
||||
if (!guild) return;
|
||||
|
||||
const users = (await LevelPluginUser.find({ guild_id: guild._id }).sort({ experience: 'desc' }).limit(12)).filter(u => u.id);
|
||||
const users = (await LevelPluginUser.find({ guild_id: guild._id }).sort({ experience: 'desc' }).limit(15)).filter(u => u.id);
|
||||
|
||||
const embed = new Discord.MessageEmbed()
|
||||
.setAuthor("Leaderboard", "https://i.imgur.com/LaPvO6n.png")
|
||||
.setColor("#FFAC38")
|
||||
.setAuthor('Leaderboard', 'https://i.imgur.com/LaPvO6n.png')
|
||||
.setColor('#FFAC38')
|
||||
.setDescription(`The most active members in ${msg.guild.name}.`)
|
||||
.setFooter(`Requested by ${msg.member!.displayName}`, msg.author.avatarURL({ size: 32 })!)
|
||||
.setFooter(`${msg.member!.displayName}`, msg.author.avatarURL({ size: 32 })!)
|
||||
.setTimestamp();
|
||||
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
try {
|
||||
let name = (await msg.guild.members.fetch(users[i].id)).displayName;
|
||||
if (name.length >= 20) name = name.substr(0, 18) + "...";
|
||||
const level = Calc.xpToLevel(this.experience, users[i].experience);
|
||||
if (name.length >= 20) name = name.substr(0, 18) + '...';
|
||||
const level = Calc.xpToLevel(this.config, users[i].experience);
|
||||
|
||||
embed.addField(`⠀${i + 1}) ${name}${i < 3 ? " :sparkles:" : ""}`,
|
||||
embed.addField(`⠀${i + 1}) ${name}${i < 3 ? ' :sparkles:' : ''}`,
|
||||
`⠀Level ${level} • ${Math.floor(users[i].experience)} XP`, true);
|
||||
}
|
||||
catch (e) { console.log(e); }
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import * as Discord from 'discord.js';
|
||||
|
||||
import * as Calc from './Calc';
|
||||
import { LevelPluginGuild, LevelPluginUser, ExperienceConfig, LevelRole } from './LevelPlugin';
|
||||
import { LevelPluginGuild, LevelPluginUser, LevelPluginConfig } from './LevelPlugin';
|
||||
|
||||
const PROGRESS_SEGMENTS = 15;
|
||||
const PROGRESS_FULL = "▇";
|
||||
const PROGRESS_EMPTY = "▁";
|
||||
const PROGRESS_FULL = '▇';
|
||||
const PROGRESS_EMPTY = '▁';
|
||||
|
||||
export default class LevelCommand {
|
||||
constructor(private experience: ExperienceConfig, private roles: LevelRole[]) {}
|
||||
constructor(private config: LevelPluginConfig) {}
|
||||
|
||||
async trigger(msg: Discord.Message) {
|
||||
if (!msg.guild) return;
|
||||
|
@ -16,27 +16,29 @@ export default class LevelCommand {
|
|||
if (!guild) return;
|
||||
const user = (await LevelPluginUser.findOne({ guild_id: guild._id, id: msg.author.id })) ?? { experience: 0, level: 0 };
|
||||
|
||||
const currentLevel = Calc.xpToLevel(this.experience, user.experience);
|
||||
const inLevel = Calc.xpInLevel(this.experience, currentLevel);
|
||||
const levelXp = user.experience - Calc.levelToXp(this.experience, currentLevel);
|
||||
const currentLevel = Calc.xpToLevel(this.config, user.experience);
|
||||
const inLevel = Calc.xpInLevel(this.config, currentLevel + 1);
|
||||
const levelXp = user.experience - Calc.levelToXp(this.config, currentLevel);
|
||||
|
||||
let progress = "「 ";
|
||||
let progress = '「 ';
|
||||
let amt = Math.floor(levelXp / inLevel * PROGRESS_SEGMENTS);
|
||||
for (let i = 0; i < amt; i++) progress += PROGRESS_FULL;
|
||||
for (let i = amt; i < PROGRESS_SEGMENTS; i++) progress += PROGRESS_EMPTY;
|
||||
progress += " 」";
|
||||
|
||||
const roleID = Calc.levelToRole(this.roles, currentLevel);
|
||||
const role = roleID ? (await msg.guild.roles.fetch(roleID))!.name : "Potato";
|
||||
progress += ' 」';
|
||||
const percentage = `${Math.round(levelXp)} / ${Math.round(inLevel)}`;
|
||||
let spaces = "";
|
||||
for (let i = 0; i < 14 - percentage.length * 0.75; i++) spaces += "⠀";
|
||||
const roleID = Calc.levelToRole(this.config, currentLevel);
|
||||
const role = roleID ? (await msg.guild.roles.fetch(roleID))!.name : 'Potato';
|
||||
|
||||
const embed = new Discord.MessageEmbed()
|
||||
.setAuthor(`${msg.member!.displayName}'s Level`, "https://i.imgur.com/Nqyb94h.png")
|
||||
.setColor("#15B5A6")
|
||||
.setAuthor(`${msg.member!.displayName}'s Level`, 'https://i.imgur.com/Nqyb94h.png')
|
||||
.setColor('#15B5A6')
|
||||
.setDescription('')
|
||||
.setFooter(`${msg.member!.displayName}`, msg.author.avatarURL({ size: 16 })!)
|
||||
.setTimestamp()
|
||||
|
||||
.addField(`⠀Level Progress⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀${Math.round(levelXp)} / ${Math.round(inLevel)}`, `${progress}`, false)
|
||||
.addField(`⠀Level Progress${spaces}${percentage}`, `${progress}`, false)
|
||||
.addField(`⠀${currentLevel}`, `⠀Level`, true)
|
||||
.addField(`⠀${Math.round(user.experience)}`, `⠀Experience`, true)
|
||||
.addField(`⠀${role}`, `⠀Role`, true);
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
import { promises as fs } from 'fs';
|
||||
import * as Mongoose from 'mongoose';
|
||||
import * as Discord from 'discord.js';
|
||||
|
||||
import * as Calc from './Calc';
|
||||
import { BotConfig } from '../../Bot';
|
||||
import { Command, CommandFn } from '../../Commands/Command';
|
||||
|
||||
import LevelCommand from './LevelCommand';
|
||||
import buildLevelImage from './BuildLevelImage';
|
||||
import LeaderboardCommand from './LeaderboardCommand';
|
||||
import SetExperienceCommand from './SetExperienceCommand';
|
||||
|
||||
// import { experienceInLevel } from './Calculate';
|
||||
|
||||
export interface ExperienceConfig {
|
||||
offset: number,
|
||||
base: number,
|
||||
multiplier: number
|
||||
a: number,
|
||||
b: number,
|
||||
c: number
|
||||
}
|
||||
|
||||
interface LevelPluginConfig {
|
||||
export interface Role {
|
||||
role: string;
|
||||
level: number;
|
||||
}
|
||||
|
||||
export interface LevelPluginConfig {
|
||||
please_and_thank_you: boolean;
|
||||
experience: ExperienceConfig,
|
||||
experience: ExperienceConfig;
|
||||
roles: Role[];
|
||||
message: {
|
||||
cooldown: number;
|
||||
min_length: number;
|
||||
}
|
||||
roles: {
|
||||
role: string,
|
||||
level: number
|
||||
}[]
|
||||
}
|
||||
|
||||
const levelPluginGuildSchema = new Mongoose.Schema({
|
||||
|
@ -43,7 +45,6 @@ const levelPluginUserSchema = new Mongoose.Schema({
|
|||
guild_id: String,
|
||||
id: String,
|
||||
|
||||
level: Number,
|
||||
experience: Number,
|
||||
totalMessages: Number,
|
||||
lastInteracted: Number
|
||||
|
@ -53,7 +54,6 @@ interface ILevelPluginUser extends Mongoose.Document {
|
|||
guild_id: ILevelPluginGuild['_id'];
|
||||
id: string;
|
||||
|
||||
level: number;
|
||||
experience: number;
|
||||
totalMessages: number;
|
||||
lastInteracted: number;
|
||||
|
@ -61,68 +61,50 @@ interface ILevelPluginUser extends Mongoose.Document {
|
|||
|
||||
export const LevelPluginUser = Mongoose.model<ILevelPluginUser>('LevelPluginUser', levelPluginUserSchema);
|
||||
|
||||
export interface LevelRole {
|
||||
id: string;
|
||||
level: number;
|
||||
totalExperience: number;
|
||||
}
|
||||
|
||||
export default class LevelPlugin {
|
||||
private roles: LevelRole[] = [];
|
||||
// storage: BotStorage;
|
||||
// imgBuilder: LevelImageBuilder;
|
||||
// checkVAInterval: any;
|
||||
|
||||
constructor(private config: BotConfig & { plugin: { level: LevelPluginConfig } },
|
||||
private client: Discord.Client, commands: { [command: string]: Command | CommandFn }) {
|
||||
|
||||
let experience = this.config.plugin.level.experience;
|
||||
|
||||
let lastLevel = 0;
|
||||
let totalExperience = experience.offset;
|
||||
this.config.plugin.level.roles.map(r => {
|
||||
for (let i = lastLevel; i < r.level; i++)
|
||||
totalExperience += experience.base * Math.sqrt(experience.multiplier * i);
|
||||
lastLevel = r.level;
|
||||
this.roles.push({ id: r.role, level: r.level, totalExperience });
|
||||
});
|
||||
|
||||
// let total_experience = 0;
|
||||
// Object.keys(this.config.plugin.level.levels).map(m => parseInt(m)).sort((a, b) => a - b).forEach(n => {
|
||||
// const role = this.config.plugin.level.levels[n.toString()];
|
||||
// total_experience += role.experience;
|
||||
// this.roles.push({ ...role, total_experience });
|
||||
// });
|
||||
|
||||
client.on('message', this.onMessage);
|
||||
commands.level = new LevelCommand(experience, this.roles);
|
||||
commands.leaderboard = new LeaderboardCommand(experience);
|
||||
commands.setxp = SetExperienceCommand;
|
||||
commands.level = new LevelCommand(config.plugin.level);
|
||||
commands.leaderboard = new LeaderboardCommand(config.plugin.level);
|
||||
|
||||
// this.checkVAInterval = setInterval(this.checkVoiceActivity.bind(this), 5*1000*60);
|
||||
// Loads all users from the classic LowDB.
|
||||
// (async () => {
|
||||
// await LevelPluginUser.deleteMany({});
|
||||
// let f = JSON.parse(fs.readFileSync('./data/db.json').toString());
|
||||
// await Promise.all(f.servers[0].users.map(async ({ id, totalXP, messages }: any) => {
|
||||
// const { _id: guild_id } = (await LevelPluginGuild.findOneAndUpdate({}))!;
|
||||
// await LevelPluginUser.create({
|
||||
// experience: totalXP,
|
||||
// totalMessages: messages,
|
||||
// guild_id: guild_id,
|
||||
// id: id,
|
||||
// });
|
||||
// }));
|
||||
// })();
|
||||
|
||||
// Refreshes all user roles.
|
||||
// (async () => {
|
||||
// this.client.guilds.cache.forEach(async guild => {
|
||||
// let members = await guild.members.fetch();
|
||||
// members.forEach(member => this.updateMember(member));
|
||||
// });
|
||||
// })()
|
||||
}
|
||||
|
||||
private onMessage = async (msg: Discord.Message) => {
|
||||
if (msg.author.bot) return;
|
||||
if (msg.content.substr(0, this.config.options.prefix.length + 1).toLowerCase() == this.config.options.prefix + ' ') return;
|
||||
|
||||
// Completely ignore messages that are less than N characters and without a space.
|
||||
if (msg.content.length < this.config.plugin.level.message.min_length || msg.content.split(' ').length - 1 < 1) return;
|
||||
|
||||
// Ignore DM conversations.
|
||||
if (!msg.guild) return;
|
||||
|
||||
const { _id: guild_id } = await LevelPluginGuild.findOneAndUpdate({ id: msg.guild.id },
|
||||
{ $setOnInsert: { id: msg.guild.id } },
|
||||
{ upsert: true, new: true });
|
||||
{ $setOnInsert: { id: msg.guild.id } }, { upsert: true, new: true });
|
||||
|
||||
const user = await LevelPluginUser.findOneAndUpdate({ id: msg.author.id, guild_id }, {
|
||||
$setOnInsert: {
|
||||
guild_id: guild_id,
|
||||
id: msg.author.id,
|
||||
experience: 0,
|
||||
level: 0,
|
||||
},
|
||||
$setOnInsert: { guild_id, id: msg.author.id, experience: 0 },
|
||||
$inc: { totalMessages: 1 }
|
||||
}, { upsert: true, new: true });
|
||||
|
||||
|
@ -132,9 +114,9 @@ export default class LevelPlugin {
|
|||
// Allow people to thank the dog... allow the dog to feel emotion.
|
||||
if (this.config.plugin.level.please_and_thank_you && msg.content.toLowerCase().startsWith('good')) {
|
||||
const lastMsg = (await msg.channel.messages.fetch({ limit: 2 })).last();
|
||||
if (lastMsg && lastMsg.author.id !== this.client.user!.id) {
|
||||
if (lastMsg && lastMsg.author.id === this.client.user!.id) {
|
||||
if (/good.(bo[i|y]|g[u|i]rl)/gi.test(msg.content.toLowerCase())) {
|
||||
msg.reply("I'm enby tho :(");
|
||||
msg.reply('I\'m enby tho :(');
|
||||
return;
|
||||
}
|
||||
else if (msg.content.toLowerCase().startsWith('good dog') &&
|
||||
|
@ -146,112 +128,38 @@ export default class LevelPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
// Completely ignore messages that are less than N characters and without a space.
|
||||
if (!thanked && (msg.content.length < this.config.plugin.level.message.min_length || msg.content.split(' ').length - 1 < 1)) return;
|
||||
|
||||
// Ignore messages that are too recent.
|
||||
if (!thanked && (Date.now() - user.lastInteracted < this.config.plugin.level.message.cooldown * 1000)) return;
|
||||
|
||||
await LevelPluginUser.findOneAndUpdate({ id: msg.author.id, guild_id }, {
|
||||
const newUser = (await LevelPluginUser.findOneAndUpdate({ id: msg.author.id, guild_id }, {
|
||||
$inc: { experience },
|
||||
$set: { lastInteracted: Date.now() }
|
||||
}, { new: true });
|
||||
}, { new: true }))!;
|
||||
|
||||
// for (let voice in guild.chatChannels) {
|
||||
// if (guild.chatChannels[voice] == msg.channel.id) {
|
||||
// xp /= 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// const cost = (this.storage.conf.xp_properties.level_base_cost + Math.pow(user.level, this.storage.conf.xp_properties.level_multiplier));
|
||||
|
||||
// if (user.levelXP >= cost) {
|
||||
// user.level++;
|
||||
// user.levelXP -= cost;
|
||||
|
||||
// this.imgBuilder.generate(msg.member.displayName, user.level, msg.author.id).then(image => {
|
||||
// msg.channel.send("", {file: image as any}).then(() => {
|
||||
// fs.unlinkSync(image);
|
||||
// });
|
||||
// });
|
||||
|
||||
// let currentRole = -1;
|
||||
// let previousRole = -1;
|
||||
|
||||
// const roles: BotLevelRoles = server.getLevelRolesTable();
|
||||
|
||||
// for (let role in roles) {
|
||||
// let num = parseInt(role);
|
||||
// if (num <= user.level && num > currentRole) currentRole = num;
|
||||
// if (num <= user.level - 1 && num > previousRole) previousRole = num;
|
||||
// }
|
||||
|
||||
// if (currentRole != previousRole) {
|
||||
// if (previousRole != -1) msg.member.removeRole(msg.guild.roles.find(r => r.id == roles[previousRole]));
|
||||
// if (currentRole != -1) msg.member.addRole(msg.guild.roles.find(r => r.id == roles[currentRole]), 'Update user level role.');
|
||||
// }
|
||||
// }
|
||||
// Award user if they cross a level boundary.
|
||||
if (Calc.xpToLevel(this.config.plugin.level, user.experience) !=
|
||||
Calc.xpToLevel(this.config.plugin.level, newUser.experience)) {
|
||||
let image = await buildLevelImage(msg.member!.displayName,
|
||||
Calc.xpToLevel(this.config.plugin.level, newUser.experience), msg.author.id);
|
||||
await msg.channel.send('', { files: [ image ] });
|
||||
await this.updateMember(msg.member!);
|
||||
await fs.unlink(image);
|
||||
}
|
||||
}
|
||||
|
||||
// checkVoiceActivity(): void {
|
||||
// for (let guildKey in this.storage.guildData) {
|
||||
// let guild = this.storage.guildData[guildKey];
|
||||
// for (let activeVoiceChannel in guild.chatChannels) {
|
||||
// let channel = guild.guild.channels.get(activeVoiceChannel) as Discord.VoiceChannel;
|
||||
// let undeafenedUsers: number = 0;
|
||||
|
||||
// channel.members.forEach((member, key) => {
|
||||
// if (!member.selfDeaf) undeafenedUsers++;
|
||||
// });
|
||||
|
||||
// if (undeafenedUsers >= 2) {
|
||||
// channel.members.forEach((member, key) => {
|
||||
// if (!member.selfDeaf && !member.selfMute) {
|
||||
|
||||
// let chatChannel = (guild.guild.channels.get(guild.chatChannels[activeVoiceChannel]) as Discord.TextChannel);
|
||||
|
||||
// let server: DBServer = this.storage.db.getServer(guild.guild);
|
||||
// let user: DBUser = server.getUser(member);
|
||||
|
||||
// let xp = Math.round(Math.random() + 0.3);
|
||||
|
||||
// user.levelXP += xp;
|
||||
// user.totalXP += xp;
|
||||
|
||||
// const cost = (this.storage.conf.xp_properties.level_base_cost + Math.pow(user.level, this.storage.conf.xp_properties.level_multiplier));
|
||||
|
||||
// if (user.levelXP >= cost) {
|
||||
// user.level++;
|
||||
// user.levelXP -= cost;
|
||||
|
||||
// if (chatChannel) {
|
||||
// this.imgBuilder.generate(member.displayName, user.level, member.id).then(image => {
|
||||
// chatChannel.send("", {file: image as any}).then(() => {
|
||||
// fs.unlinkSync(image);
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
// let currentRole = -1;
|
||||
// let previousRole = -1;
|
||||
|
||||
// const roles: BotLevelRoles = server.getLevelRolesTable();
|
||||
|
||||
// for (let role in roles) {
|
||||
// let num = parseInt(role);
|
||||
// if (num <= user.level && num > currentRole) currentRole = num;
|
||||
// if (num <= user.level - 1 && num > previousRole) previousRole = num;
|
||||
// }
|
||||
|
||||
// if (currentRole != previousRole) {
|
||||
// if (previousRole != -1) member.removeRole(member.guild.roles.find(r => r.id == roles[previousRole]));
|
||||
// if (currentRole != -1) member.addRole(member.guild.roles.find(r => r.id == roles[currentRole]), 'Update user level role.');
|
||||
// }
|
||||
// }
|
||||
|
||||
// server.pushUser(user);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
public async updateMember(member: Discord.GuildMember) {
|
||||
const user = (await LevelPluginUser.findOne({ id: member.id })) ?? { experience: 0 };
|
||||
let desiredRole = Calc.xpToRole(this.config.plugin.level, user.experience);
|
||||
this.config.plugin.level.roles.map(r => r.role).forEach(role => {
|
||||
if (member.roles.cache.has(role)) {
|
||||
if (role != desiredRole) member.roles.remove(role);
|
||||
}
|
||||
else {
|
||||
if (role == desiredRole) member.roles.add(role);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,13 @@ interface VoiceChatPluginConfig {
|
|||
export default class VoiceChatPlugin {
|
||||
private channels: { [guild: string]: { [voice_id: string]: string } } = {};
|
||||
|
||||
private description_prefix = "**Temporary discussion for ";
|
||||
private description_suffix = ".**"
|
||||
private channel_prefix = "";
|
||||
private channel_suffix = "-chat"
|
||||
private description_prefix = '**Temporary discussion for ';
|
||||
private description_suffix = '.**'
|
||||
private channel_prefix = '';
|
||||
private channel_suffix = '-chat'
|
||||
|
||||
constructor(config: BotConfig & { plugin: { voice_chat: VoiceChatPluginConfig } }, private client: Discord.Client) {
|
||||
client.on("voiceStateUpdate", this.onVoiceStateUpdate);
|
||||
client.on('voiceStateUpdate', this.onVoiceStateUpdate);
|
||||
|
||||
if (config.plugin?.voice_chat?.description?.prefix) this.description_prefix = config.plugin.voice_chat.description.prefix;
|
||||
if (config.plugin?.voice_chat?.description?.suffix) this.description_suffix = config.plugin.voice_chat.description.suffix;
|
||||
|
@ -31,12 +31,12 @@ export default class VoiceChatPlugin {
|
|||
|
||||
this.client.guilds.cache.forEach(guild => {
|
||||
guild.channels.cache.forEach(channel => {
|
||||
if (channel.type != "voice") return;
|
||||
if (channel.type != 'voice') return;
|
||||
if ((channel as Discord.VoiceChannel).members.size >= 1)
|
||||
this.createChatChannel(channel as Discord.VoiceChannel,
|
||||
(channel as Discord.VoiceChannel).members.entries().next().value[1]);
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
onVoiceStateUpdate = (oldState: Discord.VoiceState, newState: Discord.VoiceState) => {
|
||||
|
@ -59,7 +59,7 @@ export default class VoiceChatPlugin {
|
|||
}
|
||||
|
||||
createChatChannel(voice: Discord.VoiceChannel, member?: Discord.GuildMember) {
|
||||
let channelName = this.channel_prefix + voice.name.replace(/[\W_]+/g,"-").replace(/-+/g, "-") + this.channel_suffix;
|
||||
let channelName = this.channel_prefix + voice.name.replace(/[\W_]+/g,'-').replace(/-+/g, '-') + this.channel_suffix;
|
||||
voice.guild.channels.create(channelName, {
|
||||
type: `text`,
|
||||
parent: voice.parent ?? undefined,
|
||||
|
@ -69,8 +69,8 @@ export default class VoiceChatPlugin {
|
|||
this.channels[channel.guild.id][voice.id] = channel.id;
|
||||
channel.send({
|
||||
embed: new Discord.MessageEmbed()
|
||||
.setAuthor(channelName, "https://i.imgur.com/vitVUtr.png")
|
||||
.setColor("#EE86ED")
|
||||
.setAuthor(channelName, 'https://i.imgur.com/vitVUtr.png')
|
||||
.setColor('#EE86ED')
|
||||
.setDescription(
|
||||
`This is a temporary discussion channel for #${voice.name}!\n` +
|
||||
`This channel will be automatically deleted when everybody leaves the voice channel.\n`)
|
||||
|
|
Loading…
Reference in New Issue