From 178286c1899224d92b4595e8667b0959a1f11c3f Mon Sep 17 00:00:00 2001 From: toast-ts <96593068+toast-ts@users.noreply.github.com> Date: Wed, 16 Nov 2022 01:06:18 +1100 Subject: [PATCH] i think i done enough for now. (Push part 5) --- .gitignore | 1 - README.md | 2 +- src/client.ts | 316 ++++++++++---------------------- src/config.json | 4 +- src/database/MPPlayerData.json | 2 +- src/database/bonkCount.json | 29 ++- src/database/dailyMsgs.json | 2 +- src/database/userLevels.json | 304 ++++++++++++++++++------------ src/events/guildMemberAdd.ts | 35 ++++ src/events/guildMemberRemove.ts | 17 ++ src/events/guildMemberUpdate.ts | 32 ++++ src/events/interactionCreate.ts | 23 +++ src/events/inviteCreate.ts | 10 + src/events/inviteDelete.ts | 8 + src/events/messageCreate.ts | 32 +--- src/events/messageDelete.ts | 16 ++ src/events/messageDeleteBulk.ts | 15 ++ src/events/messageUpdate.ts | 18 ++ src/index.ts | 143 ++++----------- src/typings/interfaces.d.ts | 31 ++++ 20 files changed, 559 insertions(+), 481 deletions(-) create mode 100644 src/events/guildMemberAdd.ts create mode 100644 src/events/guildMemberRemove.ts create mode 100644 src/events/guildMemberUpdate.ts create mode 100644 src/events/interactionCreate.ts create mode 100644 src/events/inviteCreate.ts create mode 100644 src/events/inviteDelete.ts create mode 100644 src/events/messageDelete.ts create mode 100644 src/events/messageDeleteBulk.ts create mode 100644 src/events/messageUpdate.ts create mode 100644 src/typings/interfaces.d.ts diff --git a/.gitignore b/.gitignore index 5935a81..244a16c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,5 @@ package-lock.json .ncurc.json # TypeScript stuff dist/ -typings/ # Bot stuff database/MPDB.dat \ No newline at end of file diff --git a/README.md b/README.md index 0a26c8b..766b0be 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Daggerbot-TS -Original JavaScript Daggerbot from [here](https://github.com/SpaceManBuzz/DaggerBot-) converted to TypeScript. +TypeScript-based Daggerbot converted from JavaScript at [SpaceManBuzz/DaggerBot-](https://github.com/SpaceManBuzz/DaggerBot-) ### Todo list: - [ ] Development diff --git a/src/client.ts b/src/client.ts index 4e3ef2f..c285147 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,46 +1,3 @@ -interface createTableOpt { - columnAlign: any, - columnSeparator: any, - columnEmptyChar: any -} -interface formatTimeOpt { - longNames: boolean, - commas: boolean -} -interface CommandInfoOpt { - insertNewline: boolean, - parts: string[], //idfk - titles: string[] -} -interface punOpt { - time?: string, - reason?: string; - interaction?: any -} -interface Punishment { - id: number; - type: string; - member: string; - moderator: string; - expired?: boolean; - time?: number; - reason: string; - endTime?: number; - cancels?: number; - duration?: number; -} -interface punData { - id: number; - type: string; - member: string; - moderator: string; - expired?: boolean; - time?: number; - reason: string; - endTime?: number; - cancels?: number; - duration?: number; -} import Discord, { Client, GatewayIntentBits, Partials } from 'discord.js'; import fs from 'node:fs'; import { Database } from './database'; @@ -51,9 +8,6 @@ export class TClient extends Client { registry: Array; config: any; tokens: any; - categoryNames: any; - commandPages: any; - helpDefaultOptions: any; YTCache: any; embed: typeof Discord.EmbedBuilder; collection: any; @@ -62,6 +16,7 @@ export class TClient extends Client { moment: any; xjs: any; axios: any; + ms: any; memberCount_LastGuildFetchTimestamp: any; userLevels: userLevels; punishments: punishments; @@ -89,12 +44,6 @@ export class TClient extends Client { this.registry = []; this.config = require('./config.json'); this.tokens = require('./tokens.json'); - this.categoryNames; - this.commandPages = []; - this.helpDefaultOptions = { - parts: ['name', 'usage', 'shortDescription', 'alias'], - titles: ['alias'] - } this.YTCache = { 'UCQ8k8yTDLITldfWYKDs3xFg': undefined, // Daggerwin 'UCguI73--UraJpso4NizXNzA': undefined // Machinery Restorer @@ -106,11 +55,12 @@ export class TClient extends Client { this.moment = import('moment'); this.xjs = import('xml-js'); this.axios = import('axios'); + this.ms = import('ms'); this.memberCount_LastGuildFetchTimestamp = 0; - this.userLevels(this); - this.bonkCount(this); - this.punishments(this); - this.bannedWords(this); + this.userLevels = new userLevels(this); + this.bonkCount = new bonkCount(this); + this.punishments = new punishments(this); + this.bannedWords = new bannedWords(this); this.repeatedMessages = {}; this.setMaxListeners(80) } @@ -127,65 +77,6 @@ export class TClient extends Client { this.registry.push(command.data.toJSON()) } } - commandInfo(client: TClient, command: any, options?: CommandInfoOpt){ - let text = ':small_orange_diamond: '; - if (!options.titles) options.titles = []; - function e(){ - text += '\n'; - if (options.insertNewline){ - text += '\n'; - } return; - } - if (options.parts.includes('name') && command.name){ - if (options.titles.includes('name') && options.titles.includes('usage')){ - text += 'Name & Usage: '; - } else if (options.titles.includes('name')){ - text += 'Name: '; - } - text += '`' + client.config.prefix + command.name; - if (options.parts.includes('usage') && command.usage){ - text += ' ' + command.usage.map((x:string)=>x.startsWith('?') ? '?['+x.slice(1)+']' : '['+x+']').join(' '); - } - text += '`'; - e(); - } else if (options.parts.includes('usage') && command.usage){ - if (options.titles.includes('usage')) text += 'Usage: '; - text += '`'+command.usage.map((x:string)=>x.startsWith('?') ? '?['+x+']' : '['+x+']').join(' ') + '`'; - e(); - } - if (options.parts.includes('description') && command.description){ - if (options.titles.includes('description')) text += 'Description: '; - text += command.description; - e(); - } - if (options.parts.includes('shortDescription')){ - if (command.shortDescription){ - if (options.titles.includes('shortDescription')) text += 'Shorter description: '; - text += command.shortDescription; - e(); - } else if (!options.titles.includes('shortDescription') && command.description){ - text += command.description; - e(); - } - } - if (options.parts.includes('alias') && command.alias){ - if (options.titles.includes('alias')) text += 'Aliases: '; - text += command.alias.map((x:any)=>'`'+x+'`').join(', '); - e(); - } - if (options.parts.includes('category') && command.category){ - if (options.titles.includes('category')) text += 'Category: '; - text += command.category; - e(); - } - if (options.parts.includes('autores') && command.autores){ - if (options.titles.includes('autores')) text += 'AutoResponse:tm: Requirements: '; - text += '`['+command.autores.join('] [')+']`'; - e(); - } - e(); - return text; - } formatPunishmentType(punishment: Punishment, client: TClient, cancels: Punishment){ if (punishment.type == 'removeOtherPunishment'){ cancels ||= this.punishments._content.find((x: Punishment)=>x.id === punishment.cancels) @@ -194,7 +85,7 @@ export class TClient extends Client { } formatTime(integer: number, accuracy = 1, options?: formatTimeOpt){ let achievedAccuracy = 0; - let text = ''; + let text:any = ''; const { longNames, commas } = options for (const timeName of timeNames){ if (achievedAccuracy < accuracy){ @@ -220,6 +111,9 @@ export class TClient extends Client { isStaff(guildMember: Discord.GuildMember){ return this.config.mainServer.staffRoles.map((x: string)=>this.config.mainServer.roles[x]).some((x: string)=>guildMember.roles.cache.has(x)) } + youNeedRole(interaction: Discord.CommandInteraction, role:string){ + return interaction.reply(`This command is restricted to <@&${this.config.mainServer.roles[role]}>`) + } alignText(text: string, length: number, alignment: string, emptyChar = ' '){ if (alignment == 'right'){ text = emptyChar.repeat(length - text.length)+text; @@ -272,7 +166,7 @@ export class TClient extends Client { {name: '🔹 User', value: `<@${data.member}> \`${data.member}\``, inline: true}, {name: '🔹 Moderator', value: `<@${data.moderator}> \`${data.moderator}\``, inline: true}, {name: '\u200b', value: `\u200b`, inline: true}, - {name: '🔹 Reason', value: `\`${data.reason || 'Unspecified'}\``, inline: true}, + {name: '🔹 Reason', value: `\`${data.reason || 'Reason unspecified'}\``, inline: true}, ) if (data.duration) { embed.addFields( @@ -280,106 +174,39 @@ export class TClient extends Client { {name: '\u200b', value: '\u200b', inline: true} ) } - if (data.cancels) embed.addFields({name: '🔹 Overwrites', value: `This case overwrites Case #${cancels.id} \`${cancels.reason}\``}) + if (data.cancels) embed.addFields({name: '🔹 Overwrites', value: `This case overwrites Case #${cancels.id} \`${cancels.reason}\``}); // send embed to log channel (client.channels.cache.get(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [embed]}) } - async punish(client: TClient, message: Discord.Message, args: string, type: string){ - let member: any; - if (message.guildId !== client.config.mainServer.id) return message.channel.send('This command doesn\'t work in this server'); - if (!message.member.roles.cache.has(client.config.mainServer.roles.dcmod)) return message.reply(`You need the <@&${client.config.mainServer.roles.dcmod}> role to use this command.`) - if (type == 'ban' && args[1]){ - member = message.mentions.users?.first() || (await client.users.fetch(args[1]).catch(()=>undefined)); - } else if (args[1]){ - member = message.mentions.members?.first() || (await message.guild.members.fetch(args[1]).catch(()=>undefined)); - } - let memberAsked = false; - if (!member){ - memberAsked = true; - await message.channel.send(`Which member would you like to ${type}?\nSend another message with a mention or a user ID. (30s)`).then(async (x:any)=>{ - const filter = m=>m.author.id == message.author.id; - member = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(async (z:any)=>{ - if (z.first().content.startsWith(client.config.prefix)) return 'timedout'; - if (type == 'ban'){ - return z.first().mentions.users?.first() || (await client.users.fetch(z.first().content).catch(()=>undefined)); - } else { - return z.first().mentions.members?.first() || (await message.guild.members.fetch(z.first().content).catch(()=>undefined)) - } - }).catch(async()=>{ - message.channel.send('Command cancelled after 30 seconds of inactivity.'); - return 'timedout'; - }); - }) - } - if (member === 'timedout') return; - else if (!member) return message.channel.send('You failed to mention a member.'); - let time; - let reason; - let col1; // idfk if this should be included here but just wanted to get rid of red underline. + + async punish(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>, type: string){ let result: any; - if (args[2] && !memberAsked){ - // if the first character of args 2 is a number, args 2 is the time. otherwise its the reason. - time = (args[2][0].match(/[0-9]/) && !['softban', 'kick', 'warn'].includes(type)) ? args[2] : undefined; - // if time is in args 2, reason starts at args 3. if no time was provided, reason starts at args 2 - reason = args.slice(time ? 3 : 2).join(' '); // "Property 'join' does not exist on type 'string'." :linus: x99 + if (!client.isStaff(interaction.member as Discord.GuildMember)) return this.youNeedRole(interaction, 'dcmod') + //if (type !== ('warn' || 'mute') && (interaction.member as Discord.GuildMember).roles.cache.has(client.config.mainServer.roles.idk)) return this.youNeedRole(interaction, 'dcmod'); + const time = this.ms(interaction.options.getString('time')); + const reason = interaction.options.getString('reason') ?? 'Reason unspecified'; + if (type == 'ban'){ + const user = interaction.options.getUser('member') as Discord.User; + if (interaction.user.id == user.id) return interaction.reply(`You cannot ${type} yourself!`); + result = await this.punishments.addPunishment(type, user, {time,reason,interaction}, interaction.user.id); } else { - if (!['softban', 'kick', 'warn'].includes(type)){ - await message.channel.send(`How long do you want to ${type} this user for?\nSend another message with a time name, or 'forever' to ${type} this user forever. (30s)`); - const filter = m=>m.author.id === message.author.id; - col1 = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(collected=>{ - if (collected.first()?.content.startsWith(client.config.prefix)) return 'timedout'; - return collected.first()?.content.toLowerCase() === 'forever' ? 'inf' : collected.first()?.content; - }).catch(()=>{ - message.channel.send('Command cancelled after 30 seconds of inactivity.'); - return 'timedout'; - }); - if (time === 'timedout') return; - } - await message.channel.send(`Send another message with a reason for this ${type}.\nSend another message with "-" to leave the reason unspecified. (30s)`); - const filter = m=>m.author.id === message.author.id; - reason = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(collected=>{ - if (collected.first()?.content.startsWith(client.config)) return 0; - return collected.first()?.content == '-' ? undefined : collected.first()?.content; - }).catch(()=>{ - message.channel.send('Command cancelled after 30 seconds of inactivity.'); - return 0; - }) - if (reason === 0) return; + const member = interaction.options.getMember('member') as Discord.GuildMember; + if (interaction.user.id == member.id) return interaction.reply(`You cannot ${type} yourself!`); + if (this.isStaff(member)) return interaction.reply(`You cannot ${type} other staff!`); + result = await this.punishments.addPunishment(type, member, {time,reason,interaction}, interaction.user.id); } - const punishmentResult = await client.punishments.addPunishment(type, member, {time, reason}, message.author.id, message); - (typeof result == 'string' ? message.reply(punishmentResult) : message.reply({embeds: [punishmentResult]})) + (typeof result == 'string' ? interaction.reply({content: `${result}`}) : interaction.reply({embeds: [result]})) }; - async unPunish(client: TClient, message: Discord.Message, args: string){ - if (message.guildId !== client.config.mainServer.id) return message.channel.send('This command doesn\'t work in this server'); - if (!message.member.roles.cache.has(client.config.mainServer.roles.dcmod)) return message.reply(`You need the <@&${client.config.mainServer.roles.dcmod}> role to use this command.`) - let punishment; - if (args[1]) punishment = client.punishments._content.find((x:any)=>x.id == args[1]) - if (!punishment){ - await message.channel.send(`Which punishment would you like to remove?\nSend another message with a Case # (30s)`).then(async (x:any)=>{ - const filter = m=>m.author.id === message.author.id; - punishment = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(async (z:any)=>{ - return client.punishments._content.find((x:any)=>x.id == z.first()?.content); - }).catch(async()=>{ - message.channel.send('Command cancelled after 30 seconds of inactivity.'); - return 'timedout'; - }); - }) - } - if (punishment === 'timedout') return; - else if (!punishment) return message.channel.send('You failed to mention a Case #'); - //if (punishment.type !== 'warn' && message.member.roles.cache.has(client.config.mainServer.roles.trialmoderator)) return message.channel.send('Trial moderators can only remove warnings.'); - let reason; - if (args[2]){ - reason = args.slice(2).join(' '); // "Property 'join' does not exist on type 'string'." :linus: x50 - }else{ - await message.channel.send(`Send another message with a reason for this ${punishment.type} removal. (30s)\n*Send \`-\` to leave the reason unspecified.*`); - const filter = m=>m.author.id === message.author.id; - reason = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(collected=>collected.first()?.content === '-' ? undefined : collected.first()?.content).catch(()=>0); - if (reason === 0) return message.channel.send('Invalid reason.'); - } - const unpunishResult = await client.punishments.removePunishment(punishment.id, message.author.id, reason); - message.channel.send(unpunishResult); + async unPunish(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ + if (!client.isStaff(interaction.member as Discord.GuildMember)) return this.youNeedRole(interaction, 'dcmod'); + const punishment = this.punishments._content.find((x:Punishment)=>x.id === interaction.options.getInteger('case_id')); + if (!punishment) return interaction.reply({content: 'Invalid Case #', ephemeral: true}); + //if (type !== ('warn' || 'mute') && (interaction.member as Discord.GuildMember).roles.cache.has(client.config.mainServer.roles.idk)) return this.youNeedRole(interaction, 'dcmod'); + const reason = interaction.options.getString('reason') ?? 'Reason unspecified'; + const unpunishResult = await this.punishments.removePunishment(punishment.id, interaction.user.id, reason); + interaction.reply(unpunishResult) } + async YTLoop(YTChannelID: string, YTChannelName: string, DCChannelID: string){ const Data = this.xjs.xml2js((await this.axios.get(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelID}`, {timeout: 5000})), {compact: true, spaces: 2}).catch(()=>{return null}); if (!Data) return; @@ -410,13 +237,13 @@ class punishments extends Database { this.client = client; } createId(){ - return Math.max(...this.client.punishments._content.map((x:punData)=>x.id), 0)+1; + return Math.max(...this.client.punishments._content.map((x:Punishment)=>x.id), 0)+1; } async addPunishment(type: string, member: any, options: punOpt, moderator: string){ const now = Date.now(); const {time, reason, interaction}=options; const ms = require('ms'); - let timeInMillis; + let timeInMillis: number; if(type !== 'mute'){ timeInMillis = time ? ms(time) : null; } else { @@ -424,15 +251,40 @@ class punishments extends Database { } switch (type) { case 'ban': - const banData: punData={type, id: this.createId(), member: member.id, moderator, time: now}; - const dm1: Discord.Message = await member.send(`You've been banned from ${interaction.guild.name} ${timeInMillis ? `for ${this.client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Unspecified'}\` (Case #${banData.id})`).catch(()=>{return interaction.channel.send('Failed to DM user.')}) - const banResult = await interaction.guild.bans.create(member.id, {reason: `${reason || 'Unspecified'} | Case #${banData.id}`}).catch((err:Error)=>err.message); + const banData: Punishment={type, id: this.createId(), member: member.id, moderator, time: now}; + const dm1: Discord.Message = await member.send(`You've been banned from ${interaction.guild.name} ${timeInMillis ? `for ${this.client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Reason unspecified'}\` (Case #${banData.id})`).catch(()=>{return interaction.channel.send('Failed to DM user.')}) + const banResult = await interaction.guild.bans.create(member.id, {reason: `${reason || 'Reason unspecified'} | Case #${banData.id}`}).catch((err:Error)=>err.message); + if (typeof banResult === 'string'){ + dm1.delete() + return `Ban was unsuccessful: ${banResult}` + } else { + if (timeInMillis){ + banData.endTime = now + timeInMillis; + banData.duration = timeInMillis + } + if (reason) banData.reason = reason; + this.client.makeModlogEntry(banData, this.client); + this.addData(banData).forceSave(); + return new this.client.embed().setColor(this.client.config.embedColor).setTitle(`Case #${banData.id}: Ban`).setDescription(`${member?.user?.tag ?? member?.tag}\n<@${member.id}>\n(\`${member.id}\`)`).addFields( + {name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``}, + {name: 'Duration', value: `${timeInMillis ? `for ${this.client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'}`} + ) + } case 'softban': + const guild = member.guild; + const softbanData: Punishment={type, id: this.createId(), member: member.user.id, moderator, time: now}; + const dm2 = Discord.Message = await member.send(`You've been softbanned from ${member.guild.name} ${timeInMillis ? `for ${this.client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Reason unspecified'}\` (Case #${softbanData.id})`).catch(()=>{return interaction.channel.send('Failed to DM user.')}) + const softbanResult = await member.ban({deleteMessageDays: 3, reason: `${reason || 'Reason unspecified'} | Case #${softbanData.id}`}).catch((err:Error)=>err.message); + if (typeof softbanResult === 'string') { + dm2.delete(); + return `Softban was unsuccessful: ${softbanResult}`; + } case 'kick': case 'warn': case 'mute': } } + async removePunishment(caseId:number, moderator:any, reason:string):Promise{} } class userLevels extends Database { client: TClient; @@ -441,24 +293,44 @@ class userLevels extends Database { this.client = client } incrementUser(userid: string){ - const data = this._content[userid]; + const data = this._content[userid];// User's data. Integer for old format, object for new format. - if (data) { - this._content[userid].messages++; - if (data.messages >= this.algorithm(data.level+2)){ + if (typeof data == 'number'){// If user's data is an integer, convert it into object for new format. + this._content[userid] = {messages: data, level: 0}; + } + + if (data) {// If user exists on file... + this._content[userid].messages++;// Increment their message count + if (data.messages >= this.algorithm(data.level+2)){// Quietly level up users who can surpass more than 2 levels at once, usually due to manually updating their message count while (data.messages > this.algorithm(data.level+1)){ this._content[userid].level++; console.log(`${userid} EXTENDED LEVELUP ${this._content[userid].level}`) } - } else if (data.messages >= this.algorithm(data.level+1)){ - this._content[userid].level++; + } else if (data.messages >= this.algorithm(data.level+1)){// If user's message count meets/exceeds message requirement for next level... + this._content[userid].level++;// Level them up. (this.client.channels.resolve(this.client.config.mainServer.channels.thismeanswar) as Discord.TextChannel).send({content: `<@${userid}> has reached level **${data.level}**. GG!`}) } - } else { + } else {// If user doesn't exist on file, create an object for it. this._content[userid] = {messages: 1, level: 0}; } } - algorithm(level: number){ + algorithm(level: number){// Algorithm for determining levels. If adjusting, recommended to only change the integer at the end of equation. return level*level*15; } +} +class bonkCount extends Database { + client: TClient; + constructor(client: TClient){ + super('./database/bonkCount.json', 'object') + this.client = client + } + _incrementUser(userid: string){ + const amount = this._content[userid]; + if(amount) this._content[userid]++; + else this._content[userid] = 1; + return this; + } + getUser(userid: string){ + return this._content[userid] || 0; + } } \ No newline at end of file diff --git a/src/config.json b/src/config.json index 634d071..4ddc340 100644 --- a/src/config.json +++ b/src/config.json @@ -1,5 +1,4 @@ { - "prefix": ".", "embedColor": "#0052cf", "embedColorGreen": "#57f287", "embedColorYellow": "#ffea00", @@ -11,7 +10,8 @@ "commands": false, "logs": false, "automod": false, - "mpstats": false + "mpstats": false, + "autores": false }, "eval": { "allowed": true, diff --git a/src/database/MPPlayerData.json b/src/database/MPPlayerData.json index fb6b921..a31ec96 100644 --- a/src/database/MPPlayerData.json +++ b/src/database/MPPlayerData.json @@ -1 +1 @@ -[1,2,3,4,5,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,4,4,3,3,4,5,4,4,4,4,4,4,4,4,3,3,3,3,4,4,4,4,4,4,4,4,4,4,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,3,3,3,3,4,4,5,5,5,5,5,5,5,5,5,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,0,0,0,2,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,5,5,5,5,6,6,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,6,6,5,5,5,5,5,5,7,6,6,7,7,7,7,7,8,7,8,8,8,8,8,8,8,9,9,9,9,9,10,9,9,9,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,6,6,6,6,6,6,6,6,5,5,4,3,3,3,3,0,0,0,0,0,0,0,0,0,0,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,1,1,1,2,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,4,4,3,3,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,3,4,4,4,4,4,4,4,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,4,4,4,4,4,4,4,4,4,4,3,3,3,3,4,3,3,3,3,3,3,3,3,3,3,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,4,5,5,5,5,5,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,5,5,5,5,5,4,4,4,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,2,2,2,2,2,2,2,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,2,2,1,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,5,5,5,5,4,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,4,4,4,4,5,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,7,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7] \ No newline at end of file +[1,2,3,4,5,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,4,4,3,3,4,5,4,4,4,4,4,4,4,4,3,3,3,3,4,4,4,4,4,4,4,4,4,4,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,3,3,3,3,4,4,5,5,5,5,5,5,5,5,5,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,0,0,0,2,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,5,5,5,5,6,6,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,6,6,5,5,5,5,5,5,7,6,6,7,7,7,7,7,8,7,8,8,8,8,8,8,8,9,9,9,9,9,10,9,9,9,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,6,6,6,6,6,6,6,6,5,5,4,3,3,3,3,0,0,0,0,0,0,0,0,0,0,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,1,1,1,2,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,4,4,3,3,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,3,4,4,4,4,4,4,4,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,4,4,4,4,4,4,4,4,4,4,3,3,3,3,4,3,3,3,3,3,3,3,3,3,3,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,4,5,5,5,5,5,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,5,5,5,5,5,4,4,4,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,2,2,2,2,2,2,2,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,2,2,1,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,5,5,5,5,4,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,4,4,4,4,5,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,7,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,9,9,9,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,9,10,11,11,11,11,11,11,11,11,12,12,12,12,13,13,13,13,13,11,11,11,11,11,11,12,12,12,12,11,11,11,11,11,10,11,11,11,10,11,11,11,11,11,12,12,12,12,12,12,12,12,11,11,11,10,10,9,9,9,8,8,8,8,8,8,9,9,9,9,9,9,8,8,8,8,8,8,8,7,7,7,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,5,5,4,4,5,5,3,4,4,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,4,4,4,4,3,3,4,4,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,3,2,3,3,4,4,3,3,3,3,3,3,3,3,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,3,3,3,3,4,4,4,4,3,3,3,3,4,4,3,4,4,4,3,3,3,4,3,3,3,3,3,3,3,3,4,4,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,2,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2] \ No newline at end of file diff --git a/src/database/bonkCount.json b/src/database/bonkCount.json index 57c7d84..ab13613 100644 --- a/src/database/bonkCount.json +++ b/src/database/bonkCount.json @@ -1 +1,28 @@ -{"696085982201643090":3,"532662366354276352":2849,"178941218510602240":9,"615761944154210305":7,"141304507249197057":14,"190407856527376384":7,"711527768185372742":1,"716355511552966737":5,"593696856165449749":14,"824043915539513406":20,"771892617599516674":10,"889665445915926588":1,"488683638310043677":1027,"475037861725339649":1,"389237487094071337":1,"859313171964887140":1,"301350210926280704":2,"695323013813633076":2,"458688902102908928":2,"606595407769894995":1,"734703851558535188":2,"544215307972247553":2,"506022868157595648":1,"468837263577579524":3,"743212818467258468":1,"954092707213619221":1} \ No newline at end of file +{ + "696085982201643090": 3, + "532662366354276352": 2849, + "178941218510602240": 9, + "615761944154210305": 8, + "141304507249197057": 14, + "190407856527376384": 7, + "711527768185372742": 1, + "716355511552966737": 5, + "593696856165449749": 14, + "824043915539513406": 20, + "771892617599516674": 10, + "889665445915926588": 1, + "488683638310043677": 1027, + "475037861725339649": 1, + "389237487094071337": 1, + "859313171964887140": 1, + "301350210926280704": 2, + "695323013813633076": 2, + "458688902102908928": 2, + "606595407769894995": 1, + "734703851558535188": 2, + "544215307972247553": 2, + "506022868157595648": 1, + "468837263577579524": 3, + "743212818467258468": 1, + "954092707213619221": 1 +} \ No newline at end of file diff --git a/src/database/dailyMsgs.json b/src/database/dailyMsgs.json index 120c04a..99b5da8 100644 --- a/src/database/dailyMsgs.json +++ b/src/database/dailyMsgs.json @@ -1 +1 @@ -[[0,674965],[1,675885],[2,676639],[3,677245],[4,677609],[5,678188],[6,678916],[7,679465],[8,679938],[9,680540],[10,681614],[11,682079],[12,682780],[13,683187],[14,683547],[15,683900],[16,684592],[17,685466],[18,686078],[19,686481],[20,676748],[21,676968],[22,677427],[23,677592],[24,677894],[25,678116],[26,676785],[27,677570],[28,678491],[29,679137],[30,679818],[31,680094],[32,680417],[33,680783],[34,681563],[35,682070],[36,682670],[37,683504],[38,684078],[39,684383],[40,684692],[41,685448],[42,685664],[43,685994],[44,686366],[45,687118],[46,687626],[47,688008],[48,688754],[49,688942],[50,689107],[51,689472],[52,690143],[53,690644],[54,691124],[55,692196],[56,692624],[57,692906],[58,693456],[59,693952],[60,694586],[61,695070],[62,696163],[63,696564],[64,697315],[65,698548],[66,699138],[67,699558],[68,700307],[69,701063],[70,701394],[71,701868],[72,702453],[73,702917],[76,705187],[77,705243],[78,705488],[79,705961],[80,706585],[81,707467],[82,708212]] \ No newline at end of file +[[0,674965],[1,675885],[2,676639],[3,677245],[4,677609],[5,678188],[6,678916],[7,679465],[8,679938],[9,680540],[10,681614],[11,682079],[12,682780],[13,683187],[14,683547],[15,683900],[16,684592],[17,685466],[18,686078],[19,686481],[20,676748],[21,676968],[22,677427],[23,677592],[24,677894],[25,678116],[26,676785],[27,677570],[28,678491],[29,679137],[30,679818],[31,680094],[32,680417],[33,680783],[34,681563],[35,682070],[36,682670],[37,683504],[38,684078],[39,684383],[40,684692],[41,685448],[42,685664],[43,685994],[44,686366],[45,687118],[46,687626],[47,688008],[48,688754],[49,688942],[50,689107],[51,689472],[52,690143],[53,690644],[54,691124],[55,692196],[56,692624],[57,692906],[58,693456],[59,693952],[60,694586],[61,695070],[62,696163],[63,696564],[64,697315],[65,698548],[66,699138],[67,699558],[68,700307],[69,701063],[70,701394],[71,701868],[72,702453],[73,702917],[76,705187],[77,705243],[78,705488],[79,705961],[80,706585],[81,707467],[82,708212],[83,709024],[84,709773]] \ No newline at end of file diff --git a/src/database/userLevels.json b/src/database/userLevels.json index 70fa847..1a5b45a 100644 --- a/src/database/userLevels.json +++ b/src/database/userLevels.json @@ -1,54 +1,54 @@ { "190407856527376384": { - "messages": 52904, + "messages": 52961, "level": 59 }, "593696856165449749": { - "messages": 51257, + "messages": 51388, "level": 58 }, "141304507249197057": { - "messages": 67482, + "messages": 67550, "level": 67 }, "533707949831487488": { - "messages": 56765, + "messages": 56984, "level": 61 }, "532662366354276352": { - "messages": 33505, + "messages": 33675, "level": 47 }, "824043915539513406": { - "messages": 18398, + "messages": 18434, "level": 35 }, "178941218510602240": { - "messages": 6368, + "messages": 6372, "level": 20 }, "215497515934416896": { - "messages": 33121, + "messages": 33124, "level": 46 }, "301350210926280704": { - "messages": 14272, + "messages": 14306, "level": 30 }, "695323013813633076": { - "messages": 14063, + "messages": 14072, "level": 30 }, "389237487094071337": { - "messages": 12223, + "messages": 12240, "level": 28 }, "716355511552966737": { - "messages": 9115, + "messages": 9122, "level": 24 }, "633345781780185099": { - "messages": 29362, + "messages": 29364, "level": 44 }, "711527768185372742": { @@ -64,23 +64,23 @@ "level": 18 }, "458688902102908928": { - "messages": 6181, + "messages": 6190, "level": 20 }, "475037861725339649": { - "messages": 10096, - "level": 25 + "messages": 10192, + "level": 26 }, "392699530912727041": { - "messages": 4925, + "messages": 4928, "level": 18 }, "468837263577579524": { - "messages": 7565, + "messages": 7631, "level": 22 }, "734703851558535188": { - "messages": 20183, + "messages": 20200, "level": 36 }, "488683638310043677": { @@ -92,11 +92,11 @@ "level": 39 }, "322835877027905547": { - "messages": 9999, + "messages": 10018, "level": 25 }, "485793265568841728": { - "messages": 37876, + "messages": 37880, "level": 50 }, "837979120142778388": { @@ -108,11 +108,11 @@ "level": 0 }, "257954059988893720": { - "messages": 5391, - "level": 0 + "messages": 5392, + "level": 18 }, "690090143008555064": { - "messages": 9973, + "messages": 9974, "level": 25 }, "849633082440941628": { @@ -124,7 +124,7 @@ "level": 0 }, "452576735494406175": { - "messages": 1675, + "messages": 1676, "level": 10 }, "763055599654666291": { @@ -136,7 +136,7 @@ "level": 0 }, "366896479098372096": { - "messages": 2956, + "messages": 2958, "level": 14 }, "445940328634253323": { @@ -148,7 +148,7 @@ "level": 0 }, "169891949464125441": { - "messages": 516, + "messages": 518, "level": 5 }, "718453763932946432": { @@ -156,15 +156,15 @@ "level": 30 }, "472809522226790420": { - "messages": 2773, + "messages": 2776, "level": 13 }, "763803832542035978": { - "messages": 678, + "messages": 679, "level": 6 }, "931816463113814066": { - "messages": 672, + "messages": 673, "level": 6 }, "958108557503524904": { @@ -172,7 +172,7 @@ "level": 0 }, "771892617599516674": { - "messages": 621, + "messages": 626, "level": 6 }, "468437000232501269": { @@ -188,11 +188,11 @@ "level": 0 }, "309373272594579456": { - "messages": 3582, + "messages": 3585, "level": 15 }, "399625244588900362": { - "messages": 21298, + "messages": 21300, "level": 37 }, "889665445915926588": { @@ -200,8 +200,8 @@ "level": 0 }, "615761944154210305": { - "messages": 2924, - "level": 13 + "messages": 2997, + "level": 14 }, "397101726047666197": { "messages": 5553, @@ -216,7 +216,7 @@ "level": 0 }, "820029314103246860": { - "messages": 19, + "messages": 20, "level": 1 }, "831633702492307473": { @@ -228,7 +228,7 @@ "level": 2 }, "645342896312156181": { - "messages": 662, + "messages": 679, "level": 6 }, "488505753133645826": { @@ -236,7 +236,7 @@ "level": 0 }, "313461397457600512": { - "messages": 77, + "messages": 78, "level": 2 }, "848489550065827850": { @@ -244,7 +244,7 @@ "level": 1 }, "862138850423472128": { - "messages": 51, + "messages": 52, "level": 1 }, "700053257996992573": { @@ -264,7 +264,7 @@ "level": 0 }, "617353338324779008": { - "messages": 173, + "messages": 178, "level": 3 }, "983545546348318771": { @@ -280,7 +280,7 @@ "level": 0 }, "509374532109336576": { - "messages": 27, + "messages": 28, "level": 1 }, "464887328138199042": { @@ -292,7 +292,7 @@ "level": 0 }, "283864360697331713": { - "messages": 55, + "messages": 57, "level": 1 }, "481056143536553984": { @@ -300,7 +300,7 @@ "level": 2 }, "813156260563910696": { - "messages": 25, + "messages": 26, "level": 1 }, "236902492955344898": { @@ -336,7 +336,7 @@ "level": 0 }, "929408228255731713": { - "messages": 34, + "messages": 35, "level": 1 }, "810517881392988220": { @@ -348,7 +348,7 @@ "level": 0 }, "549295707304099846": { - "messages": 44, + "messages": 45, "level": 1 }, "759390179064283178": { @@ -400,7 +400,7 @@ "level": 0 }, "903147621961588757": { - "messages": 13, + "messages": 14, "level": 0 }, "386627658773168137": { @@ -424,7 +424,7 @@ "level": 0 }, "281518331427553280": { - "messages": 26, + "messages": 27, "level": 1 }, "708758234407895050": { @@ -472,8 +472,8 @@ "level": 0 }, "557611382028369921": { - "messages": 50, - "level": 0 + "messages": 58, + "level": 1 }, "587649354811179011": { "messages": 1, @@ -532,7 +532,7 @@ "level": 0 }, "818595993121062974": { - "messages": 45, + "messages": 46, "level": 1 }, "273755695680192513": { @@ -544,7 +544,7 @@ "level": 0 }, "869718328313278555": { - "messages": 87, + "messages": 96, "level": 2 }, "772197160372404234": { @@ -564,7 +564,7 @@ "level": 0 }, "705189525743206460": { - "messages": 13, + "messages": 14, "level": 0 }, "1007746635377410110": { @@ -656,7 +656,7 @@ "level": 0 }, "188304766923833344": { - "messages": 20, + "messages": 21, "level": 1 }, "749311773819142326": { @@ -792,7 +792,7 @@ "level": 0 }, "698428165445517356": { - "messages": 23, + "messages": 26, "level": 1 }, "940617130703990864": { @@ -824,11 +824,11 @@ "level": 0 }, "513009978315898891": { - "messages": 10, - "level": 0 + "messages": 18, + "level": 1 }, "667815332047486978": { - "messages": 1, + "messages": 2, "level": 0 }, "902243585511026738": { @@ -1044,7 +1044,7 @@ "level": 0 }, "455423861362655252": { - "messages": 1, + "messages": 2, "level": 0 }, "760579326344691762": { @@ -1056,15 +1056,15 @@ "level": 0 }, "781289786143932499": { - "messages": 105, - "level": 0 + "messages": 106, + "level": 2 }, "348617165135544321": { "messages": 1, "level": 0 }, "268494595594256386": { - "messages": 4, + "messages": 6, "level": 0 }, "120971157158625280": { @@ -1263,10 +1263,6 @@ "messages": 5, "level": 0 }, - "750064203213307905": { - "messages": 2, - "level": 0 - }, "631673794783870986": { "messages": 1, "level": 0 @@ -1320,7 +1316,7 @@ "level": 0 }, "486352184707907585": { - "messages": 3, + "messages": 4, "level": 0 }, "309170189164085249": { @@ -1336,7 +1332,7 @@ "level": 0 }, "478243224469766144": { - "messages": 1, + "messages": 2, "level": 0 }, "425065519360507904": { @@ -1348,7 +1344,7 @@ "level": 0 }, "98464148379148288": { - "messages": 1358, + "messages": 1396, "level": 9 }, "1025723411680460840": { @@ -1468,7 +1464,7 @@ "level": 0 }, "207828776262828034": { - "messages": 5, + "messages": 6, "level": 0 }, "819948487588184125": { @@ -1480,7 +1476,7 @@ "level": 0 }, "889624632724963329": { - "messages": 35, + "messages": 37, "level": 1 }, "687692546314600530": { @@ -1568,8 +1564,8 @@ "level": 0 }, "1018003331890810990": { - "messages": 12, - "level": 0 + "messages": 15, + "level": 1 }, "999815021301334147": { "messages": 4, @@ -1608,8 +1604,8 @@ "level": 0 }, "306234177404272640": { - "messages": 32, - "level": 0 + "messages": 48, + "level": 1 }, "602538366831034368": { "messages": 2, @@ -1624,7 +1620,7 @@ "level": 0 }, "792098245441486859": { - "messages": 68, + "messages": 70, "level": 2 }, "544435655070056448": { @@ -1664,7 +1660,7 @@ "level": 0 }, "937750032344571934": { - "messages": 96, + "messages": 102, "level": 2 }, "873149038709571594": { @@ -1712,7 +1708,7 @@ "level": 0 }, "825286490828701699": { - "messages": 3, + "messages": 6, "level": 0 }, "877631827337150615": { @@ -1732,7 +1728,7 @@ "level": 0 }, "796040852400635914": { - "messages": 314, + "messages": 354, "level": 4 }, "1011307308325818438": { @@ -1748,7 +1744,7 @@ "level": 0 }, "673289306424475659": { - "messages": 103, + "messages": 117, "level": 2 }, "907163452043305000": { @@ -1832,7 +1828,7 @@ "level": 0 }, "335637071878422529": { - "messages": 98, + "messages": 125, "level": 2 }, "646684489573203968": { @@ -1848,15 +1844,15 @@ "level": 0 }, "682165767109738507": { - "messages": 103, - "level": 0 + "messages": 106, + "level": 2 }, "127840266701766656": { "messages": 6, "level": 0 }, "396778041470222349": { - "messages": 98, + "messages": 100, "level": 2 }, "967849095379189861": { @@ -1864,8 +1860,8 @@ "level": 0 }, "1031950921233600662": { - "messages": 14, - "level": 0 + "messages": 15, + "level": 1 }, "907951346769092618": { "messages": 3, @@ -1932,8 +1928,8 @@ "level": 0 }, "813866707365265419": { - "messages": 100, - "level": 0 + "messages": 109, + "level": 2 }, "726188513518813275": { "messages": 1, @@ -1976,7 +1972,7 @@ "level": 0 }, "1030526730462572558": { - "messages": 189, + "messages": 191, "level": 3 }, "530533266206359552": { @@ -1984,7 +1980,7 @@ "level": 0 }, "479291578352140298": { - "messages": 1, + "messages": 7, "level": 0 }, "889408189987192863": { @@ -2056,7 +2052,7 @@ "level": 0 }, "1023915974690340946": { - "messages": 17, + "messages": 20, "level": 1 }, "871113268633174128": { @@ -2100,8 +2096,8 @@ "level": 0 }, "123080080946757632": { - "messages": 14, - "level": 0 + "messages": 27, + "level": 1 }, "1001530115148226711": { "messages": 1, @@ -2172,8 +2168,8 @@ "level": 0 }, "787081270475096084": { - "messages": 78, - "level": 0 + "messages": 79, + "level": 2 }, "1035210998321258586": { "messages": 4, @@ -2271,10 +2267,6 @@ "messages": 1, "level": 0 }, - "934366726282416168": { - "messages": 6, - "level": 0 - }, "444210633035087873": { "messages": 4, "level": 0 @@ -2320,7 +2312,7 @@ "level": 0 }, "406582522697482241": { - "messages": 1, + "messages": 2, "level": 0 }, "231907580748759040": { @@ -2500,7 +2492,7 @@ "level": 0 }, "284482432684785664": { - "messages": 1, + "messages": 2, "level": 0 }, "727948378067173407": { @@ -2512,8 +2504,8 @@ "level": 0 }, "490183428990304286": { - "messages": 50, - "level": 1 + "messages": 65, + "level": 2 }, "787352638811013151": { "messages": 1, @@ -2528,7 +2520,7 @@ "level": 0 }, "799988133893505054": { - "messages": 2, + "messages": 3, "level": 0 }, "534500956688351242": { @@ -2556,7 +2548,7 @@ "level": 0 }, "697953686487564348": { - "messages": 102, + "messages": 110, "level": 2 }, "664233182941413427": { @@ -2583,10 +2575,6 @@ "messages": 1, "level": 0 }, - "1040299894365241465": { - "messages": 14, - "level": 0 - }, "312915980303204352": { "messages": 2, "level": 0 @@ -2608,8 +2596,8 @@ "level": 0 }, "340587045250531358": { - "messages": 39, - "level": 1 + "messages": 79, + "level": 2 }, "911709434554777660": { "messages": 2, @@ -2628,7 +2616,7 @@ "level": 0 }, "1027639990521434172": { - "messages": 1, + "messages": 3, "level": 0 }, "274616625292902400": { @@ -2656,7 +2644,7 @@ "level": 0 }, "701688417091584078": { - "messages": 2, + "messages": 4, "level": 0 }, "907652504253263902": { @@ -2664,19 +2652,99 @@ "level": 0 }, "997785792401375252": { - "messages": 3, - "level": 0 - }, - "895364206025637998": { - "messages": 1, + "messages": 7, "level": 0 }, "963848176912195664": { - "messages": 3, + "messages": 6, "level": 0 }, "828585944206540850": { "messages": 3, "level": 0 + }, + "419057716200210432": { + "messages": 1, + "level": 0 + }, + "154312601495404544": { + "messages": 2, + "level": 0 + }, + "972906041295634462": { + "messages": 1, + "level": 0 + }, + "980710517817614336": { + "messages": 1, + "level": 0 + }, + "860017528109924372": { + "messages": 3, + "level": 0 + }, + "999736341220839464": { + "messages": 5, + "level": 0 + }, + "901565970974392331": { + "messages": 4, + "level": 0 + }, + "388211913621897216": { + "messages": 3, + "level": 0 + }, + "1039241529912475729": { + "messages": 1, + "level": 0 + }, + "562257805927776286": { + "messages": 7, + "level": 0 + }, + "995622955897864272": { + "messages": 42, + "level": 1 + }, + "153323923633733632": { + "messages": 6, + "level": 0 + }, + "190028480786726913": { + "messages": 2, + "level": 0 + }, + "528866704873488386": { + "messages": 2, + "level": 0 + }, + "590595536537518091": { + "messages": 1, + "level": 0 + }, + "576383133763764225": { + "messages": 1, + "level": 0 + }, + "995778519571378266": { + "messages": 10, + "level": 0 + }, + "328602696040841216": { + "messages": 7, + "level": 0 + }, + "222861120329744387": { + "messages": 1, + "level": 0 + }, + "927957676120473671": { + "messages": 1, + "level": 0 + }, + "846431793715871749": { + "messages": 1, + "level": 0 } } \ No newline at end of file diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts new file mode 100644 index 0000000..ae0ffdd --- /dev/null +++ b/src/events/guildMemberAdd.ts @@ -0,0 +1,35 @@ +import Discord from 'discord.js'; +import { TClient } from '../client'; +export default { + name: 'guildMemberAdd', + execute: async(client:TClient, member:Discord.GuildMember)=>{ + if (member.partial) return; + const index = member.guild.memberCount; + const suffix = ((index)=>{ + const numbers = index.toString().split('').reverse(); // eg 1850 --> [0,5,8,1] + if (numbers[1] === '1'){// this is some -teen + return 'th'; + } else { + if (numbers[0] === '1') return 'st'; + else if (numbers[0] === '2') return 'nd'; + else if (numbers[0] === '3') return 'rd'; + else return 'th'; + } + })(index); + + const embed0: Discord.EmbedBuilder = new client.embed().setColor(client.config.embedColor).setThumbnail(member.user.displayAvatarURL({size: 2048}) || member.user.defaultAvatarURL).setTitle(`Welcome to Daggerwin, ${member.user.tag}!`).setFooter({text: `${index}${suffix} member`}); + (client.channels.resolve(client.config.mainServer.channels.welcome) as Discord.TextChannel).send({embeds: [embed0]}) + + if (!client.config.botSwitches.logs) return; + const oldInvites = client.invites; + const newInvites = await member.guild.invites.fetch(); + const usedInvite = newInvites.find((inv:any)=>oldInvites.get(inv.code)?.uses < inv.uses); + newInvites.forEach((inv:any)=>client.invites.set(inv.code,{uses: inv.uses, creator: inv.inviter.id})); + + const embed1 = new client.embed().setColor(client.config.embedColorGreen).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048})).setTitle(`Member Joined: ${member.user.tag}`).setDescription(`<@${member.user.id}>\n\`${member.user.id}\``).addFields( + {name: '🔹 Account Creation Date', value: `<:t${Math.round(member.user.createdTimestamp/1000)}>\n`}, + {name: '🔹 Invite Data:', value: usedInvite ? `Invite: \`${usedInvite.code}\`\nCreated by: **${usedInvite.inviter?.tag}**` : 'I couldn\'t find out how they joined!'} + ); + (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [embed1]}) + } +} \ No newline at end of file diff --git a/src/events/guildMemberRemove.ts b/src/events/guildMemberRemove.ts new file mode 100644 index 0000000..f6c5b1a --- /dev/null +++ b/src/events/guildMemberRemove.ts @@ -0,0 +1,17 @@ +import Discord from 'discord.js'; +import { TClient } from '../client'; +export default { + name: 'guildMemberRemove', + execute: async(client:TClient, member:Discord.GuildMember)=>{ + if (!client.config.botSwitches.logs) return; + if (!member.joinedTimestamp) return; + const embed = new client.embed().setColor(client.config.embedColorRed).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048}) as string).setTitle(`Member Left: ${member.user.tag}`).setDescription(`<@${member.user.id}>\n\`${member.user.id}\``).addFields( + {name: '🔹 Account Creation Date', value: `\n`}, + {name: '🔹 Join Date', value: `\n`}, + {name: `🔹 Roles: ${member.roles.cache.size - 1}`, value: `${member.roles.cache.size > 1 ? member.roles.cache.filter((x)=>x.id !== member.guild.roles.everyone.id).sort((a,b)=>b.position - a.position).map(x=>x).join(member.roles.cache.size > 4 ? ' ' : '\n').slice(0,1024) : 'No roles'}`, inline: true}, + {name: '🔹 Level messages', value: `${client.userLevels._content[member.user.id]?.messages.toLocaleString('en-US') || 0}`, inline: true} + ); + (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [embed]}); + delete client.userLevels._content[member.user.id]; + } +} \ No newline at end of file diff --git a/src/events/guildMemberUpdate.ts b/src/events/guildMemberUpdate.ts new file mode 100644 index 0000000..8f90260 --- /dev/null +++ b/src/events/guildMemberUpdate.ts @@ -0,0 +1,32 @@ +import Discord from 'discord.js'; +import { TClient } from '../client'; +export default { + name: 'guildMemberUpdate', + execute: async(client:TClient, oldMember:Discord.GuildMember, newMember:Discord.GuildMember)=>{ + if (oldMember.guild.id != client.config.mainServer.id) return; + if (!client.config.botSwitches.logs) return; + const channel = (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel) + if (oldMember.nickname != newMember.nickname){ + const embed = new client.embed().setColor(client.config.embedColor).setTimestamp().setThumbnail(newMember.user.displayAvatarURL({size: 2048})).setTitle(`Nickname updated: ${newMember.user.tag}`).setDescription(`<@${newMember.user.id}>\n\`${newMember.user.id}\``).addFields( + {name: '🔹 Old nickname', value: `\`\`\`${oldMember.nickname == null ? ' ' : oldMember.nickname}\`\`\``}, + {name: '🔹 New nickname', value: `\`\`\`${newMember.nickname == null ? ' ' : newMember.nickname}\`\`\``} + ); + channel.send({embeds: [embed]}) + } + /* + todo: role update + - howtobasic the nonexistent '._roles' + + const newRoles = newMember._roles.filter(x=>!oldMember._roles.some(y=>y==x)); + const oldRoles = oldMember._roles.filter(x=>!newMember._roles.some(y=>y==x)); + const embed = new client.embed().setColor(client.config.embedColor).setThumbnail(newMember.user.displayAvatarURL({size: 2048})).setTitle(`Role updated: ${newMember.user.tag}`).setDescription(`<@${newMember.user.id}>\n\`${newMember.user.id}\``) + if (newRoles.length != 0){ + embed.addFields({name: '🔹 Role added', value: newRoles.map((x)=>`<@&${x}>`).join(' ')}) + } + if (oldRoles.length != 0){ + embed.addFields({name: '🔹 Role removed', value: oldRoles.map((x)=>`<@&${x}>`).join(' ')}) + } + channel.send({embeds: [embed]}) + */ + } +} \ No newline at end of file diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts new file mode 100644 index 0000000..44e4abf --- /dev/null +++ b/src/events/interactionCreate.ts @@ -0,0 +1,23 @@ +import Discord from 'discord.js'; +import { TClient } from '../client'; +export default { + name: 'interactionCreate', + execute: async(client:TClient, interaction:Discord.ChatInputCommandInteraction)=>{ + if (!interaction.inGuild() || !interaction.inCachedGuild() || !interaction.command) return; + if (interaction.isCommand()){ + const commandFile = client.commands.get(interaction.commandName); + console.log(`[${client.moment().format('DD/MM/YY HH:mm:ss')}] ${interaction.user.tag} used /${interaction.commandName} ${interaction.options.getSubcommand() ?? ''} in #${interaction.channel.name}`); + if (!client.config.botSwitches.commands && !client.config.eval.whitelist.includes(interaction.user.id)) return interaction.reply({content: 'Commands are currently disabled.', ephemeral: true}); + if (commandFile){ + if (commandFile.disabled) return interaction.reply({content: 'This command is currently disabled.', ephemeral: true}); + try{ + commandFile.run(client, interaction); + commandFile.uses ? commandFile.uses++ : commandFile.uses = 1; + } catch (error:any){ + console.log(`\x1b[31mAn error occured while running command "${commandFile.name}"`, error, error.stack); + return interaction.reply('An error occured while executing this command.'); + } + } + } + } +} \ No newline at end of file diff --git a/src/events/inviteCreate.ts b/src/events/inviteCreate.ts new file mode 100644 index 0000000..492cb19 --- /dev/null +++ b/src/events/inviteCreate.ts @@ -0,0 +1,10 @@ +import Discord from 'discord.js'; +import { TClient } from '../client'; +export default { + name: 'inviteCreate', + execute: async(client:TClient, invite: Discord.Invite)=>{ + if (!invite.guild) return; + const newInvites = await (invite.guild as Discord.Guild).invites.fetch(); + newInvites.forEach(inv=>client.invites.set(inv.code,{uses: inv.code, creator: inv.inviterId})) + } +} \ No newline at end of file diff --git a/src/events/inviteDelete.ts b/src/events/inviteDelete.ts new file mode 100644 index 0000000..8965dd6 --- /dev/null +++ b/src/events/inviteDelete.ts @@ -0,0 +1,8 @@ +import Discord from 'discord.js'; +import { TClient } from '../client'; +export default { + name: 'inviteDelete', + execute: async(client:TClient, invite: Discord.Invite)=>{ + client.invites.delete(invite.code) + } +} \ No newline at end of file diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index b7f82f7..1551f67 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -1,36 +1,14 @@ -import Discord, { Channel, ChannelType, TextChannel } from 'discord.js'; +import Discord, { ChannelType } from 'discord.js'; import { TClient } from '../client'; - export default { name: 'messageCreate', - execute: async (client: TClient, message: Discord.Message)=>{ + execute: async(client:TClient, message:Discord.Message)=>{ if (!client.config.botSwitches.commands && !client.config.eval.whitelist.includes(message.author.id)) return if (message.author.bot) return; if (message.channel.type === ChannelType.DM) return; const msgarr = message.content.toLowerCase().split(' '); let automodded: any; - // Command handler - if (message.content.startsWith(client.config.prefix)){ - const args = message.content.slice(client.config.prefix.length).replace(/\n/g, " ").split(" "); - const commandFile = client.commands.find((x: any)=>x.name === args[0].toLowerCase() || x.alias?.includes(args[0].toLowerCase())); - if (commandFile){ - console.log(`[${client.moment().format('DD/MM/YY HH:mm:ss')}] ${message.author.tag} used ${client.config.prefix}${commandFile.name} in #${message.channelId}`); - // do the cmd - try { - commandFile.run(client, message, args); - commandFile.uses ? commandFile.uses++ : commandFile.uses = 1; - return - } catch (error){ - console.log(error) - client.channels.fetch(client.config.mainServer.channels.errors).then((channel: TextChannel)=>{ - channel.send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]}) - }) - return message.reply('An error occured while executing that command.') - } - } - } - function onTimeout(){ delete client.repeatedMessages[message.author.id] } @@ -59,7 +37,7 @@ export default { // a spammed message is one that has been sent atleast 4 times in the last threshold milliseconds const spammedMessage = client.repeatedMessages[message.author.id]?.find((x:any)=>{ - return client.repeatedMessages[message.author.id].filter((y:any)=>x.cont === y.cont).size >= 4; + return client.repeatedMessages[message.author.id].size >= 4; }); // if a spammed message exists; @@ -90,10 +68,11 @@ export default { '742324777934520350', // #discord-moderators ] if (message.content.toLowerCase().includes('tenor.com/view') || message.content.toLowerCase().includes('giphy.com/gifs/') || message.content.toLowerCase().includes('giphy.com/media/') && bannedChannels.includes(message.channelId)) { - message.reply('Gifs are disabled in this channel.').then((msg: any)=>message.delete()) + message.reply('Gifs are not allowed in this channel.').then((msg: any)=>message.delete()) } // Autoresponse:tm: + if (!client.config.botSwitches.autores && !automodded) { if (message.mentions.members.has('309373272594579456') && !client.isStaff(message.member) && message.type != 19){ message.reply('Please don\'t tag Daggerwin, read rule 14 in <#468846117405196289>') } @@ -128,5 +107,6 @@ export default { if (message.content.toLowerCase().startsWith('night all') || message.content.toLowerCase().startsWith('night everyone')){ message.reply(`Night ${message.author.username}`) } + } } } \ No newline at end of file diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts new file mode 100644 index 0000000..7191565 --- /dev/null +++ b/src/events/messageDelete.ts @@ -0,0 +1,16 @@ +import Discord from 'discord.js'; +import { TClient } from '../client'; +export default { + name: 'messageDelete', + execute: async(client:TClient, msg:Discord.Message)=>{ + if (!client.config.botSwitches.logs) return; + const channel = client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel; + if (msg.partial) return; + if (msg.author.bot) return; + const embed = new client.embed().setColor(client.config.embedColorRed).setTimestamp().setAuthor({name: `Author: ${msg.author.tag} (${msg.author.id})`, iconURL: `${msg.author.displayAvatarURL()}`}).setTitle('Message deleted').setDescription(`<@${msg.author.id}>\nContent:\n\`\`\`\n${msg.content}\n\`\`\`\nChannel: <#${msg.channelId}>`) + channel.send({embeds: [embed]}) + if (msg.attachments?.first()?.width && ['png', 'jpeg', 'jpg', 'gif', 'webp'].some(x=>((msg.attachments.first() as Discord.Attachment).name as string).endsWith(x))) { + embed.setImage(`${[msg.attachments?.first() as Discord.Attachment]}`) + } + } +} \ No newline at end of file diff --git a/src/events/messageDeleteBulk.ts b/src/events/messageDeleteBulk.ts new file mode 100644 index 0000000..ef10c41 --- /dev/null +++ b/src/events/messageDeleteBulk.ts @@ -0,0 +1,15 @@ +import Discord, { Message, Snowflake } from 'discord.js'; +import { TClient } from '../client'; +export default { + name: 'messageDeleteBulk', + execute: async(client:TClient, messages:Discord.Collection)=>{ + const channel = client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel; + if (!client.config.botSwitches.logs) return; + let text = ''; + messages.forEach((m)=>{ + text += `${m.author.username}: ${m.content}\n`; + }); + const embed = new client.embed().setColor(client.config.embedColorRed).setTimestamp().setTitle(`${messages.size} messages were purged`).setDescription(`\`\`\`${text}\`\`\``.slice(0,3900)).addFields({name: 'Channel', value: `<#${(messages.first() as Discord.Message).channel.id}>`}); + channel.send({embeds: [embed]}) + } +} \ No newline at end of file diff --git a/src/events/messageUpdate.ts b/src/events/messageUpdate.ts new file mode 100644 index 0000000..31d3d5c --- /dev/null +++ b/src/events/messageUpdate.ts @@ -0,0 +1,18 @@ +import Discord, { ActionRowBuilder, ButtonBuilder } from 'discord.js'; +import { TClient } from '../client'; +export default { + name: 'messageUpdate', + execute: async(client:TClient, oldMsg:Discord.Message, newMsg:Discord.Message)=>{ + if (!client.config.botSwitches.logs) return; + if (oldMsg.author == null) return; + if (oldMsg?.author.bot) return; + if (oldMsg.partial) return; + if (newMsg.partial) return; + if (!newMsg.member) return; + const msgarr = newMsg.content.toLowerCase().split(' '); + if (client.bannedWords._content.some((word:string)=>msgarr.includes(word)) && (!client.isStaff(newMsg.member))) newMsg.delete(); + if (newMsg.content === oldMsg.content) return; + const embed = new client.embed().setColor(client.config.embedColor).setTimestamp().setAuthor({name: `Author: ${oldMsg.author.tag} (${oldMsg.author.id})`, iconURL: `${oldMsg.author.displayAvatarURL()}`}).setTitle('Message edited').setDescription(`<@${oldMsg.author.id}>\nOld content:\n\`\`\`\n${oldMsg.content}\n\`\`\`\nNew content:\n\`\`\`\nChannel: <#${oldMsg.channelId}>`); + (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [embed], components: [new ActionRowBuilder().addComponents(new ButtonBuilder().setStyle(5).setURL(`${oldMsg.url}`).setLabel('Jump to message'))]}); + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index f9ebb21..d2917bc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,17 +46,10 @@ process.on('error', async(error: Error)=>{ (client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]}) }); -// Command handler -const commandFiles = fs.readdirSync('./commands').filter(file=>file.endsWith('.js')); -for (const file of commandFiles){ - const command = require(`./commands/${file}`); - client.commands.set(command.name, command) -} - // Daggerwin MP loop setInterval(async()=>{ if (!client.config.botSwitches.mpstats) return; - const msg = await client.channels.resolve('ChannelID').messages.fetch('MessageID') + const msg = await (client.channels.resolve('ChannelID') as Discord.TextChannel).messages.fetch('MessageID') const embed = new client.embed(); let Players = []; let Server: any; @@ -132,22 +125,10 @@ setInterval(async()=>{ // Event loop for punishments and daily msgs setInterval(async()=>{ - interface Punishment { - id: number; - type: string; - member: string; - moderator: string; - expired?: boolean; - time?: number; - reason: string; - endTime?: number; - cancels?: number; - duration?: number; - } const now = Date.now() const lrsStart = client.config.LRSstart; - client.punishments._content.filter((x: Punishment)=>x.endTime<= now && !x.expired).forEach(async (punishment: Punishment)=>{ + client.punishments._content.filter((x:Punishment)=>x.endTime<= now && !x.expired).forEach(async (punishment:Punishment)=>{ console.log(`\x1b[36m[${client.moment().format('DD/MM/YY HH:mm:ss')}]`, '\x1b[32m' + `${punishment.member}\'s ${punishment.type} should expire now`); const unpunishResult = await client.punishments.removePunishment(punishment.id, client.user.id, 'Time\'s up!'); console.log(`\x1b[36m[${client.moment().format('DD/MM/YY HH:mm:ss')}]`, '\x1b[32m' + unpunishResult); @@ -161,7 +142,7 @@ setInterval(async()=>{ } if (!dailyMsgs.some(x=>x[0] === formattedDate)){ let total = Object.values(client.userLevels._content).reduce((a,b)=>a + b.messages, 0); // sum of all users - const yesterday = dailyMsgs.find((x: Array)=>x[0] === formattedDate - 1); + const yesterday = dailyMsgs.find((x:Array)=>x[0] === formattedDate - 1); if (total < yesterday){ // messages went down. total = yesterday } @@ -171,69 +152,15 @@ setInterval(async()=>{ } }, 5000) -// Assign page number to commands -const categories = {}; -while (client.commands.some(command=>!command.hidden && !command.page)){ - const command = client.commands.find(command=>!command.hidden && !command.page); - if (!command.category) command.category = 'Misc'; - if (!categories[command.category]) categories[command.category] = {text: '', currentPage: 1} - const commandInfo = client.commandInfo(client, command, client.helpDefaultOptions); - if (categories[command.category].text.length+commandInfo.length>1024){ - categories[command.category].text = commandInfo; - categories[command.category].currentPage++; - } else { - categories[command.category].text += commandInfo; - } - command.page = categories[command.category].currentPage; -} -client.categoryNames = Object.keys(categories); -delete categories; - -// create pages without contents -client.commands.filter(command=>!command.hidden).forEach(command=>{ - if (!client.commandPages.some((x:any)=>x.category === command.category && x.pages === command.pages)){ - client.commandPages.push({ - name: `${command.category} - Page ${command.page}/${Math.max(...client.commands.filter((x:any)=>x.category === command.category).map((x:any)=>x.page))}`, - category: command.category, - page: command.page - }); - } -}); -client.commandPages.sort((a: any, b: any)=>{ - if (a.nameb.name){ - return 1; - } else { - return 0; - } -}); // Punishments -interface punOpt { - time: number, - reason: string, - message: any -} -interface punData { - id: number; - type: string; - member: string; - moderator: string; - expired?: boolean; - time?: number; - reason?: string; - endTime?: number; - cancels?: number; - duration?: number; -} Object.assign(client.punishments,{ createId(){ - return Math.max(...client.punishments._content.map((x: punData)=>x.id), 0) + 1; + return Math.max(...client.punishments._content.map((x:Punishment)=>x.id), 0) + 1; }, - async addPunishment(type: string, member: Discord.GuildMember, options: punOpt, moderator: string){ + async addPunishment(type: string, member: any, options: punOpt, moderator: string){ const now = Date.now(); - const { time, reason, message } = options; - const ms = import('ms'); + const { time, reason, interaction } = options; + const ms = require('ms'); let timeInMillis; if (type !== 'mute'){ timeInMillis = time ? ms(time) : null; @@ -242,14 +169,14 @@ Object.assign(client.punishments,{ } switch (type) { case 'ban': - const banData: punData = {type, id: this.createId(), member: member.id, moderator, time: now}; - let dm1; + const banData: Punishment = {type, id: this.createId(), member: member.id, moderator, time: now}; + let dm1:any; try { - dm1 = await member.send(`You've been banned from ${message.guild.name} ${timeInMillis ? `for ${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Unspecified'}\` (Case #${banData.id})`) + dm1 = await member.send(`You've been banned from ${interaction.guild.name} ${timeInMillis ? `for ${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Reason unspecified'}\` (Case #${banData.id})`) } catch (err) { - setTimeout(()=>message.channel.send('Failed to DM user.'), 500) + setTimeout(()=>interaction.channel.send('Failed to DM user.'), 500) } - const banResult = await message.guild.bans.create(member.id, {reason: `${reason || 'Unspecified'} | Case #${banData.id}`}).catch((err: Error)=>err.message); + const banResult = await interaction.guild.bans.create(member.id, {reason: `${reason || 'Reason unspecified'} | Case #${banData.id}`}).catch((err: Error)=>err.message); if (typeof banResult === 'string'){ dm1.delete(); return `Ban was unsuccessful: ${banResult}`; @@ -263,20 +190,20 @@ Object.assign(client.punishments,{ this.addData(banData); this.forceSave(); return new client.embed().setColor(client.config.embedColor).setTitle(`Case #${banData.id}: Ban`).setDescription(`${member.tag}\n<@${member.id}>\n(\`${member.id}\`)`).addFields( - {name: 'Reason', value: `\`${reason || 'Unspecified'}\``}, + {name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``}, {name: 'Duration', value: `${timeInMillis ? `for ${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'}`} ) } case 'softban': const guild = member.guild; - const softbanData: punData = {type, id: this.createId(), member: member.user.id, moderator, time: now}; - const dm2 = await member.send(`You've been softbanned from ${member.guild.name} for reason \`${reason || 'Unspecified'}\` (Case #${softbanData.id})`).catch(err=>setTimeout(()=>message.channel.send(`Failed to DM <@${member.user.id}>.`), 500)); - const softbanResult = await member.ban({deleteMessageDays: 7, reason: `${reason || 'Unspecified'} | Case #${softbanData.id}`}).catch((err: Error)=>err.message); + const softbanData: Punishment = {type, id: this.createId(), member: member.user.id, moderator, time: now}; + const dm2 = await member.send(`You've been softbanned from ${member.guild.name} for reason \`${reason || 'Reason unspecified'}\` (Case #${softbanData.id})`).catch(err=>setTimeout(()=>interaction.channel.send(`Failed to DM <@${member.user.id}>.`), 500)); + const softbanResult = await member.ban({deleteMessageDays: 7, reason: `${reason || 'Reason unspecified'} | Case #${softbanData.id}`}).catch((err: Error)=>err.message); if (typeof softbanResult === 'string'){ dm2.delete(); return `Softban was unsuccessful: ${softbanResult}`; } else { - const unbanResult = guild.members.unban(softbanData.member, `${reason || 'Unspecified'} | Case #${softbanData.id}`).catch((err: Error)=>err.message); + const unbanResult = guild.members.unban(softbanData.member, `${reason || 'Reason unspecified'} | Case #${softbanData.id}`).catch((err: Error)=>err.message); if (typeof unbanResult === 'string'){ return `Softban (unban) was unsuccessful: ${softbanResult}` } else { @@ -285,14 +212,14 @@ Object.assign(client.punishments,{ this.addData(softbanData) this.forceSave(); return new client.embed().setColor(client.config.embedColor).setTitle(`Case #${softbanData.id}: Softban`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields( - {name: 'Reason', value: `\`${reason || 'Unspecified'}\``} + {name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``} ) } } case 'kick': - const kickData: punData = {type, id: this.createId(), member: member.user.id, moderator, time: now}; - const dm3 = await member.send(`You've been kicked from ${member.guild.name} for reason \`${reason || 'Unspecified'}\` (Case #${kickData.id})`).catch((err:Error)=>setTimeout(()=>message.channel.send(`Failed to DM <@${member.user.id}>.`), 500)); - const kickResult = await member.kick(`${reason || 'Unspecified'} | Case #${kickData.id}`).catch((err:Error)=>err.message); + const kickData: Punishment = {type, id: this.createId(), member: member.user.id, moderator, time: now}; + const dm3 = await member.send(`You've been kicked from ${member.guild.name} for reason \`${reason || 'Reason unspecified'}\` (Case #${kickData.id})`).catch((err:Error)=>setTimeout(()=>interaction.channel.send(`Failed to DM <@${member.user.id}>.`), 500)); + const kickResult = await member.kick(`${reason || 'Reason unspecified'} | Case #${kickData.id}`).catch((err:Error)=>err.message); if (typeof kickResult === 'string'){ dm3.delete(); return `Kick was unsuccessful: ${kickResult}`; @@ -302,17 +229,17 @@ Object.assign(client.punishments,{ this.addData(kickData); this.forceSave(); return new client.embed().setColor(client.config.embedColor).setTitle(`Case #${kickData.id}: Kick`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields( - {name: 'Reason', value: `\`${reason || 'Unspecified'}\``} + {name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``} ) } case 'mute': - const muteData: punData = {type, id: this.createId(), member: member.user.id, moderator, time: now}; + const muteData: Punishment = {type, id: this.createId(), member: member.user.id, moderator, time: now}; let muteResult; - const dm4 = await member.send(`You've been muted in ${member.guild.name} ${timeInMillis ? `for ${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Unspecified'}\` (Case #${muteData.id})`).catch((err:Error)=>setTimeout(()=>message.channel.send('Failed to DM user.'), 500)); + const dm4 = await member.send(`You've been muted in ${member.guild.name} ${timeInMillis ? `for ${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Reason unspecified'}\` (Case #${muteData.id})`).catch((err:Error)=>setTimeout(()=>interaction.channel.send('Failed to DM user.'), 500)); if (timeInMillis){ - muteResult = await member.timeout(timeInMillis, `${reason || 'Unspecified'} | Case #${muteData.id}`).catch((err: Error)=>err.message); + muteResult = await member.timeout(timeInMillis, `${reason || 'Reason unspecified'} | Case #${muteData.id}`).catch((err: Error)=>err.message); } else { - muteResult = await member.timeout(2419200000, `${reason || 'Unspecified'} | Case #${muteData.id}`).catch((err: Error)=>err.message); + muteResult = await member.timeout(2419200000, `${reason || 'Reason unspecified'} | Case #${muteData.id}`).catch((err: Error)=>err.message); } if (typeof muteResult === 'string') { dm4.delete(); @@ -326,15 +253,15 @@ Object.assign(client.punishments,{ client.makeModlogEntry(muteData, client); this.addData(muteData); this.forceSave(); - const embedm = new client.embed().setColor().setTitle(`Case #${muteData.id}: Mute`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields( - {name: 'Reason', value: `\`${reason || 'Unspecified'}\``}, + const embedm = new client.embed().setColor(client.config.embedColor).setTitle(`Case #${muteData.id}: Mute`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields( + {name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``}, {name: 'Duration', value: `${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)`} ) if (moderator !== '795443537356521502') {return embedm}; } case 'warn': - const warnData: punData = {type, id: this.createId(), member: member.user.id, moderator, time: now}; - const warnResult = await member.send(`You've been warned in ${member.guild.name} for reason \`${reason || 'Unspecified'}\` (Case #${warnData.id})`).catch((err:Error)=>setTimeout(()=>message.channel.send(`Failed to DM <@${member.user.id}>.`), 500)); + const warnData: Punishment = {type, id: this.createId(), member: member.user.id, moderator, time: now}; + const warnResult = await member.send(`You've been warned in ${member.guild.name} for reason \`${reason || 'Reason unspecified'}\` (Case #${warnData.id})`).catch((err:Error)=>setTimeout(()=>interaction.channel.send(`Failed to DM <@${member.user.id}>.`), 500)); if (typeof warnResult === 'string'){ return `Warn was unsuccessful: ${warnResult}`; } else { @@ -343,7 +270,7 @@ Object.assign(client.punishments,{ this.addData(warnData); this.forceSave(); const embedw = new client.embed().setColor(client.config.embedColor).setTitle(`Case #${warnData.id}: Warn`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields( - {name: 'Reason', value: `\`${reason || 'Unspecified'}\``} + {name: 'Reason', value: `\`${reason || 'Reason unspecified'}\``} ) if (moderator !== '795443537356521502') {return embedw}; } @@ -359,14 +286,14 @@ Object.assign(client.punishments,{ let removePunishmentResult; if(punishment.type === 'ban'){ // unban - removePunishmentResult = await guild.members.unban(punishment.member, `${reason || 'Unspecified'} | Case #${id}`).catch((err: TypeError)=>err.message); + removePunishmentResult = await guild.members.unban(punishment.member, `${reason || 'Reason unspecified'} | Case #${id}`).catch((err: TypeError)=>err.message); }else if (punishment.type === 'mute') { //remove role const member = await guild.members.fetch(punishment.member).catch(err=>undefined); if (member){ removePunishmentResult = await member if (typeof removePunishmentResult !== 'string'){ - member.timeout(null, `${reason || 'Unspecified'} | Case #${id}`) + member.timeout(null, `${reason || 'Reason unspecified'} | Case #${id}`) removePunishmentResult.send(`You've been unmuted in ${removePunishmentResult.guild.name}.`) removePunishmentResult = removePunishmentResult.user; //removing a role returns a guildmember } @@ -383,7 +310,7 @@ Object.assign(client.punishments,{ client.makeModlogEntry(removePunishmentData, client); this._content[this._content.findIndex(x=>x.id === punishment.id)].expired = true; this.addData(removePunishmentData).forceSave(); - return `Successfully ${punishment.type === 'ban' ? 'unbanned' : 'unmuted'} ${removePunishmentResult?.tag} (\`${removePunishmentResult?.id}\`) for reason \`${reason || 'Unspecified'}\``; + return `Successfully ${punishment.type === 'ban' ? 'unbanned' : 'unmuted'} ${removePunishmentResult?.tag} (\`${removePunishmentResult?.id}\`) for reason \`${reason || 'Reason unspecified'}\``; } } else { try { @@ -392,7 +319,7 @@ Object.assign(client.punishments,{ this._content[this._content.findIndex(x=>x.id === punishment.id)].expired = true; this.addData(removePunishmentData).forceSave(); return `Successfully removed Case #${punishment.id} (type: ${punishment.type}, user: ${punishment.member}).`; - } catch(error: Error){ + } catch(error: any){ return `${punishment.type[0].toUpperCase()+punishment.type.slice(1)} removal was unsuccessful: ${error.message}` } } diff --git a/src/typings/interfaces.d.ts b/src/typings/interfaces.d.ts new file mode 100644 index 0000000..959f77f --- /dev/null +++ b/src/typings/interfaces.d.ts @@ -0,0 +1,31 @@ +interface createTableOpt { + columnAlign: any, + columnSeparator: any, + columnEmptyChar: any +} +interface formatTimeOpt { + longNames: boolean, + commas: boolean +} +interface CommandInfoOpt { + insertNewline: boolean, + parts: string[], //idfk + titles: string[] +} +interface punOpt { + time?: string, + reason?: string, + interaction?: any +} +interface Punishment { + id: number; + type: string; + member: string; + moderator: string; + expired?: boolean; + time?: number; + reason?: string; + endTime?: number; + cancels?: number; + duration?: number; +} \ No newline at end of file