Files
xiao/commands/games-mp/imposter.js
T
2020-09-17 14:55:54 -04:00

155 lines
5.3 KiB
JavaScript

const Command = require('../../structures/Command');
const { stripIndents } = require('common-tags');
const Collection = require('@discordjs/collection');
const { delay, awaitPlayers, list } = require('../../util/Util');
const words = require('../../assets/json/imposter');
module.exports = class ImposterCommand extends Command {
constructor(client) {
super(client, {
name: 'imposter',
aliases: ['among-us'],
group: 'games-mp',
memberName: 'imposter',
description: 'Who is the imposter among us?',
guildOnly: true,
clientPermissions: ['ADD_REACTIONS', 'READ_MESSAGE_HISTORY'],
args: [
{
key: 'playersCount',
label: 'players',
prompt: 'How many players are you expecting to have?',
type: 'integer',
min: 3,
max: 20
}
]
});
}
async run(msg, { playersCount }) {
const current = this.client.games.get(msg.channel.id);
if (current) return msg.reply(`Please wait until the current game of \`${current.name}\` is finished.`);
this.client.games.set(msg.channel.id, { name: this.name });
try {
const awaitedPlayers = await awaitPlayers(msg, playersCount, 3);
if (!awaitedPlayers) {
this.client.games.delete(msg.channel.id);
return msg.say('Game could not be started...');
}
const word = words[Math.floor(Math.random() * words.length)];
const wordRegex = new RegExp(`\\b${word}\\b`, 'i');
const players = new Collection();
const imposter = awaitedPlayers[Math.floor(Math.random() * awaitedPlayers.length)];
for (const player of awaitedPlayers) {
players.set(player, {
id: player,
user: await this.client.users.fetch(player),
killed: false,
imposter: imposter === player
});
const newPlayer = players.get(player);
if (imposter === player) newPlayer.user.send(`You are the imposter. The kill word is ${word}.`);
else newPlayer.user.send('You are not the imposter.');
}
let lastTurnTimeout = false;
const winners = [];
while (players.some(player => !player.killed) > 2) {
++turn;
const playersLeft = players.filter(player => !player.killed).size;
await msg.say(`There are **${playersLeft}** players left. Talk until someone says the kill word.`);
const filter = res => {
const player = players.get(res.author.id);
if (!player || player.killed || player.imposter) return false;
if (res.content && wordRegex.test(res.content)) return true;
return false;
};
const msgs = await msg.channel.awaitMessages(filter, {
max: 1,
time: 600000
});
if (msgs.size) {
const killedMsg = msgs.first();
try {
await killedMsg.react('🔪');
} catch {
await killedMsg.reply('🔪');
}
players.get(killedMsg.author.id).killed = true;
await msg.say(stripIndents`
${killedMsg.author} has been murdered for saying the kill word!
Talk amongst yourselves, who is the imposter? Voting begins in 1 minute.
`);
} else {
await msg.say(stripIndents`
No has said the word for 10 minutes. We're voting anyway! Who looks suspicious?
Talk amongst yourselves, who is the imposter? Voting begins in 1 minute.
`);
}
await delay(60000);
const choices = players.filter(player => !player.killed);
await msg.say(stripIndents`
Alright, who do you think the imposter is? You have 1 minute to vote.
_Type the number of the player you think is the imposter._
${choices.map((player, i) => `**${i + 1}.** ${player.user.tag}`).join('\n')}
`)
const votes = new Collection();
const voteFilter = res => {
const player = players.get(res.author.id);
if (!player || player.killed) return false;
const int = Number.parseInt(res.content, 10);
if (int >= 1 && int <= players.filter(player => !player.killed).size) {
const currentVotes = votes.get(choices[int - 1]);
votes.set(ids[int - 1], {
votes: currentVotes ? currentVotes + 1 : 1,
id: ids[int - 1]
});
res.react(SUCCESS_EMOJI_ID || '✅').catch(() => null);
return true;
}
return false;
};
const vote = await msg.channel.awaitMessages(voteFilter, {
max: players.filter(player => !player.killed).size,
time: 60000
});
if (!vote.size) {
if (lastTurnTimeout) {
await msg.say('Game ended due to inactivity.');
break;
} else {
await msg.say('Come on guys, get in the game!');
lastTurnTimeout = true;
continue;
}
}
const kicked = players.get(votes.sort((a, b) => b.votes - a.votes).first().id);
players.get(kicked.id).killed = true;
if (kicked.id === players.find(player => player.imposter).id) {
await msg.say(`**${kicked.user.tag}** was the imposter.`);
winners.push(...players.filter(player => !player.killed).map(player => player.user.tag));
break;
}
const amountLeft = players.filter(player => !player.killed);
await msg.say(stripIndents`
**${kicked.user.tag}** was not the imposter.
${amountLeft.size > 2 ? '_Next round starts in 30 seconds._' : ''}
`);
if (amountLeft.size > 2) {
await delay(30000);
} else {
winners.push(players.find(player => player.imposter).user.tag);
break;
}
}
this.client.games.delete(msg.channel.id);
return msg.say(`Congrats, ${list(winners)}! The kill word was **${word}**.`);
} catch (err) {
this.client.games.delete(msg.channel.id);
throw err;
}
}
};