willow-plugin-exp
Version:
A plugin for willow that allows users to collect exp, gain levels, and be assigned roles.
299 lines (298 loc) • 13.5 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
require("reflect-metadata");
const command_line_args_1 = __importDefault(require("command-line-args"));
const lodash_1 = __importDefault(require("lodash"));
const moment_1 = __importDefault(require("moment"));
const willow_models_1 = require("willow-models");
const typeorm_1 = require("typeorm");
exports.commandOptions = [
{ name: 'exp', alias: 'e', type: Boolean },
{ name: 'rank', alias: 'r', type: Boolean },
{ name: 'help', alias: 'h', type: Boolean }
];
var CommandType;
(function (CommandType) {
CommandType[CommandType["Quote"] = 0] = "Quote";
CommandType[CommandType["Random"] = 1] = "Random";
})(CommandType = exports.CommandType || (exports.CommandType = {}));
class PsyduckExampleOrm {
constructor(options, announceLevelUp = false, minExp = 1, maxExp = 10) {
this.connectionOptions = options;
this.announceLevelUp = announceLevelUp;
this.minExp = minExp;
this.maxExp = maxExp;
}
/**
* This method is to be called after instantiation to connect to the data store. This is intentional to allow for unit testing methods without requiring a connection.
*/
connect() {
typeorm_1.createConnection({
type: this.connectionOptions.type,
host: this.connectionOptions.host,
port: this.connectionOptions.port,
username: this.connectionOptions.username,
password: this.connectionOptions.password,
database: this.connectionOptions.database,
synchronize: true,
logging: false,
entities: [
willow_models_1.PluginExpUser, willow_models_1.UserLevel, willow_models_1.UserExp, willow_models_1.UserRank
]
}).then((connection) => __awaiter(this, void 0, void 0, function* () {
this.users = connection.getRepository(willow_models_1.PluginExpUser);
this.levels = connection.getRepository(willow_models_1.UserLevel);
this.ranks = connection.getRepository(willow_models_1.UserRank);
this.exps = connection.getRepository(willow_models_1.UserExp);
this.buildLevels();
})).catch(error => console.log(error));
}
buildLevels() {
return __awaiter(this, void 0, void 0, function* () {
const levels = yield this.levels.find();
if (!levels || levels.length < 1) {
for (let i = 0; i < 100; i++) {
const level = new willow_models_1.UserLevel();
level.level = i + 1;
level.requiredExp = (i + 1) * 1993 - 1185;
yield this.levels.save(level);
}
}
});
}
/**
* This event is emitted from Psyduck when a message is recieved in a discord channel. From there you may do as you with with it in your plugin.
*/
onMessage(message) {
// If the message came from a bot, ignore.
if (message.author.bot) {
return;
}
// If the message is too small to be a command, ignore.
if (message.content.length <= 1) {
this.gainExp(message, message.author.id, message.channel.name);
return;
}
// If the message is a string of repeated characters, ignore. For example !!!!!!!
const dupe = RegExp(/^(.)\1*$/gm);
if (dupe.test(message.content)) {
this.gainExp(message, message.author.id, message.channel.name);
return;
}
// Extract the command code, if it is in the list of commands we want to handle, continue.
if (message.content.startsWith('!')) {
const commandCodes = ['level', 'lvl', 'l'];
const baseCommand = message.content.slice(1);
const commandWithArgs = message.content.slice(1, message.content.indexOf(' '));
if (lodash_1.default.includes(commandCodes, baseCommand)) {
this.explainLevel(message, message.channel.name);
}
else if (lodash_1.default.includes(commandCodes, commandWithArgs)) {
}
}
else {
this.gainExp(message, message.author.id, message.channel.name);
}
}
getUser(userId) {
return __awaiter(this, void 0, void 0, function* () {
return yield this.users.findOne({
user: {
id: userId
}
}, { relations: ['exps', 'level'] });
});
}
createUser(guildId, serverName, guildAvatarUrl, userId, userName, avatarUrl) {
const user = new willow_models_1.PluginExpUser();
const guildUser = new willow_models_1.GuildUser();
guildUser.id = userId;
guildUser.userName = userName;
guildUser.avatarUrl = avatarUrl || '';
const guild = new willow_models_1.Guild();
guild.id = guildId;
guild.serverName = serverName;
guild.avatarUrl = guildAvatarUrl || '';
guildUser.guild = guild;
user.user = guildUser;
user.exps = [];
return user;
}
explainLevel(discord, channelName) {
return __awaiter(this, void 0, void 0, function* () {
let user = yield this.getUser(discord.author.id);
if (!user) {
user = this.createUser(discord.guild.id, discord.guild.name, discord.guild.iconURL, discord.author.id, discord.author.username, discord.author.avatarURL);
user.exps.push(this.buildExp(channelName));
yield this.users.save(user);
}
let users = yield this.users.find({ relations: ['level', 'exps'] });
users = lodash_1.default.orderBy(users, u => lodash_1.default.sum(u.exps.map(e => e.amount)), ['desc']);
let currentExp = 0;
user.exps.forEach(exp => currentExp += exp.amount);
const nextLevel = yield this.levels.findOne({ level: user.level ? user.level.level + 1 : 1 });
const userIndex = users.findIndex(u => u.user.id === user.user.id);
const nextPlaceUser = users[userIndex === 0 ? 0 : userIndex - 1];
let nextPlaceUserExp = 0;
let nextPlaceUserName = undefined;
if (nextPlaceUser) {
try {
const du = yield discord.guild.fetchMember(nextPlaceUser.user.id);
nextPlaceUserName = du.user.username;
}
catch (error) {
console.log(error);
}
nextPlaceUser.exps.forEach(exp => nextPlaceUserExp += exp.amount);
}
const embed = {
'color': 11812284,
'author': {
'name': '💯 Your Level Report'
},
'fields': [
{
'name': 'Overall Rank',
'value': `${userIndex + 1}/${users.length}`,
'inline': true
},
{
'name': 'Current Exp',
'value': `${currentExp}`,
'inline': true
},
{
'name': 'Current Level',
'value': `**${user.level ? user.level.level : 'None'}** (req. *${user.level ? user.level.requiredExp : 0} exp*)`,
'inline': true
},
{
'name': 'Next Level',
'value': `**${nextLevel ? nextLevel.level : 'none'}** (req. *${nextLevel ? nextLevel.requiredExp : 0} exp*)`,
'inline': true
},
{
'name': 'Exp To Next Level',
'value': `${nextLevel ? nextLevel.requiredExp - currentExp : 0}`,
'inline': true
},
{
'name': 'Exp To Overtake',
'value': `${nextPlaceUserExp - currentExp} (*${nextPlaceUserName || nextPlaceUser.user.id}*)`,
'inline': true
}
]
};
discord.channel.send({ embed });
});
}
buildExp(channel) {
const exp = new willow_models_1.UserExp();
exp.channel = channel;
exp.timeStamp = moment_1.default().format('ddd MMM DD YYYY h:mm A');
exp.amount = lodash_1.default.random(this.minExp, this.maxExp);
return exp;
}
gainExp(discord, userId, channel) {
return __awaiter(this, void 0, void 0, function* () {
let user = yield this.getUser(userId);
if (!user) {
user = this.createUser(discord.guild.id, discord.guild.name, discord.guild.iconURL, discord.author.id, discord.author.username, discord.author.avatarURL);
yield this.users.save(user);
}
user.exps.push(this.buildExp(channel));
yield this.users.save(user);
this.checkGainLevel(discord, user);
});
}
checkGainLevel(discord, user) {
return __awaiter(this, void 0, void 0, function* () {
let currentExp = 0;
let leveled = false;
user.exps.forEach(exp => currentExp += exp.amount);
const levels = yield this.levels.find({ requiredExp: typeorm_1.Between(1, currentExp) });
if (!user.level) {
leveled = true;
user.level = levels[0];
yield this.users.save(user);
}
else {
for (let i = 0; i < levels.length; i++) {
const level = levels[i];
if (level.id > user.level.id) {
leveled = true;
user.level = level;
yield this.users.save(user);
break;
}
}
}
yield this.users.save(user);
if (leveled) {
yield this.gainLevel(discord, user);
if (this.announceLevelUp) {
if (typeof (this.announceLevelUp) === 'boolean') {
discord.channel.send(`Level 🆙 <@${user.user.id}> - You are now level ${user.level.level}`);
}
else {
const channel = discord.guild.channels.find('id', this.announceLevelUp.announceChannel);
if (channel) {
channel.send(`Level 🆙 <@${user.user.id}> - You are now level ${user.level.level}`);
}
}
}
}
});
}
gainLevel(discord, user) {
return __awaiter(this, void 0, void 0, function* () {
const currentLevel = yield this.levels.findOne({ id: user.level.id }, { relations: ['ranks'] });
if (currentLevel) {
currentLevel.ranks.forEach(r => {
this.assignRole(discord, user.user.id, r.rankName);
});
}
});
}
assignRole(discord, userId, roleName) {
return __awaiter(this, void 0, void 0, function* () {
try {
const serverRole = discord.guild.roles.find('name', roleName);
if (serverRole) {
const guildUser = yield discord.guild.fetchMember(userId);
if (guildUser && !guildUser.roles.get(serverRole.id)) {
guildUser.addRole(serverRole);
}
}
}
catch (error) {
}
});
}
parseParameters(messageContent) {
const params = messageContent.match(/ (?=\S)[^'\s]*(?:'[^\\']*(?:\\[\s\S][^\\']*)*'[^'\s]*)*/g) || [];
return params.map(p => p.trim());
}
hydrateOptions(parameters) {
return command_line_args_1.default(exports.commandOptions, { argv: parameters, partial: true });
}
extractUserId(userId) {
const matches = userId.match(/(?<=@|!)(.*)(?=>)/gm);
if (matches && matches.length === 1) {
return matches[0].replace('!', '');
}
return undefined;
}
}
exports.default = PsyduckExampleOrm;