diff --git a/Shard.js b/Shard.js deleted file mode 100644 index 17add350..00000000 --- a/Shard.js +++ /dev/null @@ -1,5 +0,0 @@ -const { ShardingManager } = require('discord.js'); -const path = require('path'); -const { TOKEN } = process.env; -const manager = new ShardingManager(path.join(__dirname, 'XiaoBot.js'), { token: TOKEN }); -manager.spawn(undefined, 1000); diff --git a/XiaoBot.js b/XiaoBot.js index 816d6967..ec628bac 100644 --- a/XiaoBot.js +++ b/XiaoBot.js @@ -9,7 +9,6 @@ const client = new CommandoClient({ unknownCommandResponse: false, disabledEvents: ['TYPING_START'] }); -const whitelist = require('./assets/json/whitelist'); client.registry .registerDefaultTypes() @@ -38,7 +37,7 @@ client.registry .registerCommandsIn(path.join(__dirname, 'commands')); client.on('ready', () => { - console.log(`[READY] Shard ${client.shard.id} logged in as ${client.user.tag}! (${client.user.id})`); + console.log(`[READY] Logged in as ${client.user.tag}! (${client.user.id})`); client.setInterval(() => { const activities = [ `${COMMAND_PREFIX}help for commands`, @@ -49,15 +48,10 @@ client.on('ready', () => { ]; client.user.setActivity(activities[Math.floor(Math.random() * activities.length)]); }, 60000); - for (const guild of client.guilds.values()) { - if (whitelist.guilds.includes(guild.id) || whitelist.owners.includes(guild.ownerID)) continue; - console.log(`[LEAVE] Leaving guild ${guild.name}.`); - guild.leave().catch(err => console.error(`[LEAVE] Failed to leave ${guild.name}.`, err)); - } }); client.on('disconnect', event => { - console.error(`[DISCONNECT] Shard ${client.shard.id} disconnected with code ${event.code}.`); + console.error(`[DISCONNECT] Disconnected with code ${event.code}.`); process.exit(0); }); diff --git a/assets/json/whitelist.json b/assets/json/whitelist.json deleted file mode 100644 index dbe04818..00000000 --- a/assets/json/whitelist.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "guilds": [ - "252317073814978561", - "353661927056211970", - "317042872543346689", - "346450651326185475", - "355017633906819073", - "228598099549880320", - "320631716538613760", - "280525180411969536", - "348616424803008513", - "224249138982813696", - "319959788400148481" - ], - "owners": [ - "252755193739870208", - "189255131982856192", - "228313559329669120", - "255408285644095489", - "242699360352206850", - "268104118000812042", - "244541315939958785", - "155882426541801472", - "259468791103094785", - "223639379594313728", - "234318196893548545", - "270090582435561493", - "296891491933093900", - "219199801177145345", - "252605433620070410", - "219239880855781376", - "252969562868285440", - "229003197908385794", - "358444437745172480", - "252711086556577792" - ] -} diff --git a/assets/json/wizard-convention.json b/assets/json/wizard-convention.json new file mode 100644 index 00000000..e77336d8 --- /dev/null +++ b/assets/json/wizard-convention.json @@ -0,0 +1,29 @@ +{ + "questions": { + "dragon": "Who do you want to eat?", + "healer": "Who do you want to heal?", + "mind reader": "Who do you think is the dragon?" + }, + "stories": [ + ".", + " after they had left to get a little snack.", + " while they were in the library fixing their wand.", + " before they could get the chance to call for help.", + " while they were trying to sneak into another wizard's room.", + " when they left for the bathroom.", + " in one big bite.", + " while they were making a very early coffee.", + " while they were attemping to flirt with it.", + ", who willingly accepted their fate.", + " while they were playing a quick game of Wizard Convention.", + " while they were writing a letter to the king.", + " before they could have the chance to fight back.", + " just as they were about to get ready to leave in fear.", + ", who was a complete coward and turned into a chicken at the sight of the beast.", + ", who had no time to run.", + ", who was busy trying to find the rumored dragon of the convention.", + " with almost no sign of any remains.", + " before they could even mutter a word.", + ", who left a large mess in the kitchen." + ] +} diff --git a/commands/games/akinator.js b/commands/games/akinator.js index 1638397c..1ecc0ed3 100644 --- a/commands/games/akinator.js +++ b/commands/games/akinator.js @@ -55,6 +55,7 @@ module.exports = class AkinatorCommand extends Command { await msg.embed(embed); const verification = await verify(msg.channel, msg.author); this.sessions.delete(msg.channel.id); + if (verification === 0) return msg.reply('I guess your silence means I have won.'); if (!verification) return msg.say('Bravo, you have defeated me.'); return msg.say('Guessed right one more time! I love playing with you!'); } catch (err) { diff --git a/commands/games/hangman.js b/commands/games/hangman.js index 828885ff..063d9f1a 100644 --- a/commands/games/hangman.js +++ b/commands/games/hangman.js @@ -52,6 +52,7 @@ module.exports = class HangmanCommand extends Command { if (choice.length > 1) { if (word === choice) break; else await msg.say('Nope, that\'s not the word, try again!'); + points++; } else if (confirmation.includes(choice) || incorrect.includes(choice)) { await msg.say('You have already picked that letter!'); } else if (word.includes(choice)) { diff --git a/commands/games/wizard-convention.js b/commands/games/wizard-convention.js new file mode 100644 index 00000000..4db16956 --- /dev/null +++ b/commands/games/wizard-convention.js @@ -0,0 +1,176 @@ +const { Command } = require('discord.js-commando'); +const { Collection } = require('discord.js'); +const { stripIndents } = require('common-tags'); +const { shuffle, list, wait } = require('../../util/Util'); +const { questions, stories } = require('../../assets/json/wizard-convention'); + +module.exports = class WizardConventionCommand extends Command { + constructor(client) { + super(client, { + name: 'wizard-convention', + group: 'games', + memberName: 'wizard-convention', + description: 'Who is the Dragon? Who is the healer? Who is the mind reader? Will the Dragon eat them all?', + guildOnly: true + }); + + this.playing = new Set(); + } + + async run(msg) { // eslint-disable-line complexity + if (this.playing.has(msg.channel.id)) return msg.say('Only one game may be occurring per channel.'); + try { + await msg.say('You will need at least 2 more players, type `join game` to join the game.'); + const joined = []; + const filter = res => { + if (res.author.id === msg.author.id) return false; + if (joined.includes(res.author.id)) return false; + if (['join game', 'join convention'].includes(res.content.toLowerCase())) { + joined.push(res.author.id); + return true; + } + return false; + }; + const verify = await msg.channel.awaitMessages(filter, { time: 30000 }); + if (verify.size < 2) { + this.playing.delete(msg.channel.id); + return msg.say('Game could not be started...'); + } + let roles = ['dragon', 'healer', 'mind reader']; + for (let i = 0; i < (verify.size - 2); i++) roles.push(`pleb ${i + 1}`); + roles = shuffle(roles); + const players = new Collection(); + players.set(msg.author.id, { + user: msg.author, + role: roles[0] + }); + await msg.author.send(`You are ${roles[0].includes('pleb') ? 'a pleb.' : `the ${roles[0]}!`}`); + let i = 1; + for (const message of verify.values()) { + players.set(message.author.id, { + user: message.author, + role: roles[i] + }); + await message.author.send(`You are ${roles[i].includes('pleb') ? 'a pleb.' : `the ${roles[i]}!`}`); + i++; + } + let night = 1; + let win = false; + let skips = 0; + while (players.size > 2) { + if (skips > 3) return msg.say('Game ended after too many skips.'); + let eaten = null; + let healed = null; + await msg.say(`Night ${night++}... Sending DMs...`); + for (const player of players.values()) { + if (player.role.includes('pleb')) continue; + const playerList = players.filter(p => p.role !== player.role).map(p => p.user.tag); + await player.user.send(`${questions[player.role]} ${list(playerList, 'or')}?`); + const decision = await player.user.dmChannel.awaitMessages(res => playerList.includes(res.content), { + max: 1, + time: 30000 + }); + if (!decision.size) { + await player.user.send('Skipping your turn...'); + ++skips; + continue; + } + const choice = decision.first().content; + if (player.role === 'dragon') { + const found = players.find(p => p.user.tag === choice); + eaten = found.user.id; + await player.user.send(`${choice} will be eaten...`); + } else if (player.role === 'healer') { + const found = players.find(p => p.user.tag === choice); + healed = found.user.id; + await player.user.send(`${choice} will be healed...`); + } else if (player.role === 'mind reader') { + const dragon = players.find('role', 'dragon'); + const found = players.find(p => p.user.tag === choice); + await player.user.send(dragon.user.id === found.user.id ? 'Yes.' : 'No.'); + } + } + const display = eaten ? players.get(eaten).user : null; + if (eaten && eaten !== healed) { + const found = players.find(p => p.user.id === eaten); + players.delete(found.user.id); + } + const story = stories[Math.floor(Math.random() * stories.length)]; + if (eaten && eaten === healed) { + await msg.say(stripIndents` + Late last night, a dragon emerged and tried to eat ${display}${story} + Thankfully, a healer stepped in just in time to save the day. + Who is this mysterious dragon? You have one minute to argue your case. + `); + } else if (eaten && players.size < 3) { + await msg.say(stripIndents` + Late last night, a dragon emerged and devoured poor ${display}${story} + Sadly, after the event, the final wizard ran in fear, leaving the dragon to rule forever. + `); + break; + } else if (eaten && eaten !== healed) { + await msg.say(stripIndents` + Late last night, a dragon emerged and devoured poor ${display}${story} + Who is this mysterious dragon? You have one minute to argue your case. + `); + } else { + await msg.say(stripIndents` + Late last night, a dragon emerged. Thankfully, however, it didn't try to eat anyone. + Who is this mysterious dragon? You have one minute to argue your case. + `); + } + await wait(60000); + await msg.say('Time is up!'); + const voteCounts = new Collection(); + const voted = []; + const playerList = players.map(p => p.user.tag); + const filter2 = res => { + if (!players.has(res.author.id)) return false; + if (voted.includes(res.author.id)) return false; + if (playerList.includes(res.content)) { + voted.push(res.author.id); + return true; + } + return false; + }; + await msg.say(`Who is the dragon? ${list(playerList, 'or')}?`); + const votes = await msg.channel.awaitMessages(filter2, { time: 30000 }); + for (const vote of votes.values()) { + for (const player of players.values()) { + if (!player.user.tag.includes(vote.content)) continue; + const existing = voteCounts.get(player.user.id); + if (existing) { + ++existing.votes; + } else { + voteCounts.set(player.user.id, { + votes: 1, + user: player.user + }); + } + } + } + if (!voteCounts.size) { + await msg.say('No one will be expelled.'); + ++skips; + continue; + } + const expelled = voteCounts.sort((a, b) => b.votes - a.votes).first(); + await msg.say(`${expelled.user} will be expelled.`); + if (players.find('role', 'dragon').user.id === expelled.user.id) { + win = true; + break; + } else { + const found = players.find(player => player.user.id === expelled.id); + players.delete(found.user.id); + } + } + this.playing.delete(msg.channel.id); + if (win) return msg.say('The dragon is dead! Thanks for playing!'); + const dragon = players.find('role', 'dragon'); + return msg.say(`Oh no... The dragon wasn't caught in time... Nice job, ${dragon.user}!`); + } catch (err) { + this.playing.delete(msg.channel.id); + return msg.say(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); + } + } +}; diff --git a/commands/guild-info/server-info.js b/commands/guild-info/server-info.js index 8f234db4..7dbab951 100644 --- a/commands/guild-info/server-info.js +++ b/commands/guild-info/server-info.js @@ -24,22 +24,22 @@ module.exports = class ServerInfoCommand extends Command { msg.guild.name, true) .addField('❯ ID', msg.guild.id, true) - .addField('❯ Shard', - this.client.shard.id, true) + .addField('❯ Region', + msg.guild.region.toUpperCase(), true) .addField('❯ Creation Date', msg.guild.createdAt.toDateString(), true) .addField('❯ Explicit Filter', filterLevels[msg.guild.explicitContentFilter], true) .addField('❯ Verification Level', verificationLevels[msg.guild.verificationLevel], true) - .addField('❯ Region', - msg.guild.region.toUpperCase(), true) .addField('❯ Owner', msg.guild.owner ? msg.guild.owner.user.tag : 'None', true) - .addField('❯ Channels', - msg.guild.channels.size, true) .addField('❯ Members', - msg.guild.memberCount, true); + msg.guild.memberCount, true) + .addField('❯ Roles', + msg.guild.roles.size, true) + .addField('❯ Channels', + msg.guild.channels.size, true); return msg.embed(embed); } }; diff --git a/commands/search/danbooru.js b/commands/search/danbooru.js index cf541a99..178c8645 100644 --- a/commands/search/danbooru.js +++ b/commands/search/danbooru.js @@ -1,6 +1,5 @@ const { Command } = require('discord.js-commando'); const snekfetch = require('snekfetch'); -const { stripIndents } = require('common-tags'); module.exports = class DanbooruCommand extends Command { constructor(client) { @@ -34,10 +33,7 @@ module.exports = class DanbooruCommand extends Command { limit: 1 }); if (!body.length || !body[0].file_url) return msg.say('Could not find any results.'); - return msg.say(stripIndents` - Result for ${query}: - https://danbooru.donmai.us${body[0].file_url} - `); + return msg.say(`https://danbooru.donmai.us${body[0].file_url}`); } catch (err) { return msg.say(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); } diff --git a/commands/search/derpibooru.js b/commands/search/derpibooru.js index a13200b5..ac98917d 100644 --- a/commands/search/derpibooru.js +++ b/commands/search/derpibooru.js @@ -1,6 +1,5 @@ const { Command } = require('discord.js-commando'); const snekfetch = require('snekfetch'); -const { stripIndents } = require('common-tags'); module.exports = class DerpibooruCommand extends Command { constructor(client) { @@ -30,10 +29,7 @@ module.exports = class DerpibooruCommand extends Command { }); if (!search.body) return msg.say('Could not find any results.'); const { body } = await snekfetch.get(`https://derpibooru.org/images/${search.body.id}.json`); - return msg.say(stripIndents` - Result for ${query}: - https:${body.representations.medium} - `); + return msg.say(`https:${body.representations.medium}`); } catch (err) { return msg.say(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); } diff --git a/commands/search/gelbooru.js b/commands/search/gelbooru.js index 7846e347..14bee91b 100644 --- a/commands/search/gelbooru.js +++ b/commands/search/gelbooru.js @@ -1,7 +1,6 @@ const { Command } = require('discord.js-commando'); const snekfetch = require('snekfetch'); const { xml2js } = require('xml-js'); -const { stripIndents } = require('common-tags'); module.exports = class GelbooruCommand extends Command { constructor(client) { @@ -34,10 +33,7 @@ module.exports = class GelbooruCommand extends Command { }); const parsed = xml2js(text, { compact: true }).posts; if (!parsed.post || !parsed.post.length) return msg.say('Could not find any results.'); - return msg.say(stripIndents` - Result for ${query}: - ${parsed.post[Math.floor(Math.random() * parsed.post.length)]._attributes.file_url} - `); + return msg.say(`${parsed.post[Math.floor(Math.random() * parsed.post.length)]._attributes.file_url}`); } catch (err) { return msg.say(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); } diff --git a/commands/search/konachan.js b/commands/search/konachan.js index 98baf2e8..aa26901b 100644 --- a/commands/search/konachan.js +++ b/commands/search/konachan.js @@ -1,6 +1,5 @@ const { Command } = require('discord.js-commando'); const snekfetch = require('snekfetch'); -const { stripIndents } = require('common-tags'); module.exports = class KonachanCommand extends Command { constructor(client) { @@ -30,10 +29,7 @@ module.exports = class KonachanCommand extends Command { limit: 1 }); if (!body.length || !body[0].file_url) return msg.say('Could not find any results.'); - return msg.say(stripIndents` - Result for ${query}: - https:${body[0].file_url} - `); + return msg.say(`https:${body[0].file_url}`); } catch (err) { return msg.say(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); } diff --git a/commands/search/safebooru.js b/commands/search/safebooru.js index 78175df0..e1bd4e43 100644 --- a/commands/search/safebooru.js +++ b/commands/search/safebooru.js @@ -1,7 +1,6 @@ const { Command } = require('discord.js-commando'); const snekfetch = require('snekfetch'); const { xml2js } = require('xml-js'); -const { stripIndents } = require('common-tags'); module.exports = class SafebooruCommand extends Command { constructor(client) { @@ -33,10 +32,7 @@ module.exports = class SafebooruCommand extends Command { }); const parsed = xml2js(text, { compact: true }).posts; if (!parsed.post || !parsed.post.length) return msg.say('Could not find any results.'); - return msg.say(stripIndents` - Result for ${query}: - https:${parsed.post[Math.floor(Math.random() * parsed.post.length)]._attributes.file_url} - `); + return msg.say(`https:${parsed.post[Math.floor(Math.random() * parsed.post.length)]._attributes.file_url}`); } catch (err) { return msg.say(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); } diff --git a/commands/text-edit/portal-send.js b/commands/text-edit/portal-send.js index 1397a10e..d5b7c407 100644 --- a/commands/text-edit/portal-send.js +++ b/commands/text-edit/portal-send.js @@ -27,7 +27,7 @@ module.exports = class PortalSendCommand extends Command { async run(msg, { text }) { const valid = this.client.channels.filter(channel => channel.type === 'text' && channel.guild.id !== msg.guild.id); const channels = valid.filter(channel => channel.topic && channel.topic.toLowerCase().includes('')); - if (!channels.size) return msg.say('No channels on this shard have an open portal.'); + if (!channels.size) return msg.say('No channels have an open portal.'); const channel = channels.random(); try { await channel.send(`**${msg.author.tag} (${msg.guild.name})**: ${text}`); diff --git a/commands/util/info.js b/commands/util/info.js index fde842e6..84803b57 100644 --- a/commands/util/info.js +++ b/commands/util/info.js @@ -16,13 +16,12 @@ module.exports = class InfoCommand extends Command { }); } - async run(msg) { - const guilds = await this.client.shard.fetchClientValues('guilds.size'); + run(msg) { const embed = new MessageEmbed() .setColor(0x00AE86) .setFooter('©2017 dragonfire535#8081') .addField('❯ Servers', - guilds.reduce((prev, val) => prev + val, 0), true) + this.client.guilds.size, true) .addField('❯ Home Server', `[Here](https://${this.client.options.invite})`, true) .addField('❯ Invite', diff --git a/commands/util/uptime.js b/commands/util/uptime.js index a20e40fa..773fd4f6 100644 --- a/commands/util/uptime.js +++ b/commands/util/uptime.js @@ -7,7 +7,7 @@ module.exports = class UptimeCommand extends Command { name: 'uptime', group: 'util', memberName: 'uptime', - description: 'Responds with how long the bot has been active on this Shard.', + description: 'Responds with how long the bot has been active.', guarded: true }); } diff --git a/package.json b/package.json index 4ea83679..0b40e45c 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "xiaobot", - "version": "49.2.2", + "version": "49.3.0", "description": "Your personal server companion.", - "main": "Shard.js", + "main": "XiaoBot.js", "scripts": { "test": "npm run lint", "lint": "eslint . --ext .js --ext .json", - "start": "node Shard.js" + "start": "node XiaoBot.js" }, "repository": { "type": "git", diff --git a/util/Util.js b/util/Util.js index e05da1f8..f2d3deaf 100644 --- a/util/Util.js +++ b/util/Util.js @@ -103,7 +103,7 @@ class Util { max: 1, time }); - if (!verify.size) return false; + if (!verify.size) return 0; const choice = verify.first().content.toLowerCase(); if (yes.includes(choice)) return true; if (no.includes(choice)) return false;