mirror of
https://github.com/arthur-pbty/xiao.git
synced 2026-06-03 23:36:43 +02:00
Finish removing "Oh no, an error occurred"
This commit is contained in:
@@ -14,6 +14,7 @@ module.exports = class ApplesToApplesCommand extends Command {
|
||||
memberName: 'apples-to-apples',
|
||||
description: 'Compete to see who can come up with the best card to match an adjective.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
clientPermissions: ['ADD_REACTIONS', 'READ_MESSAGE_HISTORY'],
|
||||
credit: [
|
||||
{
|
||||
@@ -52,17 +53,10 @@ module.exports = class ApplesToApplesCommand extends Command {
|
||||
|
||||
async run(msg, { maxPts, flags }) {
|
||||
const bot = flags.bot || flags.b;
|
||||
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,
|
||||
new Game(this.client, this.name, msg.channel, redCards, greenCards, 'Green'));
|
||||
const game = this.client.games.get(msg.channel.id);
|
||||
const game = new Game(this.client, this.name, msg.channel, redCards, greenCards, 'Green');
|
||||
try {
|
||||
const awaitedPlayers = await game.awaitPlayers(msg, bot);
|
||||
if (!awaitedPlayers) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Game could not be started...');
|
||||
}
|
||||
if (!awaitedPlayers) return msg.say('Game could not be started...');
|
||||
game.createJoinLeaveCollector(msg.channel, game);
|
||||
while (!game.winner) {
|
||||
const czar = game.changeCzar();
|
||||
@@ -133,13 +127,11 @@ module.exports = class ApplesToApplesCommand extends Command {
|
||||
}
|
||||
}
|
||||
game.stopJoinLeaveCollector();
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!game.winner) return msg.say('See you next time!');
|
||||
return msg.say(`And the winner is... ${game.winner}! Great job!`);
|
||||
} catch (err) {
|
||||
game.stopJoinLeaveCollector();
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ module.exports = class BalloonPopCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'balloon-pop',
|
||||
description: 'Don\'t let yourself be the last one to pump the balloon before it pops!',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'PAC-MAN Party',
|
||||
@@ -29,64 +30,52 @@ module.exports = class BalloonPopCommand extends Command {
|
||||
}
|
||||
|
||||
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, 2, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Game could not be started...');
|
||||
const awaitedPlayers = await awaitPlayers(msg, playersCount, 2, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) return msg.say('Game could not be started...');
|
||||
const players = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
pumps: 0,
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
let loser = null;
|
||||
let remains = players.size * 250;
|
||||
let turns = 0;
|
||||
const rotation = players.map(player => player.id);
|
||||
while (!loser) {
|
||||
const user = players.get(rotation[0]);
|
||||
let pump;
|
||||
++turns;
|
||||
if (turns === 1) {
|
||||
await msg.say(`${user.user} pumps the balloon!`);
|
||||
pump = true;
|
||||
} else {
|
||||
await msg.say(`${user.user}, do you pump the balloon again?`);
|
||||
pump = await verify(msg.channel, user.user);
|
||||
}
|
||||
const players = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
pumps: 0,
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
let loser = null;
|
||||
let remains = players.size * 250;
|
||||
let turns = 0;
|
||||
const rotation = players.map(player => player.id);
|
||||
while (!loser) {
|
||||
const user = players.get(rotation[0]);
|
||||
let pump;
|
||||
++turns;
|
||||
if (turns === 1) {
|
||||
await msg.say(`${user.user} pumps the balloon!`);
|
||||
pump = true;
|
||||
} else {
|
||||
await msg.say(`${user.user}, do you pump the balloon again?`);
|
||||
pump = await verify(msg.channel, user.user);
|
||||
if (pump) {
|
||||
remains -= randomRange(10, 100);
|
||||
const popped = Math.floor(Math.random() * remains);
|
||||
if (popped <= 0) {
|
||||
await msg.say('The balloon pops!');
|
||||
loser = user;
|
||||
break;
|
||||
}
|
||||
if (pump) {
|
||||
remains -= randomRange(10, 100);
|
||||
const popped = Math.floor(Math.random() * remains);
|
||||
if (popped <= 0) {
|
||||
await msg.say('The balloon pops!');
|
||||
loser = user;
|
||||
break;
|
||||
}
|
||||
if (turns >= 5) {
|
||||
await msg.say(`${user.user} steps back!`);
|
||||
turns = 0;
|
||||
rotation.shift();
|
||||
rotation.push(user.id);
|
||||
}
|
||||
} else {
|
||||
if (turns >= 5) {
|
||||
await msg.say(`${user.user} steps back!`);
|
||||
turns = 0;
|
||||
rotation.shift();
|
||||
rotation.push(user.id);
|
||||
}
|
||||
} else {
|
||||
await msg.say(`${user.user} steps back!`);
|
||||
turns = 0;
|
||||
rotation.shift();
|
||||
rotation.push(user.id);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say(`And the loser is... ${loser.user}! Great job everyone else!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
return msg.say(`And the loser is... ${loser.user}! Great job everyone else!`);
|
||||
}
|
||||
};
|
||||
|
||||
+63
-74
@@ -10,6 +10,7 @@ module.exports = class BattleCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'battle',
|
||||
description: 'Engage in a turn-based battle against another user or the AI.',
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -22,80 +23,68 @@ module.exports = class BattleCommand extends Command {
|
||||
async run(msg, { opponent }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not battle yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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, data: new Battle(msg.author, opponent) });
|
||||
const battle = this.client.games.get(msg.channel.id).data;
|
||||
try {
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
}
|
||||
while (!battle.winner) {
|
||||
const choice = await battle.attacker.chooseAction(msg);
|
||||
if (choice === 'attack') {
|
||||
const damage = randomRange(battle.defender.guard ? 5 : 20, battle.defender.guard ? 20 : 50);
|
||||
await msg.say(`${battle.attacker} deals **${damage}** damage!`);
|
||||
battle.defender.dealDamage(damage);
|
||||
battle.reset();
|
||||
} else if (choice === 'defend') {
|
||||
await msg.say(`${battle.attacker} defends!`);
|
||||
battle.attacker.changeGuard();
|
||||
battle.reset(false);
|
||||
} else if (choice === 'special') {
|
||||
const miss = Math.floor(Math.random() * 5);
|
||||
if (miss === 0 || miss === 3) {
|
||||
await msg.say(`${battle.attacker}'s special attack missed!`);
|
||||
} else if (miss === 1 || miss === 5) {
|
||||
const damage = randomRange(battle.defender.guard ? 10 : 40, battle.defender.guard ? 40 : 100);
|
||||
await msg.say(`${battle.attacker}'s special attack grazed the opponent, dealing **${damage}** damage!`);
|
||||
battle.defender.dealDamage(damage);
|
||||
} else if (miss === 2) {
|
||||
const damage = randomRange(battle.defender.guard ? 20 : 80, battle.defender.guard ? 80 : 200);
|
||||
await msg.say(`${battle.attacker}'s special attack hit directly, dealing **${damage}** damage!`);
|
||||
battle.defender.dealDamage(damage);
|
||||
}
|
||||
battle.attacker.useMP(25);
|
||||
battle.reset();
|
||||
} else if (choice === 'cure') {
|
||||
const amount = Math.round(battle.attacker.mp / 2);
|
||||
await msg.say(`${battle.attacker} heals **${amount}** HP!`);
|
||||
battle.attacker.heal(amount);
|
||||
battle.attacker.useMP(battle.attacker.mp);
|
||||
battle.reset();
|
||||
} else if (choice === 'final') {
|
||||
await msg.say(`${battle.attacker} uses their final move, dealing **100** damage!`);
|
||||
battle.defender.dealDamage(100);
|
||||
battle.attacker.useMP(50);
|
||||
battle.attacker.usedFinal = true;
|
||||
battle.reset();
|
||||
} else if (choice === 'run') {
|
||||
await msg.say(`${battle.attacker} flees!`);
|
||||
battle.attacker.forfeit();
|
||||
} else if (choice === 'failed:time') {
|
||||
await msg.say(`Time's up, ${battle.attacker}!`);
|
||||
battle.reset();
|
||||
if (battle.lastTurnTimeout) {
|
||||
battle.endedDueToInactivity = true;
|
||||
break;
|
||||
} else {
|
||||
battle.lastTurnTimeout = true;
|
||||
}
|
||||
} else {
|
||||
await msg.say('I do not understand what you want to do.');
|
||||
}
|
||||
if (choice !== 'failed:time' && battle.lastTurnTimeout) battle.lastTurnTimeout = false;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (battle.winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(`The match is over! Congrats, ${battle.winner}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const battle = new Battle(msg.author, opponent);
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
}
|
||||
while (!battle.winner) {
|
||||
const choice = await battle.attacker.chooseAction(msg);
|
||||
if (choice === 'attack') {
|
||||
const damage = randomRange(battle.defender.guard ? 5 : 20, battle.defender.guard ? 20 : 50);
|
||||
await msg.say(`${battle.attacker} deals **${damage}** damage!`);
|
||||
battle.defender.dealDamage(damage);
|
||||
battle.reset();
|
||||
} else if (choice === 'defend') {
|
||||
await msg.say(`${battle.attacker} defends!`);
|
||||
battle.attacker.changeGuard();
|
||||
battle.reset(false);
|
||||
} else if (choice === 'special') {
|
||||
const miss = Math.floor(Math.random() * 5);
|
||||
if (miss === 0 || miss === 3) {
|
||||
await msg.say(`${battle.attacker}'s special attack missed!`);
|
||||
} else if (miss === 1 || miss === 5) {
|
||||
const damage = randomRange(battle.defender.guard ? 10 : 40, battle.defender.guard ? 40 : 100);
|
||||
await msg.say(`${battle.attacker}'s special attack grazed the opponent, dealing **${damage}** damage!`);
|
||||
battle.defender.dealDamage(damage);
|
||||
} else if (miss === 2) {
|
||||
const damage = randomRange(battle.defender.guard ? 20 : 80, battle.defender.guard ? 80 : 200);
|
||||
await msg.say(`${battle.attacker}'s special attack hit directly, dealing **${damage}** damage!`);
|
||||
battle.defender.dealDamage(damage);
|
||||
}
|
||||
battle.attacker.useMP(25);
|
||||
battle.reset();
|
||||
} else if (choice === 'cure') {
|
||||
const amount = Math.round(battle.attacker.mp / 2);
|
||||
await msg.say(`${battle.attacker} heals **${amount}** HP!`);
|
||||
battle.attacker.heal(amount);
|
||||
battle.attacker.useMP(battle.attacker.mp);
|
||||
battle.reset();
|
||||
} else if (choice === 'final') {
|
||||
await msg.say(`${battle.attacker} uses their final move, dealing **100** damage!`);
|
||||
battle.defender.dealDamage(100);
|
||||
battle.attacker.useMP(50);
|
||||
battle.attacker.usedFinal = true;
|
||||
battle.reset();
|
||||
} else if (choice === 'run') {
|
||||
await msg.say(`${battle.attacker} flees!`);
|
||||
battle.attacker.forfeit();
|
||||
} else if (choice === 'failed:time') {
|
||||
await msg.say(`Time's up, ${battle.attacker}!`);
|
||||
battle.reset();
|
||||
if (battle.lastTurnTimeout) {
|
||||
battle.endedDueToInactivity = true;
|
||||
break;
|
||||
} else {
|
||||
battle.lastTurnTimeout = true;
|
||||
}
|
||||
} else {
|
||||
await msg.say('I do not understand what you want to do.');
|
||||
}
|
||||
if (choice !== 'failed:time' && battle.lastTurnTimeout) battle.lastTurnTimeout = false;
|
||||
}
|
||||
if (battle.winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(`The match is over! Congrats, ${battle.winner}!`);
|
||||
}
|
||||
};
|
||||
|
||||
+60
-71
@@ -15,6 +15,7 @@ module.exports = class BingoCommand extends Command {
|
||||
memberName: 'bingo',
|
||||
description: 'Play bingo with up to 99 other users.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'playersCount',
|
||||
@@ -27,78 +28,66 @@ module.exports = class BingoCommand extends Command {
|
||||
}
|
||||
|
||||
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, 1, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Game could not be started...');
|
||||
}
|
||||
const players = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
board: this.generateBoard(),
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
let winner = null;
|
||||
const called = ['FR'];
|
||||
while (!winner) {
|
||||
const validNums = callNums.filter(num => !called.includes(num));
|
||||
if (!validNums.length) break;
|
||||
const picked = validNums[Math.floor(Math.random() * validNums.length)];
|
||||
called.push(picked);
|
||||
for (const player of players.values()) {
|
||||
try {
|
||||
await player.user.send(stripIndents`
|
||||
**${this.findRowValue(picked)} ${picked}** was called in ${msg.channel}.
|
||||
${this.generateBoardDisplay(player.board, called)}
|
||||
`);
|
||||
} catch {
|
||||
await msg.say(`${player.user}, I couldn't send your board! Turn on DMs!`);
|
||||
}
|
||||
}
|
||||
await msg.say(stripIndents`
|
||||
**${this.findRowValue(picked)} ${picked}**!
|
||||
|
||||
Check your DMs for your board. If you have bingo, type \`bingo\`!
|
||||
If you wish to drop out, type \`leave game\`.
|
||||
_Next number will be called in 20 seconds. ${validNums.length - 1} numbers left._
|
||||
`);
|
||||
const filter = res => {
|
||||
if (!players.has(res.author.id)) return false;
|
||||
if (res.content.toLowerCase() === 'leave game') {
|
||||
players.delete(res.author.id);
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
if (!players.size) return true;
|
||||
return false;
|
||||
}
|
||||
if (res.content.toLowerCase() !== 'bingo') return false;
|
||||
if (!this.checkBingo(players.get(res.author.id).board, called)) {
|
||||
msg.say(`${res.author}, you don't have bingo, liar.`).catch(() => null);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const bingo = await msg.channel.awaitMessages({ filter, max: 1, time: 20000 });
|
||||
if (!players.size) {
|
||||
winner = 0;
|
||||
break;
|
||||
}
|
||||
if (!bingo.size) continue;
|
||||
winner = bingo.first().author;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner === 0) return msg.say('Everyone dropped out...');
|
||||
if (!winner) return msg.say('I called the entire board, but no one called bingo...');
|
||||
return msg.say(`Congrats, ${winner}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const awaitedPlayers = await awaitPlayers(msg, playersCount, 1, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) return msg.say('Game could not be started...');
|
||||
const players = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
board: this.generateBoard(),
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
let winner = null;
|
||||
const called = ['FR'];
|
||||
while (!winner) {
|
||||
const validNums = callNums.filter(num => !called.includes(num));
|
||||
if (!validNums.length) break;
|
||||
const picked = validNums[Math.floor(Math.random() * validNums.length)];
|
||||
called.push(picked);
|
||||
for (const player of players.values()) {
|
||||
try {
|
||||
await player.user.send(stripIndents`
|
||||
**${this.findRowValue(picked)} ${picked}** was called in ${msg.channel}.
|
||||
${this.generateBoardDisplay(player.board, called)}
|
||||
`);
|
||||
} catch {
|
||||
await msg.say(`${player.user}, I couldn't send your board! Turn on DMs!`);
|
||||
}
|
||||
}
|
||||
await msg.say(stripIndents`
|
||||
**${this.findRowValue(picked)} ${picked}**!
|
||||
|
||||
Check your DMs for your board. If you have bingo, type \`bingo\`!
|
||||
If you wish to drop out, type \`leave game\`.
|
||||
_Next number will be called in 20 seconds. ${validNums.length - 1} numbers left._
|
||||
`);
|
||||
const filter = res => {
|
||||
if (!players.has(res.author.id)) return false;
|
||||
if (res.content.toLowerCase() === 'leave game') {
|
||||
players.delete(res.author.id);
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
if (!players.size) return true;
|
||||
return false;
|
||||
}
|
||||
if (res.content.toLowerCase() !== 'bingo') return false;
|
||||
if (!this.checkBingo(players.get(res.author.id).board, called)) {
|
||||
msg.say(`${res.author}, you don't have bingo, liar.`).catch(() => null);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const bingo = await msg.channel.awaitMessages({ filter, max: 1, time: 20000 });
|
||||
if (!players.size) {
|
||||
winner = 0;
|
||||
break;
|
||||
}
|
||||
if (!bingo.size) continue;
|
||||
winner = bingo.first().author;
|
||||
}
|
||||
if (winner === 0) return msg.say('Everyone dropped out...');
|
||||
if (!winner) return msg.say('I called the entire board, but no one said bingo...');
|
||||
return msg.say(`Congrats, ${winner}!`);
|
||||
}
|
||||
|
||||
generateBoard() {
|
||||
|
||||
+124
-139
@@ -25,6 +25,7 @@ module.exports = class CarRaceCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'car-race',
|
||||
description: 'Race a car against another user or the AI.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'iStock',
|
||||
@@ -352,9 +353,6 @@ module.exports = class CarRaceCommand extends Command {
|
||||
async run(msg, { opponent, car }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 });
|
||||
const bg = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'car-race', 'bg.png'));
|
||||
const userData = {
|
||||
user: msg.author,
|
||||
@@ -370,147 +368,134 @@ module.exports = class CarRaceCommand extends Command {
|
||||
const userAvatar = await request.get(msg.author.displayAvatarURL({ format: 'png', size: 128 }));
|
||||
userData.avatar = await loadImage(userAvatar.body);
|
||||
let difficulty;
|
||||
try {
|
||||
const available = cars.filter(car2 => car !== car2);
|
||||
if (opponent.bot) {
|
||||
await msg.reply(`What difficulty do you want to use? Either ${list(Object.keys(difficulties), 'or')}.`);
|
||||
const difficultyFilter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
return Object.keys(difficulties).includes(res.content.toLowerCase());
|
||||
};
|
||||
const difficultyPick = await msg.channel.awaitMessages({
|
||||
filter: difficultyFilter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!difficultyPick.size) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Failed to pick difficulty. Aborted command.');
|
||||
}
|
||||
difficulty = difficultyPick.first().content.toLowerCase();
|
||||
const oppoCarPick = available[Math.floor(Math.random() * available.length)];
|
||||
const available = cars.filter(car2 => car !== car2);
|
||||
if (opponent.bot) {
|
||||
await msg.reply(`What difficulty do you want to use? Either ${list(Object.keys(difficulties), 'or')}.`);
|
||||
const difficultyFilter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
return Object.keys(difficulties).includes(res.content.toLowerCase());
|
||||
};
|
||||
const difficultyPick = await msg.channel.awaitMessages({
|
||||
filter: difficultyFilter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!difficultyPick.size) return msg.say('Failed to pick difficulty. Aborted command.');
|
||||
difficulty = difficultyPick.first().content.toLowerCase();
|
||||
const oppoCarPick = available[Math.floor(Math.random() * available.length)];
|
||||
oppoData.car = await loadImage(
|
||||
path.join(__dirname, '..', '..', 'assets', 'images', 'car-race', 'cars', `${oppoCarPick}.png`)
|
||||
);
|
||||
} else {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
await msg.say(`${opponent}, what car do you want to be? Either ${list(available, 'or')}.`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== opponent.id) return false;
|
||||
return available.includes(res.content.toLowerCase());
|
||||
};
|
||||
const p2Car = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (p2Car.size) {
|
||||
const choice = p2Car.first().content.toLowerCase();
|
||||
oppoData.car = await loadImage(
|
||||
path.join(__dirname, '..', '..', 'assets', 'images', 'car-race', 'cars', `${oppoCarPick}.png`)
|
||||
path.join(__dirname, '..', '..', 'assets', 'images', 'car-race', 'cars', `${choice}.png`)
|
||||
);
|
||||
} else {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
await msg.say(`${opponent}, what car do you want to be? Either ${list(available, 'or')}.`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== opponent.id) return false;
|
||||
return available.includes(res.content.toLowerCase());
|
||||
};
|
||||
const p2Car = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (p2Car.size) {
|
||||
const choice = p2Car.first().content.toLowerCase();
|
||||
oppoData.car = await loadImage(
|
||||
path.join(__dirname, '..', '..', 'assets', 'images', 'car-race', 'cars', `${choice}.png`)
|
||||
);
|
||||
} else {
|
||||
const chosen = cars[Math.floor(Math.random() * cars.length)];
|
||||
oppoData.car = await loadImage(
|
||||
path.join(__dirname, '..', '..', 'assets', 'images', 'car-race', 'cars', `${chosen}.png`)
|
||||
);
|
||||
}
|
||||
const chosen = cars[Math.floor(Math.random() * cars.length)];
|
||||
oppoData.car = await loadImage(
|
||||
path.join(__dirname, '..', '..', 'assets', 'images', 'car-race', 'cars', `${chosen}.png`)
|
||||
);
|
||||
}
|
||||
const oppoAvatar = await request.get(opponent.displayAvatarURL({ format: 'png', size: 128 }));
|
||||
oppoData.avatar = await loadImage(oppoAvatar.body);
|
||||
let lastRoundWinner;
|
||||
let lastTurnTimeout = false;
|
||||
while (userData.spaces < 7 && oppoData.spaces < 7) {
|
||||
const board = await this.generateBoard(bg, userData, oppoData, lastRoundWinner);
|
||||
let text;
|
||||
if (lastRoundWinner) {
|
||||
if (userData.spaces > oppoData.spaces || oppoData.spaces > userData.spaces) {
|
||||
const leader = userData.spaces > oppoData.spaces ? msg.author : opponent;
|
||||
if (leader.id === lastRoundWinner.id) text = `${lastRoundWinner} pulls ahead!`;
|
||||
else text = `${lastRoundWinner} catches up!`;
|
||||
} else if (userData.spaces === oppoData.spaces) {
|
||||
text = `${lastRoundWinner} ties it up!`;
|
||||
}
|
||||
} else {
|
||||
text = stripIndents`
|
||||
Welcome to \`car-race\`! Whenever a message pops up, type the word provided.
|
||||
Whoever types the word first advances their car!
|
||||
Either player can type \`end\` at any time to end the game.
|
||||
`;
|
||||
}
|
||||
await msg.say(`${text}\nGet Ready...`, { files: [{ attachment: board, name: 'car-race.png' }] });
|
||||
const earlyFilter = res => {
|
||||
if (![opponent.id, msg.author.id].includes(res.author.id)) return false;
|
||||
return res.content.toLowerCase() === 'end';
|
||||
};
|
||||
const earlyEnd = await msg.channel.awaitMessages({
|
||||
filter: earlyFilter,
|
||||
max: 1,
|
||||
time: randomRange(1000, 30000)
|
||||
});
|
||||
if (earlyEnd.size) {
|
||||
if (earlyEnd.first().author.id === msg.author.id) oppoData.spaces = 7;
|
||||
else if (earlyEnd.first().author.id === opponent.id) userData.spaces = 7;
|
||||
break;
|
||||
}
|
||||
const word = words[Math.floor(Math.random() * words.length)];
|
||||
await msg.say(`TYPE \`${word.toUpperCase()}\` NOW!`);
|
||||
const turnFilter = res => {
|
||||
if (![opponent.id, msg.author.id].includes(res.author.id)) return false;
|
||||
if (res.content.toLowerCase() === 'end') return true;
|
||||
return res.content.toLowerCase() === word;
|
||||
};
|
||||
const winner = await msg.channel.awaitMessages({
|
||||
filter: turnFilter,
|
||||
max: 1,
|
||||
time: opponent.bot ? difficulties[difficulty] : 30000
|
||||
});
|
||||
if (!winner.size) {
|
||||
if (opponent.bot) {
|
||||
oppoData.spaces += 1;
|
||||
lastRoundWinner = opponent;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
continue;
|
||||
} else if (lastTurnTimeout) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Game ended due to inactivity.');
|
||||
} else {
|
||||
await msg.say('Come on, get your head in the game!');
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const win = winner.first();
|
||||
if (win.content.toLowerCase() === 'end') {
|
||||
if (win.author.id === msg.author.id) {
|
||||
oppoData.spaces = 7;
|
||||
lastRoundWinner = opponent;
|
||||
} else if (win.author.id === opponent.id) {
|
||||
userData.spaces = 7;
|
||||
lastRoundWinner = msg.author;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (win.author.id === msg.author.id) userData.spaces += 1;
|
||||
else if (win.author.id === opponent.id) oppoData.spaces += 1;
|
||||
lastRoundWinner = win.author;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
const winner = userData.spaces > oppoData.spaces ? msg.author : opponent;
|
||||
const board = await this.generateBoard(bg, userData, oppoData, lastRoundWinner, winner);
|
||||
return msg.say(`Congrats, ${winner}!`, {
|
||||
files: [{ attachment: board, name: 'car-race-win.png' }]
|
||||
});
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
const oppoAvatar = await request.get(opponent.displayAvatarURL({ format: 'png', size: 128 }));
|
||||
oppoData.avatar = await loadImage(oppoAvatar.body);
|
||||
let lastRoundWinner;
|
||||
let lastTurnTimeout = false;
|
||||
while (userData.spaces < 7 && oppoData.spaces < 7) {
|
||||
const board = await this.generateBoard(bg, userData, oppoData, lastRoundWinner);
|
||||
let text;
|
||||
if (lastRoundWinner) {
|
||||
if (userData.spaces > oppoData.spaces || oppoData.spaces > userData.spaces) {
|
||||
const leader = userData.spaces > oppoData.spaces ? msg.author : opponent;
|
||||
if (leader.id === lastRoundWinner.id) text = `${lastRoundWinner} pulls ahead!`;
|
||||
else text = `${lastRoundWinner} catches up!`;
|
||||
} else if (userData.spaces === oppoData.spaces) {
|
||||
text = `${lastRoundWinner} ties it up!`;
|
||||
}
|
||||
} else {
|
||||
text = stripIndents`
|
||||
Welcome to \`car-race\`! Whenever a message pops up, type the word provided.
|
||||
Whoever types the word first advances their car!
|
||||
Either player can type \`end\` at any time to end the game.
|
||||
`;
|
||||
}
|
||||
await msg.say(`${text}\nGet Ready...`, { files: [{ attachment: board, name: 'car-race.png' }] });
|
||||
const earlyFilter = res => {
|
||||
if (![opponent.id, msg.author.id].includes(res.author.id)) return false;
|
||||
return res.content.toLowerCase() === 'end';
|
||||
};
|
||||
const earlyEnd = await msg.channel.awaitMessages({
|
||||
filter: earlyFilter,
|
||||
max: 1,
|
||||
time: randomRange(1000, 30000)
|
||||
});
|
||||
if (earlyEnd.size) {
|
||||
if (earlyEnd.first().author.id === msg.author.id) oppoData.spaces = 7;
|
||||
else if (earlyEnd.first().author.id === opponent.id) userData.spaces = 7;
|
||||
break;
|
||||
}
|
||||
const word = words[Math.floor(Math.random() * words.length)];
|
||||
await msg.say(`TYPE \`${word.toUpperCase()}\` NOW!`);
|
||||
const turnFilter = res => {
|
||||
if (![opponent.id, msg.author.id].includes(res.author.id)) return false;
|
||||
if (res.content.toLowerCase() === 'end') return true;
|
||||
return res.content.toLowerCase() === word;
|
||||
};
|
||||
const winner = await msg.channel.awaitMessages({
|
||||
filter: turnFilter,
|
||||
max: 1,
|
||||
time: opponent.bot ? difficulties[difficulty] : 30000
|
||||
});
|
||||
if (!winner.size) {
|
||||
if (opponent.bot) {
|
||||
oppoData.spaces += 1;
|
||||
lastRoundWinner = opponent;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
continue;
|
||||
} else if (lastTurnTimeout) {
|
||||
return msg.say('Game ended due to inactivity.');
|
||||
} else {
|
||||
await msg.say('Come on, get your head in the game!');
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const win = winner.first();
|
||||
if (win.content.toLowerCase() === 'end') {
|
||||
if (win.author.id === msg.author.id) {
|
||||
oppoData.spaces = 7;
|
||||
lastRoundWinner = opponent;
|
||||
} else if (win.author.id === opponent.id) {
|
||||
userData.spaces = 7;
|
||||
lastRoundWinner = msg.author;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (win.author.id === msg.author.id) userData.spaces += 1;
|
||||
else if (win.author.id === opponent.id) oppoData.spaces += 1;
|
||||
lastRoundWinner = win.author;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
const winner = userData.spaces > oppoData.spaces ? msg.author : opponent;
|
||||
const board = await this.generateBoard(bg, userData, oppoData, lastRoundWinner, winner);
|
||||
return msg.say(`Congrats, ${winner}!`, {
|
||||
files: [{ attachment: board, name: 'car-race-win.png' }]
|
||||
});
|
||||
}
|
||||
|
||||
async generateBoard(bg, userData, oppoData, turnWin, win) {
|
||||
|
||||
@@ -15,6 +15,7 @@ module.exports = class CardsAgainstHumanityCommand extends Command {
|
||||
description: 'Compete to see who can come up with the best card to fill in the blank.',
|
||||
guildOnly: true,
|
||||
nsfw: true,
|
||||
game: true,
|
||||
clientPermissions: ['ADD_REACTIONS', 'READ_MESSAGE_HISTORY'],
|
||||
credit: [
|
||||
{
|
||||
@@ -52,17 +53,10 @@ module.exports = class CardsAgainstHumanityCommand extends Command {
|
||||
|
||||
async run(msg, { maxPts, flags }) {
|
||||
const bot = flags.bot || flags.b;
|
||||
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,
|
||||
new Game(this.client, this.name, msg.channel, whiteCards, blackCards, 'Black'));
|
||||
const game = this.client.games.get(msg.channel.id);
|
||||
const game = new Game(this.client, this.name, msg.channel, whiteCards, blackCards, 'Black');
|
||||
try {
|
||||
const awaitedPlayers = await game.awaitPlayers(msg, bot);
|
||||
if (!awaitedPlayers) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Game could not be started...');
|
||||
}
|
||||
if (!awaitedPlayers) return msg.say('Game could not be started...');
|
||||
game.createJoinLeaveCollector(msg.channel, game);
|
||||
while (!game.winner) {
|
||||
const czar = game.changeCzar();
|
||||
@@ -133,13 +127,11 @@ module.exports = class CardsAgainstHumanityCommand extends Command {
|
||||
}
|
||||
}
|
||||
game.stopJoinLeaveCollector();
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!game.winner) return msg.say('See you next time!');
|
||||
return msg.say(`And the winner is... ${game.winner}! Great job!`);
|
||||
} catch (err) {
|
||||
game.stopJoinLeaveCollector();
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+139
-152
@@ -19,6 +19,7 @@ module.exports = class ChessCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'chess',
|
||||
description: 'Play a game of Chess with another user or the AI.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'PNGkey.com',
|
||||
@@ -58,169 +59,155 @@ module.exports = class ChessCommand extends Command {
|
||||
async run(msg, { opponent, time, fen }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 });
|
||||
if (!this.images) await this.loadImages();
|
||||
try {
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
}
|
||||
const resumeGame = await this.client.redis.get(`chess-${msg.author.id}`);
|
||||
let game;
|
||||
let whiteTime = time === 0 ? Infinity : time * 60000;
|
||||
let blackTime = time === 0 ? Infinity : time * 60000;
|
||||
let whitePlayer = msg.author;
|
||||
let blackPlayer = opponent;
|
||||
if (resumeGame) {
|
||||
await msg.reply(stripIndents`
|
||||
You have a saved game, do you want to resume it?
|
||||
**This will delete your saved game.**
|
||||
`);
|
||||
const verification = await verify(msg.channel, msg.author);
|
||||
if (verification) {
|
||||
try {
|
||||
const data = JSON.parse(resumeGame);
|
||||
game = new jsChess.Game(data.fen);
|
||||
whiteTime = data.whiteTime === -1 ? Infinity : data.whiteTime;
|
||||
blackTime = data.blackTime === -1 ? Infinity : data.blackTime;
|
||||
whitePlayer = data.color === 'white' ? msg.author : opponent;
|
||||
blackPlayer = data.color === 'black' ? msg.author : opponent;
|
||||
await this.client.redis.del(`chess-${msg.author.id}`);
|
||||
} catch {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
await this.client.redis.del(`chess-${msg.author.id}`);
|
||||
return msg.reply('An error occurred reading your saved game. Please try again.');
|
||||
}
|
||||
} else {
|
||||
game = new jsChess.Game(fen || undefined);
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
}
|
||||
const resumeGame = await this.client.redis.get(`chess-${msg.author.id}`);
|
||||
let game;
|
||||
let whiteTime = time === 0 ? Infinity : time * 60000;
|
||||
let blackTime = time === 0 ? Infinity : time * 60000;
|
||||
let whitePlayer = msg.author;
|
||||
let blackPlayer = opponent;
|
||||
if (resumeGame) {
|
||||
await msg.reply(stripIndents`
|
||||
You have a saved game, do you want to resume it?
|
||||
**This will delete your saved game.**
|
||||
`);
|
||||
const verification = await verify(msg.channel, msg.author);
|
||||
if (verification) {
|
||||
try {
|
||||
const data = JSON.parse(resumeGame);
|
||||
game = new jsChess.Game(data.fen);
|
||||
whiteTime = data.whiteTime === -1 ? Infinity : data.whiteTime;
|
||||
blackTime = data.blackTime === -1 ? Infinity : data.blackTime;
|
||||
whitePlayer = data.color === 'white' ? msg.author : opponent;
|
||||
blackPlayer = data.color === 'black' ? msg.author : opponent;
|
||||
await this.client.redis.del(`chess-${msg.author.id}`);
|
||||
} catch {
|
||||
await this.client.redis.del(`chess-${msg.author.id}`);
|
||||
return msg.reply('An error occurred reading your saved game. It will be deleted.');
|
||||
}
|
||||
} else {
|
||||
game = new jsChess.Game(fen || undefined);
|
||||
}
|
||||
let prevPieces = null;
|
||||
let saved = false;
|
||||
while (!game.exportJson().isFinished && game.exportJson().halfMove <= 50) {
|
||||
const gameState = game.exportJson();
|
||||
const user = gameState.turn === 'black' ? blackPlayer : whitePlayer;
|
||||
const userTime = gameState.turn === 'black' ? blackTime : whiteTime;
|
||||
if (user.bot) {
|
||||
prevPieces = Object.assign({}, game.exportJson().pieces);
|
||||
const now = new Date();
|
||||
game.aiMove(1);
|
||||
const timeTaken = new Date() - now;
|
||||
if (gameState.turn === 'black') blackTime -= timeTaken - 5000;
|
||||
if (gameState.turn === 'white') whiteTime -= timeTaken - 5000;
|
||||
} else {
|
||||
const displayTime = userTime === Infinity ? 'Infinite' : moment.duration(userTime).format();
|
||||
await msg.say(stripIndents`
|
||||
${user}, what move do you want to make (ex. A1A2 or NC3)? Type \`end\` to forfeit.
|
||||
You can save your game by typing \`save\`. Can't think of a move? Use \`play for me\`.
|
||||
|
||||
_You are ${gameState.check ? '**in check!**' : 'not in check.'}_
|
||||
**Time Remaining: ${displayTime}** (Max 10min per turn)
|
||||
**FEN:** \`${game.exportFEN()}\`
|
||||
`, { files: [{ attachment: this.displayBoard(gameState, prevPieces), name: 'chess.png' }] });
|
||||
prevPieces = Object.assign({}, game.exportJson().pieces);
|
||||
const moves = game.moves();
|
||||
const pickFilter = res => {
|
||||
if (![msg.author.id, opponent.id].includes(res.author.id)) return false;
|
||||
const choice = res.content.toUpperCase();
|
||||
if (choice === 'END') return true;
|
||||
if (choice === 'SAVE') return true;
|
||||
if (choice === 'PLAY FOR ME') return true;
|
||||
if (res.author.id !== user.id) return false;
|
||||
const move = choice.match(turnRegex);
|
||||
if (!move) return false;
|
||||
const parsed = this.parseSAN(gameState, moves, move);
|
||||
if (!parsed || !moves[parsed[0]] || !moves[parsed[0]].includes(parsed[1])) {
|
||||
reactIfAble(res, res.author, FAILURE_EMOJI_ID, '❌');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const now = new Date();
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: pickFilter,
|
||||
max: 1,
|
||||
time: Math.min(userTime, 600000)
|
||||
});
|
||||
if (!turn.size) {
|
||||
const timeTaken = new Date() - now;
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (userTime - timeTaken <= 0) {
|
||||
return msg.say(`${user.id === msg.author.id ? opponent : msg.author} wins from timeout!`);
|
||||
} else {
|
||||
return msg.say(`${user}, the game has been ended. You cannot take more than 10 minutes.`);
|
||||
}
|
||||
}
|
||||
if (turn.first().content.toLowerCase() === 'end') break;
|
||||
if (turn.first().content.toLowerCase() === 'save') {
|
||||
const { author } = turn.first();
|
||||
const alreadySaved = await this.client.redis.get(`chess-${author.id}`);
|
||||
if (alreadySaved) {
|
||||
await msg.say('You already have a saved game, do you want to overwrite it?');
|
||||
const verification = await verify(msg.channel, author);
|
||||
if (!verification) continue; // eslint-disable-line max-depth
|
||||
}
|
||||
if (gameState.turn === 'black') blackTime -= new Date() - now;
|
||||
if (gameState.turn === 'white') whiteTime -= new Date() - now;
|
||||
await this.client.redis.set(
|
||||
`chess-${author.id}`,
|
||||
this.exportGame(
|
||||
game,
|
||||
blackTime,
|
||||
whiteTime,
|
||||
whitePlayer.id === author.id ? 'white' : 'black'
|
||||
)
|
||||
);
|
||||
saved = true;
|
||||
break;
|
||||
}
|
||||
if (turn.first().content.toLowerCase() === 'play for me') {
|
||||
game.aiMove(0);
|
||||
} else {
|
||||
const choice = this.parseSAN(gameState, moves, turn.first().content.toUpperCase().match(turnRegex));
|
||||
const pawnMoved = gameState.pieces[choice[0]].toUpperCase() === 'P';
|
||||
game.move(choice[0], choice[1]);
|
||||
if (pawnMoved && choice[1].endsWith(gameState.turn === 'white' ? '8' : '1')) {
|
||||
game.setPiece(choice[1], gameState.turn === 'white' ? choice[2] : choice[2].toLowerCase());
|
||||
}
|
||||
}
|
||||
const timeTaken = new Date() - now;
|
||||
if (gameState.turn === 'black') blackTime -= timeTaken - 5000;
|
||||
if (gameState.turn === 'white') whiteTime -= timeTaken - 5000;
|
||||
}
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (saved) {
|
||||
return msg.say(stripIndents`
|
||||
Game saved! Use ${this.usage(opponent.tag)} to resume it.
|
||||
You do not have to use the same opponent to resume the game.
|
||||
If you want to delete your saved game, use ${this.client.registry.commands.get('chess-delete').usage()}.
|
||||
`);
|
||||
}
|
||||
} else {
|
||||
game = new jsChess.Game(fen || undefined);
|
||||
}
|
||||
let prevPieces = null;
|
||||
let saved = false;
|
||||
while (!game.exportJson().isFinished && game.exportJson().halfMove <= 50) {
|
||||
const gameState = game.exportJson();
|
||||
if (gameState.halfMove > 50) return msg.say('Due to the fifty move rule, this game is a draw.');
|
||||
if (!gameState.isFinished) return msg.say('Game ended due to forfeit.');
|
||||
if (!gameState.checkMate && gameState.isFinished) {
|
||||
return msg.say('Stalemate! This game is a draw.', {
|
||||
files: [{ attachment: this.displayBoard(gameState, prevPieces), name: 'chess.png' }]
|
||||
const user = gameState.turn === 'black' ? blackPlayer : whitePlayer;
|
||||
const userTime = gameState.turn === 'black' ? blackTime : whiteTime;
|
||||
if (user.bot) {
|
||||
prevPieces = Object.assign({}, game.exportJson().pieces);
|
||||
const now = new Date();
|
||||
game.aiMove(1);
|
||||
const timeTaken = new Date() - now;
|
||||
if (gameState.turn === 'black') blackTime -= timeTaken - 5000;
|
||||
if (gameState.turn === 'white') whiteTime -= timeTaken - 5000;
|
||||
} else {
|
||||
const displayTime = userTime === Infinity ? 'Infinite' : moment.duration(userTime).format();
|
||||
await msg.say(stripIndents`
|
||||
${user}, what move do you want to make (ex. A1A2 or NC3)? Type \`end\` to forfeit.
|
||||
You can save your game by typing \`save\`. Can't think of a move? Use \`play for me\`.
|
||||
|
||||
_You are ${gameState.check ? '**in check!**' : 'not in check.'}_
|
||||
**Time Remaining: ${displayTime}** (Max 10min per turn)
|
||||
**FEN:** \`${game.exportFEN()}\`
|
||||
`, { files: [{ attachment: this.displayBoard(gameState, prevPieces), name: 'chess.png' }] });
|
||||
prevPieces = Object.assign({}, game.exportJson().pieces);
|
||||
const moves = game.moves();
|
||||
const pickFilter = res => {
|
||||
if (![msg.author.id, opponent.id].includes(res.author.id)) return false;
|
||||
const choice = res.content.toUpperCase();
|
||||
if (choice === 'END') return true;
|
||||
if (choice === 'SAVE') return true;
|
||||
if (choice === 'PLAY FOR ME') return true;
|
||||
if (res.author.id !== user.id) return false;
|
||||
const move = choice.match(turnRegex);
|
||||
if (!move) return false;
|
||||
const parsed = this.parseSAN(gameState, moves, move);
|
||||
if (!parsed || !moves[parsed[0]] || !moves[parsed[0]].includes(parsed[1])) {
|
||||
reactIfAble(res, res.author, FAILURE_EMOJI_ID, '❌');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const now = new Date();
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: pickFilter,
|
||||
max: 1,
|
||||
time: Math.min(userTime, 600000)
|
||||
});
|
||||
if (!turn.size) {
|
||||
const timeTaken = new Date() - now;
|
||||
if (userTime - timeTaken <= 0) {
|
||||
return msg.say(`${user.id === msg.author.id ? opponent : msg.author} wins from timeout!`);
|
||||
} else {
|
||||
return msg.say(`${user}, the game has been ended. You cannot take more than 10 minutes.`);
|
||||
}
|
||||
}
|
||||
if (turn.first().content.toLowerCase() === 'end') break;
|
||||
if (turn.first().content.toLowerCase() === 'save') {
|
||||
const { author } = turn.first();
|
||||
const alreadySaved = await this.client.redis.get(`chess-${author.id}`);
|
||||
if (alreadySaved) {
|
||||
await msg.say('You already have a saved game, do you want to overwrite it?');
|
||||
const verification = await verify(msg.channel, author);
|
||||
if (!verification) continue; // eslint-disable-line max-depth
|
||||
}
|
||||
if (gameState.turn === 'black') blackTime -= new Date() - now;
|
||||
if (gameState.turn === 'white') whiteTime -= new Date() - now;
|
||||
await this.client.redis.set(
|
||||
`chess-${author.id}`,
|
||||
this.exportGame(
|
||||
game,
|
||||
blackTime,
|
||||
whiteTime,
|
||||
whitePlayer.id === author.id ? 'white' : 'black'
|
||||
)
|
||||
);
|
||||
saved = true;
|
||||
break;
|
||||
}
|
||||
if (turn.first().content.toLowerCase() === 'play for me') {
|
||||
game.aiMove(0);
|
||||
} else {
|
||||
const choice = this.parseSAN(gameState, moves, turn.first().content.toUpperCase().match(turnRegex));
|
||||
const pawnMoved = gameState.pieces[choice[0]].toUpperCase() === 'P';
|
||||
game.move(choice[0], choice[1]);
|
||||
if (pawnMoved && choice[1].endsWith(gameState.turn === 'white' ? '8' : '1')) {
|
||||
game.setPiece(choice[1], gameState.turn === 'white' ? choice[2] : choice[2].toLowerCase());
|
||||
}
|
||||
}
|
||||
const timeTaken = new Date() - now;
|
||||
if (gameState.turn === 'black') blackTime -= timeTaken - 5000;
|
||||
if (gameState.turn === 'white') whiteTime -= timeTaken - 5000;
|
||||
}
|
||||
const winner = gameState.turn === 'black' ? whitePlayer : blackPlayer;
|
||||
return msg.say(`Checkmate! Congrats, ${winner}!`, {
|
||||
}
|
||||
if (saved) {
|
||||
return msg.say(stripIndents`
|
||||
Game saved! Use ${this.usage(opponent.tag)} to resume it.
|
||||
You do not have to use the same opponent to resume the game.
|
||||
If you want to delete your saved game, use ${this.client.registry.commands.get('chess-delete').usage()}.
|
||||
`);
|
||||
}
|
||||
const gameState = game.exportJson();
|
||||
if (gameState.halfMove > 50) return msg.say('Due to the fifty move rule, this game is a draw.');
|
||||
if (!gameState.isFinished) return msg.say('Game ended due to forfeit.');
|
||||
if (!gameState.checkMate && gameState.isFinished) {
|
||||
return msg.say('Stalemate! This game is a draw.', {
|
||||
files: [{ attachment: this.displayBoard(gameState, prevPieces), name: 'chess.png' }]
|
||||
});
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
const winner = gameState.turn === 'black' ? whitePlayer : blackPlayer;
|
||||
return msg.say(`Checkmate! Congrats, ${winner}!`, {
|
||||
files: [{ attachment: this.displayBoard(gameState, prevPieces), name: 'chess.png' }]
|
||||
});
|
||||
}
|
||||
|
||||
parseSAN(gameState, moves, move) {
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = class ConnectFourCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'connect-four',
|
||||
description: 'Play a game of Connect Four with another user or the AI.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Hasbro',
|
||||
@@ -59,119 +60,107 @@ module.exports = class ConnectFourCommand extends Command {
|
||||
async run(msg, { opponent, color }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 });
|
||||
const playerOneEmoji = color;
|
||||
let playerTwoEmoji = color === colors.yellow ? colors.red : colors.yellow;
|
||||
try {
|
||||
const available = Object.keys(colors).filter(clr => color !== colors[clr]);
|
||||
if (opponent.bot) {
|
||||
playerTwoEmoji = colors[available[Math.floor(Math.random() * available.length)]];
|
||||
} else {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
await msg.say(
|
||||
`${opponent}, what color do you want to be? Either an emoji or one of ${list(available, 'or')}.`
|
||||
);
|
||||
const filter = res => {
|
||||
if (res.author.id !== opponent.id) return false;
|
||||
if (res.content === blankEmoji) return false;
|
||||
const hasEmoji = new RegExp(`^(?:${emojiRegex().source})$`).test(res.content);
|
||||
const hasCustom = res.content.match(customEmojiRegex);
|
||||
if (hasCustom && msg.guild && !msg.guild.emojis.cache.has(hasCustom[2])) return false;
|
||||
return (hasCustom && msg.guild) || hasEmoji || available.includes(res.content.toLowerCase());
|
||||
};
|
||||
const p2Color = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (p2Color.size) {
|
||||
const choice = p2Color.first().content.toLowerCase();
|
||||
const hasCustom = choice.match(customEmojiRegex);
|
||||
if (hasCustom && msg.guild) {
|
||||
playerTwoEmoji = msg.guild.emojis.cache.get(hasCustom[2]).toString();
|
||||
} else {
|
||||
playerTwoEmoji = colors[choice] || choice;
|
||||
}
|
||||
const available = Object.keys(colors).filter(clr => color !== colors[clr]);
|
||||
if (opponent.bot) {
|
||||
playerTwoEmoji = colors[available[Math.floor(Math.random() * available.length)]];
|
||||
} else {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
await msg.say(
|
||||
`${opponent}, what color do you want to be? Either an emoji or one of ${list(available, 'or')}.`
|
||||
);
|
||||
const filter = res => {
|
||||
if (res.author.id !== opponent.id) return false;
|
||||
if (res.content === blankEmoji) return false;
|
||||
const hasEmoji = new RegExp(`^(?:${emojiRegex().source})$`).test(res.content);
|
||||
const hasCustom = res.content.match(customEmojiRegex);
|
||||
if (hasCustom && msg.guild && !msg.guild.emojis.cache.has(hasCustom[2])) return false;
|
||||
return (hasCustom && msg.guild) || hasEmoji || available.includes(res.content.toLowerCase());
|
||||
};
|
||||
const p2Color = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (p2Color.size) {
|
||||
const choice = p2Color.first().content.toLowerCase();
|
||||
const hasCustom = choice.match(customEmojiRegex);
|
||||
if (hasCustom && msg.guild) {
|
||||
playerTwoEmoji = msg.guild.emojis.cache.get(hasCustom[2]).toString();
|
||||
} else {
|
||||
playerTwoEmoji = colors[choice] || choice;
|
||||
}
|
||||
}
|
||||
const AIEngine = new Connect4AI();
|
||||
const board = this.generateBoard();
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
const colLevels = [5, 5, 5, 5, 5, 5, 5];
|
||||
let lastMove = 'None';
|
||||
while (!winner && board.some(row => row.includes(null))) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
const sign = userTurn ? 'user' : 'oppo';
|
||||
let i;
|
||||
if (opponent.bot && !userTurn) {
|
||||
}
|
||||
const AIEngine = new Connect4AI();
|
||||
const board = this.generateBoard();
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
const colLevels = [5, 5, 5, 5, 5, 5, 5];
|
||||
let lastMove = 'None';
|
||||
while (!winner && board.some(row => row.includes(null))) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
const sign = userTurn ? 'user' : 'oppo';
|
||||
let i;
|
||||
if (opponent.bot && !userTurn) {
|
||||
i = AIEngine.playAI('hard');
|
||||
lastMove = i + 1;
|
||||
} else {
|
||||
const emoji = userTurn ? playerOneEmoji : playerTwoEmoji;
|
||||
await msg.say(stripIndents`
|
||||
${emoji} ${user}, which column do you pick? Type \`end\` to forfeit.
|
||||
Can't think of a move? Use \`play for me\`.
|
||||
${opponent.bot ? `I placed mine in **${lastMove}**.` : `Previous Move: **${lastMove}**`}
|
||||
|
||||
${this.displayBoard(board, playerOneEmoji, playerTwoEmoji)}
|
||||
${nums.join('')}
|
||||
`);
|
||||
const pickFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const choice = res.content;
|
||||
if (choice.toLowerCase() === 'end') return true;
|
||||
if (choice.toLowerCase() === 'play for me') return true;
|
||||
const j = Number.parseInt(choice, 10) - 1;
|
||||
return board[colLevels[j]] && board[colLevels[j]][j] !== undefined;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: pickFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
const choice = turn.size ? turn.first().content : null;
|
||||
if (!choice) {
|
||||
await msg.say('Sorry, time is up! I\'ll pick their move for them.');
|
||||
i = AIEngine.playAI('hard');
|
||||
lastMove = i + 1;
|
||||
} else if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
} else if (choice.toLowerCase() === 'play for me') {
|
||||
i = AIEngine.playAI('hard');
|
||||
lastMove = i + 1;
|
||||
} else {
|
||||
const emoji = userTurn ? playerOneEmoji : playerTwoEmoji;
|
||||
await msg.say(stripIndents`
|
||||
${emoji} ${user}, which column do you pick? Type \`end\` to forfeit.
|
||||
Can't think of a move? Use \`play for me\`.
|
||||
${opponent.bot ? `I placed mine in **${lastMove}**.` : `Previous Move: **${lastMove}**`}
|
||||
|
||||
${this.displayBoard(board, playerOneEmoji, playerTwoEmoji)}
|
||||
${nums.join('')}
|
||||
`);
|
||||
const pickFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const choice = res.content;
|
||||
if (choice.toLowerCase() === 'end') return true;
|
||||
if (choice.toLowerCase() === 'play for me') return true;
|
||||
const j = Number.parseInt(choice, 10) - 1;
|
||||
return board[colLevels[j]] && board[colLevels[j]][j] !== undefined;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: pickFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
const choice = turn.size ? turn.first().content : null;
|
||||
if (!choice) {
|
||||
await msg.say('Sorry, time is up! I\'ll pick their move for them.');
|
||||
i = AIEngine.playAI('hard');
|
||||
lastMove = i + 1;
|
||||
} else if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
} else if (choice.toLowerCase() === 'play for me') {
|
||||
i = AIEngine.playAI('hard');
|
||||
lastMove = i + 1;
|
||||
} else {
|
||||
i = Number.parseInt(choice, 10) - 1;
|
||||
AIEngine.play(i);
|
||||
lastMove = i + 1;
|
||||
}
|
||||
i = Number.parseInt(choice, 10) - 1;
|
||||
AIEngine.play(i);
|
||||
lastMove = i + 1;
|
||||
}
|
||||
board[colLevels[i]][i] = sign;
|
||||
colLevels[i]--;
|
||||
if (this.verifyWin(board)) winner = userTurn ? msg.author : opponent;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
board[colLevels[i]][i] = sign;
|
||||
colLevels[i]--;
|
||||
if (this.verifyWin(board)) winner = userTurn ? msg.author : opponent;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
${winner ? `Congrats, ${winner}!` : 'Looks like it\'s a draw...'}
|
||||
Final Move: **${lastMove}**
|
||||
|
||||
${this.displayBoard(board, playerOneEmoji, playerTwoEmoji)}
|
||||
${nums.join('')}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
checkLine(a, b, c, d) {
|
||||
|
||||
+79
-90
@@ -15,6 +15,7 @@ module.exports = class CramCommand extends Command {
|
||||
memberName: 'cram',
|
||||
description: 'Play a game of Cram with another user.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -41,102 +42,90 @@ module.exports = class CramCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be played against.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 });
|
||||
const userEmoji = colors[color];
|
||||
let oppoEmoji = userEmoji === colors.blue ? colors.red : colors.blue;
|
||||
try {
|
||||
const available = Object.keys(colors).filter(clr => color !== clr);
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
await msg.say(`${opponent}, what color do you want to be? Either ${list(available, 'or')}.`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== opponent.id) return false;
|
||||
return available.includes(res.content.toLowerCase());
|
||||
};
|
||||
const p2Color = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (p2Color.size) oppoEmoji = colors[p2Color.first().content.toLowerCase()];
|
||||
const board = this.generateBoard(size);
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (!winner) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${user}, at what coordinates do you want to place your block? Type \`end\` to forfeit.
|
||||
You must also choose a direction. (ex. v1,1 or h3,4).
|
||||
|
||||
${this.displayBoard(board, userEmoji, oppoEmoji)}
|
||||
`);
|
||||
const possibleMoves = this.possibleMoves(board);
|
||||
const colorFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
const coordPicked = pick.match(turnRegex);
|
||||
if (!coordPicked) return false;
|
||||
const direction = coordPicked[1].toLowerCase();
|
||||
const x = Number.parseInt(coordPicked[2], 10);
|
||||
const y = Number.parseInt(coordPicked[3], 10);
|
||||
if (x > size || y > size || x < 1 || y < 1) return false;
|
||||
if (!possibleMoves.includes(`${direction}${x - 1},${y - 1}`)) return false;
|
||||
return true;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: colorFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const matched = choice.match(turnRegex);
|
||||
const direction = matched[1].toLowerCase();
|
||||
const x = Number.parseInt(matched[2], 10);
|
||||
const y = Number.parseInt(matched[3], 10);
|
||||
board[y - 1][x - 1] = userTurn ? 'U' : 'O';
|
||||
board[direction === 'v' ? y : y - 1][direction === 'v' ? x - 1 : x] = userTurn ? 'U' : 'O';
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
const oppoPossible = this.possibleMoves(board, userTurn);
|
||||
if (!oppoPossible.length) {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}! Your opponent has no possible moves left!
|
||||
const available = Object.keys(colors).filter(clr => color !== clr);
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
await msg.say(`${opponent}, what color do you want to be? Either ${list(available, 'or')}.`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== opponent.id) return false;
|
||||
return available.includes(res.content.toLowerCase());
|
||||
};
|
||||
const p2Color = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (p2Color.size) oppoEmoji = colors[p2Color.first().content.toLowerCase()];
|
||||
const board = this.generateBoard(size);
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (!winner) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${user}, at what coordinates do you want to place your block? Type \`end\` to forfeit.
|
||||
You must also choose a direction. (ex. v1,1 or h3,4).
|
||||
|
||||
${this.displayBoard(board, userEmoji, oppoEmoji)}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const possibleMoves = this.possibleMoves(board);
|
||||
const colorFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
const coordPicked = pick.match(turnRegex);
|
||||
if (!coordPicked) return false;
|
||||
const direction = coordPicked[1].toLowerCase();
|
||||
const x = Number.parseInt(coordPicked[2], 10);
|
||||
const y = Number.parseInt(coordPicked[3], 10);
|
||||
if (x > size || y > size || x < 1 || y < 1) return false;
|
||||
if (!possibleMoves.includes(`${direction}${x - 1},${y - 1}`)) return false;
|
||||
return true;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: colorFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const matched = choice.match(turnRegex);
|
||||
const direction = matched[1].toLowerCase();
|
||||
const x = Number.parseInt(matched[2], 10);
|
||||
const y = Number.parseInt(matched[3], 10);
|
||||
board[y - 1][x - 1] = userTurn ? 'U' : 'O';
|
||||
board[direction === 'v' ? y : y - 1][direction === 'v' ? x - 1 : x] = userTurn ? 'U' : 'O';
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
const oppoPossible = this.possibleMoves(board, userTurn);
|
||||
if (!oppoPossible.length) {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}! Your opponent has no possible moves left!
|
||||
|
||||
${this.displayBoard(board, userEmoji, oppoEmoji)}
|
||||
`);
|
||||
}
|
||||
|
||||
possibleMoves(board) {
|
||||
|
||||
@@ -15,6 +15,7 @@ module.exports = class DomineeringCommand extends Command {
|
||||
memberName: 'domineering',
|
||||
description: 'Play a game of Domineering with another user.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -41,100 +42,88 @@ module.exports = class DomineeringCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be played against.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 });
|
||||
const userEmoji = colors[color];
|
||||
let oppoEmoji = userEmoji === colors.blue ? colors.red : colors.blue;
|
||||
try {
|
||||
const available = Object.keys(colors).filter(clr => color !== clr);
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
await msg.say(`${opponent}, what color do you want to be? Either ${list(available, 'or')}.`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== opponent.id) return false;
|
||||
return available.includes(res.content.toLowerCase());
|
||||
};
|
||||
const p2Color = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (p2Color.size) oppoEmoji = colors[p2Color.first().content.toLowerCase()];
|
||||
const board = this.generateBoard(size);
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (!winner) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${user}, at what coordinates do you want to place your block (ex. 1,1)? Type \`end\` to forfeit.
|
||||
Your pieces are **${userTurn ? 'vertical' : 'horizontal'}**.
|
||||
|
||||
${this.displayBoard(board, userEmoji, oppoEmoji)}
|
||||
`);
|
||||
const possibleMoves = this.possibleMoves(board, userTurn);
|
||||
const colorFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
const coordPicked = pick.match(turnRegex);
|
||||
if (!coordPicked) return false;
|
||||
const x = Number.parseInt(coordPicked[1], 10);
|
||||
const y = Number.parseInt(coordPicked[2], 10);
|
||||
if (x > size || y > size || x < 1 || y < 1) return false;
|
||||
if (!possibleMoves.includes(`${x - 1},${y - 1}`)) return false;
|
||||
return true;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: colorFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const matched = choice.match(turnRegex);
|
||||
const x = Number.parseInt(matched[1], 10);
|
||||
const y = Number.parseInt(matched[2], 10);
|
||||
board[y - 1][x - 1] = userTurn ? 'U' : 'O';
|
||||
board[userTurn ? y : y - 1][userTurn ? x - 1 : x] = userTurn ? 'U' : 'O';
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
const oppoPossible = this.possibleMoves(board, userTurn);
|
||||
if (!oppoPossible.length) {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}! Your opponent has no possible moves left!
|
||||
const available = Object.keys(colors).filter(clr => color !== clr);
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
await msg.say(`${opponent}, what color do you want to be? Either ${list(available, 'or')}.`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== opponent.id) return false;
|
||||
return available.includes(res.content.toLowerCase());
|
||||
};
|
||||
const p2Color = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (p2Color.size) oppoEmoji = colors[p2Color.first().content.toLowerCase()];
|
||||
const board = this.generateBoard(size);
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (!winner) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${user}, at what coordinates do you want to place your block (ex. 1,1)? Type \`end\` to forfeit.
|
||||
Your pieces are **${userTurn ? 'vertical' : 'horizontal'}**.
|
||||
|
||||
${this.displayBoard(board, userEmoji, oppoEmoji)}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const possibleMoves = this.possibleMoves(board, userTurn);
|
||||
const colorFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
const coordPicked = pick.match(turnRegex);
|
||||
if (!coordPicked) return false;
|
||||
const x = Number.parseInt(coordPicked[1], 10);
|
||||
const y = Number.parseInt(coordPicked[2], 10);
|
||||
if (x > size || y > size || x < 1 || y < 1) return false;
|
||||
if (!possibleMoves.includes(`${x - 1},${y - 1}`)) return false;
|
||||
return true;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: colorFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const matched = choice.match(turnRegex);
|
||||
const x = Number.parseInt(matched[1], 10);
|
||||
const y = Number.parseInt(matched[2], 10);
|
||||
board[y - 1][x - 1] = userTurn ? 'U' : 'O';
|
||||
board[userTurn ? y : y - 1][userTurn ? x - 1 : x] = userTurn ? 'U' : 'O';
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
const oppoPossible = this.possibleMoves(board, userTurn);
|
||||
if (!oppoPossible.length) {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}! Your opponent has no possible moves left!
|
||||
|
||||
${this.displayBoard(board, userEmoji, oppoEmoji)}
|
||||
`);
|
||||
}
|
||||
|
||||
possibleMoves(board, userTurn) {
|
||||
|
||||
@@ -12,6 +12,7 @@ module.exports = class DotsAndBoxesCommand extends Command {
|
||||
memberName: 'dots-and-boxes',
|
||||
description: 'Play a game of Dots and Boxes with another user.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -25,113 +26,101 @@ module.exports = class DotsAndBoxesCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be played against.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
const board = this.generateBoard();
|
||||
const taken = [];
|
||||
const userOwned = [];
|
||||
const oppoOwned = [];
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (taken.length < 40) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${user}, which connection do you pick? Type \`end\` to forfeit.
|
||||
_Format like \`1-2\` or \`0-5\`. Any two spaces bordering **vertical or horizontal**._
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
const board = this.generateBoard();
|
||||
const taken = [];
|
||||
const userOwned = [];
|
||||
const oppoOwned = [];
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (taken.length < 40) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${user}, which connection do you pick? Type \`end\` to forfeit.
|
||||
_Format like \`1-2\` or \`0-5\`. Any two spaces bordering **vertical or horizontal**._
|
||||
|
||||
P1: ${msg.author.tag} | P2: ${opponent.tag}
|
||||
\`\`\`
|
||||
${this.displayBoard(board, taken, userOwned, oppoOwned)}
|
||||
\`\`\`
|
||||
`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const choice = res.content;
|
||||
if (choice.toLowerCase() === 'end') return true;
|
||||
const matched = choice.match(/([0-9]+)-([0-9]+)/);
|
||||
if (!matched) return false;
|
||||
let first = Number.parseInt(matched[1], 10);
|
||||
let second = Number.parseInt(matched[2], 10);
|
||||
if (first === second) return false;
|
||||
if (second < first) {
|
||||
const temp = first;
|
||||
first = second;
|
||||
second = temp;
|
||||
}
|
||||
if (first > 24 || second > 24 || first < 0 || second < 0) return false;
|
||||
const column1 = first % 5;
|
||||
const column2 = second % 5;
|
||||
if (second !== first + 1 && column1 !== column2) {
|
||||
const row1 = Math.floor(first / 5);
|
||||
const row2 = Math.floor(second / 5);
|
||||
if (row2 !== row1 - 1) return false;
|
||||
return !taken.includes(`${first}-${second}`);
|
||||
}
|
||||
return !taken.includes(`${first}-${second}`);
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
P1: ${msg.author.tag} | P2: ${opponent.tag}
|
||||
\`\`\`
|
||||
${this.displayBoard(board, taken, userOwned, oppoOwned)}
|
||||
\`\`\`
|
||||
`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const choice = res.content;
|
||||
if (choice.toLowerCase() === 'end') return true;
|
||||
const matched = choice.match(/([0-9]+)-([0-9]+)/);
|
||||
if (!matched) return false;
|
||||
let first = Number.parseInt(matched[1], 10);
|
||||
let second = Number.parseInt(matched[2], 10);
|
||||
if (first === second) return false;
|
||||
if (second < first) {
|
||||
const temp = first;
|
||||
first = second;
|
||||
second = temp;
|
||||
}
|
||||
taken.push(`${first}-${second}`);
|
||||
const newSquares = this.calcNewSquare(taken, userOwned, oppoOwned);
|
||||
if (newSquares.length) {
|
||||
for (const newSquare of newSquares) {
|
||||
if (userTurn) userOwned.push(newSquare);
|
||||
else oppoOwned.push(newSquare);
|
||||
}
|
||||
if (taken.length < 40) {
|
||||
await msg.say(`${user}, great job! Keep going until you can't make any more!`);
|
||||
}
|
||||
} else {
|
||||
userTurn = !userTurn;
|
||||
if (first > 24 || second > 24 || first < 0 || second < 0) return false;
|
||||
const column1 = first % 5;
|
||||
const column2 = second % 5;
|
||||
if (second !== first + 1 && column1 !== column2) {
|
||||
const row1 = Math.floor(first / 5);
|
||||
const row2 = Math.floor(second / 5);
|
||||
if (row2 !== row1 - 1) return false;
|
||||
return !taken.includes(`${first}-${second}`);
|
||||
}
|
||||
return !taken.includes(`${first}-${second}`);
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
winner = userOwned.length === oppoOwned.length
|
||||
? null
|
||||
: userOwned.length > oppoOwned.length ? msg.author : opponent;
|
||||
return msg.say(winner ? `Congrats, ${winner}!` : 'Looks like it\'s a draw...');
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const matched = choice.match(/([0-9]+)-([0-9]+)/);
|
||||
let first = Number.parseInt(matched[1], 10);
|
||||
let second = Number.parseInt(matched[2], 10);
|
||||
if (second < first) {
|
||||
const temp = first;
|
||||
first = second;
|
||||
second = temp;
|
||||
}
|
||||
taken.push(`${first}-${second}`);
|
||||
const newSquares = this.calcNewSquare(taken, userOwned, oppoOwned);
|
||||
if (newSquares.length) {
|
||||
for (const newSquare of newSquares) {
|
||||
if (userTurn) userOwned.push(newSquare);
|
||||
else oppoOwned.push(newSquare);
|
||||
}
|
||||
if (taken.length < 40) {
|
||||
await msg.say(`${user}, great job! Keep going until you can't make any more!`);
|
||||
}
|
||||
} else {
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
winner = userOwned.length === oppoOwned.length
|
||||
? null
|
||||
: userOwned.length > oppoOwned.length ? msg.author : opponent;
|
||||
return msg.say(winner ? `Congrats, ${winner}!` : 'Looks like it\'s a draw...');
|
||||
}
|
||||
|
||||
calcSquare(num, taken) {
|
||||
|
||||
@@ -13,6 +13,7 @@ module.exports = class EmojiEmojiRevolutionCommand extends Command {
|
||||
memberName: 'emoji-emoji-revolution',
|
||||
description: 'Can you type arrow emoji faster than anyone else has ever typed them before?',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Dance Dance Revolution',
|
||||
@@ -33,57 +34,45 @@ module.exports = class EmojiEmojiRevolutionCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be played against.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
let turn = 0;
|
||||
let aPts = 0;
|
||||
let oPts = 0;
|
||||
let lastTurnTimeout = false;
|
||||
while (turn < 10) {
|
||||
++turn;
|
||||
const num = Math.floor(Math.random() * emojis.length);
|
||||
const emoji = [emojis[num], emojisNew[num]];
|
||||
await msg.say(emojisNew[num]);
|
||||
const filter = res => [msg.author.id, opponent.id].includes(res.author.id) && emoji.includes(res.content);
|
||||
const win = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!win.size) {
|
||||
await msg.say('Hmm... No one even tried that round.');
|
||||
if (lastTurnTimeout) {
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
let turn = 0;
|
||||
let aPts = 0;
|
||||
let oPts = 0;
|
||||
let lastTurnTimeout = false;
|
||||
while (turn < 10) {
|
||||
++turn;
|
||||
const num = Math.floor(Math.random() * emojis.length);
|
||||
const emoji = [emojis[num], emojisNew[num]];
|
||||
await msg.say(emojisNew[num]);
|
||||
const filter = res => [msg.author.id, opponent.id].includes(res.author.id) && emoji.includes(res.content);
|
||||
const win = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!win.size) {
|
||||
await msg.say('Hmm... No one even tried that round.');
|
||||
if (lastTurnTimeout) {
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
const winner = win.first().author;
|
||||
if (winner.id === msg.author.id) ++aPts;
|
||||
else ++oPts;
|
||||
await msg.say(stripIndents`
|
||||
${winner} won this round!
|
||||
**${msg.author.username}:** ${aPts}
|
||||
**${opponent.username}:** ${oPts}
|
||||
`);
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (aPts === oPts) return msg.say('It\'s a tie!');
|
||||
const userWin = aPts > oPts;
|
||||
return msg.say(`You win ${userWin ? msg.author : opponent} with ${userWin ? aPts : oPts} points!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const winner = win.first().author;
|
||||
if (winner.id === msg.author.id) ++aPts;
|
||||
else ++oPts;
|
||||
await msg.say(stripIndents`
|
||||
${winner} won this round!
|
||||
**${msg.author.username}:** ${aPts}
|
||||
**${opponent.username}:** ${oPts}
|
||||
`);
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
if (aPts === oPts) return msg.say('It\'s a tie!');
|
||||
const userWin = aPts > oPts;
|
||||
return msg.say(`You win ${userWin ? msg.author : opponent} with ${userWin ? aPts : oPts} points!`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@ module.exports = class GuesspionageCommand extends Command {
|
||||
memberName: 'guesspionage',
|
||||
description: 'Tests your knowledge of humans as you guess how people responded to poll questions.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Jackbox Games',
|
||||
@@ -49,120 +50,108 @@ module.exports = class GuesspionageCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { players }) {
|
||||
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, players, min, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Game could not be started...');
|
||||
}
|
||||
let turn = 0;
|
||||
const pts = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
pts.set(player, {
|
||||
points: 0,
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
const used = [];
|
||||
const userTurn = awaitedPlayers.slice(0);
|
||||
let lastTurnTimeout = false;
|
||||
while (userTurn.length) {
|
||||
++turn;
|
||||
const mainUser = pts.get(userTurn[0]).user;
|
||||
userTurn.shift();
|
||||
const valid = questions.filter(
|
||||
question => !used.includes(question.text) && (msg.channel.nsfw ? true : !question.nsfw)
|
||||
);
|
||||
const question = valid[Math.floor(Math.random() * valid.length)];
|
||||
used.push(question.text);
|
||||
await msg.say(stripIndents`
|
||||
**${turn}.** ${question.text}
|
||||
const awaitedPlayers = await awaitPlayers(msg, players, min, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) return msg.say('Game could not be started...');
|
||||
let turn = 0;
|
||||
const pts = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
pts.set(player, {
|
||||
points: 0,
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
const used = [];
|
||||
const userTurn = awaitedPlayers.slice(0);
|
||||
let lastTurnTimeout = false;
|
||||
while (userTurn.length) {
|
||||
++turn;
|
||||
const mainUser = pts.get(userTurn[0]).user;
|
||||
userTurn.shift();
|
||||
const valid = questions.filter(
|
||||
question => !used.includes(question.text) && (msg.channel.nsfw ? true : !question.nsfw)
|
||||
);
|
||||
const question = valid[Math.floor(Math.random() * valid.length)];
|
||||
used.push(question.text);
|
||||
await msg.say(stripIndents`
|
||||
**${turn}.** ${question.text}
|
||||
|
||||
${mainUser}, what percentage do you guess?
|
||||
`);
|
||||
const initialGuessFilter = res => {
|
||||
if (res.author.id !== mainUser.id) return false;
|
||||
const int = Number.parseInt(res.content, 10);
|
||||
return int >= 0 && int <= 100;
|
||||
};
|
||||
const initialGuess = await msg.channel.awaitMessages({
|
||||
filter: initialGuessFilter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!initialGuess.size) {
|
||||
await msg.say('Hmm... No guess? I guess you\'re getting skipped.');
|
||||
${mainUser}, what percentage do you guess?
|
||||
`);
|
||||
const initialGuessFilter = res => {
|
||||
if (res.author.id !== mainUser.id) return false;
|
||||
const int = Number.parseInt(res.content, 10);
|
||||
return int >= 0 && int <= 100;
|
||||
};
|
||||
const initialGuess = await msg.channel.awaitMessages({
|
||||
filter: initialGuessFilter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!initialGuess.size) {
|
||||
await msg.say('Hmm... No guess? I guess you\'re getting skipped.');
|
||||
continue;
|
||||
}
|
||||
const guess = Number.parseInt(initialGuess.first().content, 10);
|
||||
await msg.say(stripIndents`
|
||||
**${guess}%**
|
||||
|
||||
Alright, everyone else, do you think the _actual_ percentage is \`higher\` or \`lower\`?
|
||||
You can also guess \`much higher\` or \`much lower\` for double points if their answer is 15% off.
|
||||
`);
|
||||
const guessed = [];
|
||||
const everyoneElseFilter = res => {
|
||||
if (res.author.id === mainUser.id) return false;
|
||||
if (guessed.includes(res.author.id)) return false;
|
||||
if (!awaitedPlayers.includes(res.author.id)) return false;
|
||||
if (!guesses.includes(res.content.toLowerCase())) return false;
|
||||
guessed.push(res.author.id);
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
};
|
||||
const everyoneElse = await msg.channel.awaitMessages({
|
||||
filter: everyoneElseFilter,
|
||||
max: awaitedPlayers.length - 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!everyoneElse.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 guess = Number.parseInt(initialGuess.first().content, 10);
|
||||
await msg.say(stripIndents`
|
||||
**${guess}%**
|
||||
|
||||
Alright, everyone else, do you think the _actual_ percentage is \`higher\` or \`lower\`?
|
||||
You can also guess \`much higher\` or \`much lower\` for double points if their answer is 15% off.
|
||||
`);
|
||||
const guessed = [];
|
||||
const everyoneElseFilter = res => {
|
||||
if (res.author.id === mainUser.id) return false;
|
||||
if (guessed.includes(res.author.id)) return false;
|
||||
if (!awaitedPlayers.includes(res.author.id)) return false;
|
||||
if (!guesses.includes(res.content.toLowerCase())) return false;
|
||||
guessed.push(res.author.id);
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
};
|
||||
const everyoneElse = await msg.channel.awaitMessages({
|
||||
filter: everyoneElseFilter,
|
||||
max: awaitedPlayers.length - 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!everyoneElse.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 higherLower = everyoneElse.map(res => ({ guess: res.content.toLowerCase(), id: res.author.id }));
|
||||
for (const answer of higherLower) {
|
||||
const uGuess = answer.guess;
|
||||
if (uGuess === 'higher' && guess < question.answer) {
|
||||
pts.get(answer.id).points += 1000;
|
||||
} else if (uGuess === 'lower' && guess > question.answer) {
|
||||
pts.get(answer.id).points += 1000;
|
||||
} else if (uGuess === 'much higher' && guess < question.answer && question.answer - guess >= 15) {
|
||||
pts.get(answer.id).points += 2000;
|
||||
} else if (uGuess === 'much lower' && guess > question.answer && guess - question.answer >= 15) {
|
||||
pts.get(answer.id).points += 2000;
|
||||
}
|
||||
}
|
||||
const diff = Math.abs(question.answer - guess);
|
||||
if (diff <= 30) pts.get(mainUser.id).points += 3000 - (diff * 100);
|
||||
await msg.say(stripIndents`
|
||||
The actual answer was... **${question.answer}%**!
|
||||
|
||||
__**Leaderboard:**__
|
||||
${this.makeLeaderboard(pts).join('\n')}
|
||||
|
||||
${userTurn.length ? '_Next round starting in 10 seconds..._' : ''}
|
||||
`);
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
if (userTurn.length) await delay(10000);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
const winner = pts.sort((a, b) => b.points - a.points).first().user;
|
||||
return msg.say(`Congrats, ${winner}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const higherLower = everyoneElse.map(res => ({ guess: res.content.toLowerCase(), id: res.author.id }));
|
||||
for (const answer of higherLower) {
|
||||
const uGuess = answer.guess;
|
||||
if (uGuess === 'higher' && guess < question.answer) {
|
||||
pts.get(answer.id).points += 1000;
|
||||
} else if (uGuess === 'lower' && guess > question.answer) {
|
||||
pts.get(answer.id).points += 1000;
|
||||
} else if (uGuess === 'much higher' && guess < question.answer && question.answer - guess >= 15) {
|
||||
pts.get(answer.id).points += 2000;
|
||||
} else if (uGuess === 'much lower' && guess > question.answer && guess - question.answer >= 15) {
|
||||
pts.get(answer.id).points += 2000;
|
||||
}
|
||||
}
|
||||
const diff = Math.abs(question.answer - guess);
|
||||
if (diff <= 30) pts.get(mainUser.id).points += 3000 - (diff * 100);
|
||||
await msg.say(stripIndents`
|
||||
The actual answer was... **${question.answer}%**!
|
||||
|
||||
__**Leaderboard:**__
|
||||
${this.makeLeaderboard(pts).join('\n')}
|
||||
|
||||
${userTurn.length ? '_Next round starting in 10 seconds..._' : ''}
|
||||
`);
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
if (userTurn.length) await delay(10000);
|
||||
}
|
||||
const winner = pts.sort((a, b) => b.points - a.points).first().user;
|
||||
return msg.say(`Congrats, ${winner}!`);
|
||||
}
|
||||
|
||||
makeLeaderboard(pts) {
|
||||
|
||||
@@ -12,6 +12,7 @@ module.exports = class GunfightCommand extends Command {
|
||||
memberName: 'gunfight',
|
||||
description: 'Engage in a western gunfight against another user. High noon.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -25,46 +26,34 @@ module.exports = class GunfightCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be fought.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not fight yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
await msg.say('Get Ready...');
|
||||
await delay(randomRange(1000, 30000));
|
||||
const word = words[Math.floor(Math.random() * words.length)];
|
||||
await msg.say(`TYPE \`${word.toUpperCase()}\` NOW!`);
|
||||
const filter = res => [opponent.id, msg.author.id].includes(res.author.id) && res.content.toLowerCase() === word;
|
||||
const now = Date.now();
|
||||
const winner = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
const newScore = Date.now() - now;
|
||||
const highScoreGet = await this.client.redis.get('reaction-time');
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get('reaction-time-user');
|
||||
const scoreBeat = !highScore || highScore > newScore;
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set('reaction-time', newScore);
|
||||
await this.client.redis.set('reaction-time-user', winner.first().author.id);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!winner.size) return msg.say('Oh... No one won.');
|
||||
return msg.say(stripIndents`
|
||||
The winner is ${winner.first().author}! (Took ${newScore / 1000} seconds)
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${highScore / 1000} (Held by ${user})
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
await msg.say('Get Ready...');
|
||||
await delay(randomRange(1000, 30000));
|
||||
const word = words[Math.floor(Math.random() * words.length)];
|
||||
await msg.say(`TYPE \`${word.toUpperCase()}\` NOW!`);
|
||||
const filter = res => [opponent.id, msg.author.id].includes(res.author.id) && res.content.toLowerCase() === word;
|
||||
const now = Date.now();
|
||||
const winner = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
const newScore = Date.now() - now;
|
||||
const highScoreGet = await this.client.redis.get('reaction-time');
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get('reaction-time-user');
|
||||
const scoreBeat = !highScore || highScore > newScore;
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set('reaction-time', newScore);
|
||||
await this.client.redis.set('reaction-time-user', winner.first().author.id);
|
||||
}
|
||||
if (!winner.size) return msg.say('Oh... No one won.');
|
||||
return msg.say(stripIndents`
|
||||
The winner is ${winner.first().author}! (Took ${newScore / 1000} seconds)
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${highScore / 1000} (Held by ${user})
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
+121
-132
@@ -14,6 +14,7 @@ module.exports = class ImposterCommand extends Command {
|
||||
memberName: 'imposter',
|
||||
description: 'Who is the imposter among us?',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
clientPermissions: ['ADD_REACTIONS', 'READ_MESSAGE_HISTORY'],
|
||||
args: [
|
||||
{
|
||||
@@ -28,138 +29,126 @@ module.exports = class ImposterCommand extends Command {
|
||||
}
|
||||
|
||||
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, this.client.blacklist.user);
|
||||
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)];
|
||||
await msg.say(oneLine`
|
||||
Welcome to Imposter! In this game, you will have to figure out who the imposter is!
|
||||
All you have to do is watch what other players say. There's a special word called a kill word.
|
||||
Only the imposter can say it, and if anyone else does, they die! To win, figure out what the kill
|
||||
word is, and try to catch the imposter saying it. As for the imposter, you know the word, try to get
|
||||
everyone to say it!
|
||||
`);
|
||||
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. Be careful what you say!');
|
||||
}
|
||||
let lastTurnTimeout = false;
|
||||
const winners = [];
|
||||
while (players.filter(player => !player.killed).size > 2) {
|
||||
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);
|
||||
const ids = choices.map(player => player.id);
|
||||
let i = 0;
|
||||
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++; return `**${i}.** ${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(p => !p.killed).size) {
|
||||
const currentVotes = votes.get(choices[int - 1]);
|
||||
votes.set(ids[int - 1], {
|
||||
votes: currentVotes ? currentVotes + 1 : 1,
|
||||
id: ids[int - 1]
|
||||
});
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const vote = await msg.channel.awaitMessages({
|
||||
filter: 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;
|
||||
}
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
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;
|
||||
const awaitedPlayers = await awaitPlayers(msg, playersCount, 3, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) 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)];
|
||||
await msg.say(oneLine`
|
||||
Welcome to Imposter! In this game, you will have to figure out who the imposter is!
|
||||
All you have to do is watch what other players say. There's a special word called a kill word.
|
||||
Only the imposter can say it, and if anyone else does, they die! To win, figure out what the kill
|
||||
word is, and try to catch the imposter saying it. As for the imposter, you know the word, try to get
|
||||
everyone to say it!
|
||||
`);
|
||||
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. Be careful what you say!');
|
||||
}
|
||||
let lastTurnTimeout = false;
|
||||
const winners = [];
|
||||
while (players.filter(player => !player.killed).size > 2) {
|
||||
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);
|
||||
const ids = choices.map(player => player.id);
|
||||
let i = 0;
|
||||
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++; return `**${i}.** ${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(p => !p.killed).size) {
|
||||
const currentVotes = votes.get(choices[int - 1]);
|
||||
votes.set(ids[int - 1], {
|
||||
votes: currentVotes ? currentVotes + 1 : 1,
|
||||
id: ids[int - 1]
|
||||
});
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const vote = await msg.channel.awaitMessages({
|
||||
filter: 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;
|
||||
}
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
return msg.say(`Congrats, ${list(winners)}! The kill word was **${word}**.`);
|
||||
}
|
||||
};
|
||||
|
||||
+77
-88
@@ -11,6 +11,7 @@ module.exports = class IslandCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'island',
|
||||
description: 'Who will be the final two left on the island after a series of vote-kicks?',
|
||||
game: true,
|
||||
guildOnly: true,
|
||||
args: [
|
||||
{
|
||||
@@ -25,94 +26,82 @@ module.exports = class IslandCommand extends Command {
|
||||
}
|
||||
|
||||
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, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Game could not be started...');
|
||||
}
|
||||
let turn = 0;
|
||||
const players = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
let lastTurnTimeout = false;
|
||||
const playersLeft = new Set(players.map(p => p.id));
|
||||
while (playersLeft.size > 2) {
|
||||
++turn;
|
||||
await msg.say(stripIndents`
|
||||
**Day ${turn}.** Who should be kicked off the island?
|
||||
|
||||
You have **2 minutes** to make a decision before voting starts.
|
||||
`);
|
||||
await delay(120000);
|
||||
const choices = players.filter(player => playersLeft.has(player.id));
|
||||
const ids = choices.map(player => player.id);
|
||||
let i = 0;
|
||||
const display = choices.map(player => {
|
||||
const res = `**${i + 1}.** ${player.user.tag}`;
|
||||
i++;
|
||||
return res;
|
||||
});
|
||||
await msg.say(stripIndents`
|
||||
Alright, who do you want to kick off the island? You have 1 minute to vote.
|
||||
|
||||
_Type the number of the player you want to kick._
|
||||
${display.join('\n')}
|
||||
`);
|
||||
const votes = new Collection();
|
||||
const voteFilter = res => {
|
||||
if (!playersLeft.has(res.author.id)) return false;
|
||||
const int = Number.parseInt(res.content, 10);
|
||||
if (int >= 1 && int <= playersLeft.size) {
|
||||
const currentVotes = votes.get(choices[int - 1]);
|
||||
votes.set(ids[int - 1], {
|
||||
votes: currentVotes ? currentVotes + 1 : 1,
|
||||
id: ids[int - 1]
|
||||
});
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const vote = await msg.channel.awaitMessages({
|
||||
filter: voteFilter,
|
||||
max: playersLeft.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);
|
||||
playersLeft.delete(kicked.id);
|
||||
await msg.say(stripIndents`
|
||||
**${kicked.user.tag}** will be kicked off the island.
|
||||
|
||||
${playersLeft.size > 2 ? '_Next round starts in 30 seconds.' : ''}
|
||||
`);
|
||||
if (playersLeft.size > 2) await delay(30000);
|
||||
else break;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
const winners = players.filter(player => playersLeft.has(player.id));
|
||||
return msg.say(`Congrats, ${winners.map(player => player.user.tag).join(' and ')}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const awaitedPlayers = await awaitPlayers(msg, playersCount, 3, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) return msg.say('Game could not be started...');
|
||||
let turn = 0;
|
||||
const players = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
let lastTurnTimeout = false;
|
||||
const playersLeft = new Set(players.map(p => p.id));
|
||||
while (playersLeft.size > 2) {
|
||||
++turn;
|
||||
await msg.say(stripIndents`
|
||||
**Day ${turn}.** Who should be kicked off the island?
|
||||
|
||||
You have **2 minutes** to make a decision before voting starts.
|
||||
`);
|
||||
await delay(120000);
|
||||
const choices = players.filter(player => playersLeft.has(player.id));
|
||||
const ids = choices.map(player => player.id);
|
||||
let i = 0;
|
||||
const display = choices.map(player => {
|
||||
const res = `**${i + 1}.** ${player.user.tag}`;
|
||||
i++;
|
||||
return res;
|
||||
});
|
||||
await msg.say(stripIndents`
|
||||
Alright, who do you want to kick off the island? You have 1 minute to vote.
|
||||
|
||||
_Type the number of the player you want to kick._
|
||||
${display.join('\n')}
|
||||
`);
|
||||
const votes = new Collection();
|
||||
const voteFilter = res => {
|
||||
if (!playersLeft.has(res.author.id)) return false;
|
||||
const int = Number.parseInt(res.content, 10);
|
||||
if (int >= 1 && int <= playersLeft.size) {
|
||||
const currentVotes = votes.get(choices[int - 1]);
|
||||
votes.set(ids[int - 1], {
|
||||
votes: currentVotes ? currentVotes + 1 : 1,
|
||||
id: ids[int - 1]
|
||||
});
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const vote = await msg.channel.awaitMessages({
|
||||
filter: voteFilter,
|
||||
max: playersLeft.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);
|
||||
playersLeft.delete(kicked.id);
|
||||
await msg.say(stripIndents`
|
||||
**${kicked.user.tag}** will be kicked off the island.
|
||||
|
||||
${playersLeft.size > 2 ? '_Next round starts in 30 seconds.' : ''}
|
||||
`);
|
||||
if (playersLeft.size > 2) await delay(30000);
|
||||
else break;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
const winners = players.filter(player => playersLeft.has(player.id));
|
||||
return msg.say(`Congrats, ${winners.map(player => player.user.tag).join(' and ')}!`);
|
||||
}
|
||||
};
|
||||
|
||||
+71
-82
@@ -10,6 +10,7 @@ module.exports = class JengaCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'jenga',
|
||||
description: 'Play a game of Jenga with another user or the AI.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Jenga',
|
||||
@@ -29,97 +30,85 @@ module.exports = class JengaCommand extends Command {
|
||||
async run(msg, { opponent }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
}
|
||||
const board = [true, true, true, true, true, true, true, true, true, true];
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let wonByFinalPiece = false;
|
||||
let lastTurnTimeout = false;
|
||||
let i;
|
||||
while (!winner && board.length) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
if (opponent.bot && !userTurn) {
|
||||
i = Math.floor(Math.random() * board.length);
|
||||
} else {
|
||||
const text = stripIndents`
|
||||
${user}, which block do you want to remove? Type \`end\` to forfeit.
|
||||
Each block you go lower on the tower, the more likely the tower falls.
|
||||
`;
|
||||
await msg.say(`${text}\n\n${this.displayBoard(board)}`);
|
||||
const pickFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const choice = res.content;
|
||||
if (choice.toLowerCase() === 'end') return true;
|
||||
const j = Number.parseInt(choice, 10) - 1;
|
||||
return board[j];
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: pickFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
await msg.say('Sorry, time is up!');
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
const picked = Number.parseInt(choice, 10);
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
}
|
||||
const board = [true, true, true, true, true, true, true, true, true, true];
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let wonByFinalPiece = false;
|
||||
let lastTurnTimeout = false;
|
||||
let i;
|
||||
while (!winner && board.length) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
if (opponent.bot && !userTurn) {
|
||||
i = Math.floor(Math.random() * board.length);
|
||||
} else {
|
||||
const text = stripIndents`
|
||||
${user}, which block do you want to remove? Type \`end\` to forfeit.
|
||||
Each block you go lower on the tower, the more likely the tower falls.
|
||||
`;
|
||||
await msg.say(`${text}\n\n${this.displayBoard(board)}`);
|
||||
const pickFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const choice = res.content;
|
||||
if (choice.toLowerCase() === 'end') return true;
|
||||
const j = Number.parseInt(choice, 10) - 1;
|
||||
return board[j];
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: pickFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
await msg.say('Sorry, time is up!');
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
i = picked - 1;
|
||||
}
|
||||
if (board.length === 1) {
|
||||
winner = userTurn ? msg.author : opponent;
|
||||
wonByFinalPiece = true;
|
||||
}
|
||||
const fell = Math.floor(Math.random() * ((board.length + 1) - (i + 1)));
|
||||
if (!fell) {
|
||||
const choice = turn.first().content;
|
||||
const picked = Number.parseInt(choice, 10);
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
await msg.say(`${opponent.bot && !userTurn ? `I pick ${i + 1}. ` : ''}Thankfully, the tower stands.`);
|
||||
board.shift();
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
i = picked - 1;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
let text;
|
||||
if (wonByFinalPiece) {
|
||||
text = opponent.bot && !userTurn
|
||||
? 'I pick up the last piece and win!'
|
||||
: `${winner} picks up the last piece, winning the game!`;
|
||||
} else {
|
||||
text = `${opponent.bot && !userTurn ? `I pick ${i + 1}, a` : 'A'}nd the tower topples!`;
|
||||
if (board.length === 1) {
|
||||
winner = userTurn ? msg.author : opponent;
|
||||
wonByFinalPiece = true;
|
||||
}
|
||||
return msg.say(stripIndents`
|
||||
${text}
|
||||
${winner ? `Congrats, ${winner}!` : 'Looks like it\'s a draw...'}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const fell = Math.floor(Math.random() * ((board.length + 1) - (i + 1)));
|
||||
if (!fell) {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
await msg.say(`${opponent.bot && !userTurn ? `I pick ${i + 1}. ` : ''}Thankfully, the tower stands.`);
|
||||
board.shift();
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
let text;
|
||||
if (wonByFinalPiece) {
|
||||
text = opponent.bot && !userTurn
|
||||
? 'I pick up the last piece and win!'
|
||||
: `${winner} picks up the last piece, winning the game!`;
|
||||
} else {
|
||||
text = `${opponent.bot && !userTurn ? `I pick ${i + 1}, a` : 'A'}nd the tower topples!`;
|
||||
}
|
||||
return msg.say(stripIndents`
|
||||
${text}
|
||||
${winner ? `Congrats, ${winner}!` : 'Looks like it\'s a draw...'}
|
||||
`);
|
||||
}
|
||||
|
||||
displayBoard(board) {
|
||||
|
||||
@@ -14,6 +14,7 @@ module.exports = class LieSwatterCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'lie-swatter',
|
||||
description: 'Players are given a fact and must quickly decide if it\'s True or a Lie.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Jackbox Games',
|
||||
@@ -40,89 +41,80 @@ module.exports = class LieSwatterCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { players }) {
|
||||
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, players, 1, this.client.blacklist.user);
|
||||
let turn = 0;
|
||||
const pts = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
pts.set(player, {
|
||||
points: 0,
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
const questions = await this.fetchQuestions();
|
||||
let lastTurnTimeout = false;
|
||||
while (questions.length) {
|
||||
++turn;
|
||||
const question = questions[0];
|
||||
questions.shift();
|
||||
await msg.say(stripIndents`
|
||||
**${turn}. ${question.category}**
|
||||
${question.question}
|
||||
|
||||
_Is it True or is it a Lie?_
|
||||
`);
|
||||
const filter = res => {
|
||||
if (!awaitedPlayers.includes(res.author.id)) return false;
|
||||
const answer = res.content.toLowerCase();
|
||||
if (trueOptions.includes(answer) || falseOptions.includes(answer)) {
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: pts.size,
|
||||
time: 30000
|
||||
});
|
||||
if (!msgs.size) {
|
||||
await msg.say(`No answers? Well, it was ${question.answer ? 'true' : 'a lie'}.`);
|
||||
if (lastTurnTimeout) {
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const answers = msgs.map(res => {
|
||||
let answer;
|
||||
if (trueOptions.includes(res.content.toLowerCase())) answer = true;
|
||||
else if (falseOptions.includes(res.content.toLowerCase())) answer = false;
|
||||
return { answer, id: res.author.id };
|
||||
});
|
||||
const correct = answers.filter(answer => answer.answer === question.answer);
|
||||
for (const answer of correct) {
|
||||
const player = pts.get(answer.id);
|
||||
if (correct[0].id === answer.id) player.points += 75;
|
||||
else player.points += 50;
|
||||
}
|
||||
await msg.say(stripIndents`
|
||||
It was... **${question.answer ? 'true' : 'a lie'}**!
|
||||
|
||||
_Fastest Guess: ${correct.length ? `${pts.get(correct[0].id).user.tag} (+75 pts)` : 'No One...'}_
|
||||
|
||||
${questions.length ? '_Next round starting in 5 seconds..._' : ''}
|
||||
`);
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
if (questions.length) await delay(5000);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
const winner = pts.sort((a, b) => b.points - a.points).first().user;
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}!
|
||||
|
||||
__**Top 10:**__
|
||||
${this.makeLeaderboard(pts).slice(0, 10).join('\n')}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const awaitedPlayers = await awaitPlayers(msg, players, 1, this.client.blacklist.user);
|
||||
let turn = 0;
|
||||
const pts = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
pts.set(player, {
|
||||
points: 0,
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
const questions = await this.fetchQuestions();
|
||||
let lastTurnTimeout = false;
|
||||
while (questions.length) {
|
||||
++turn;
|
||||
const question = questions[0];
|
||||
questions.shift();
|
||||
await msg.say(stripIndents`
|
||||
**${turn}. ${question.category}**
|
||||
${question.question}
|
||||
|
||||
_Is it True or is it a Lie?_
|
||||
`);
|
||||
const filter = res => {
|
||||
if (!awaitedPlayers.includes(res.author.id)) return false;
|
||||
const answer = res.content.toLowerCase();
|
||||
if (trueOptions.includes(answer) || falseOptions.includes(answer)) {
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: pts.size,
|
||||
time: 30000
|
||||
});
|
||||
if (!msgs.size) {
|
||||
await msg.say(`No answers? Well, it was ${question.answer ? 'true' : 'a lie'}.`);
|
||||
if (lastTurnTimeout) {
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const answers = msgs.map(res => {
|
||||
let answer;
|
||||
if (trueOptions.includes(res.content.toLowerCase())) answer = true;
|
||||
else if (falseOptions.includes(res.content.toLowerCase())) answer = false;
|
||||
return { answer, id: res.author.id };
|
||||
});
|
||||
const correct = answers.filter(answer => answer.answer === question.answer);
|
||||
for (const answer of correct) {
|
||||
const player = pts.get(answer.id);
|
||||
if (correct[0].id === answer.id) player.points += 75;
|
||||
else player.points += 50;
|
||||
}
|
||||
await msg.say(stripIndents`
|
||||
It was... **${question.answer ? 'true' : 'a lie'}**!
|
||||
|
||||
_Fastest Guess: ${correct.length ? `${pts.get(correct[0].id).user.tag} (+75 pts)` : 'No One...'}_
|
||||
|
||||
${questions.length ? '_Next round starting in 5 seconds..._' : ''}
|
||||
`);
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
if (questions.length) await delay(5000);
|
||||
}
|
||||
const winner = pts.sort((a, b) => b.points - a.points).first().user;
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}!
|
||||
|
||||
__**Top 10:**__
|
||||
${this.makeLeaderboard(pts).slice(0, 10).join('\n')}
|
||||
`);
|
||||
}
|
||||
|
||||
async fetchQuestions() {
|
||||
|
||||
+49
-57
@@ -10,13 +10,12 @@ module.exports = class MafiaCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'mafia',
|
||||
description: 'Who is the Mafia? Who is the detective? Will the Mafia kill them all?',
|
||||
guildOnly: true
|
||||
guildOnly: true,
|
||||
game: true
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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.`);
|
||||
const connection = this.client.dispatchers.get(msg.guild.id);
|
||||
if (!connection) {
|
||||
const usage = this.client.registry.commands.get('join').usage();
|
||||
@@ -31,61 +30,54 @@ module.exports = class MafiaCommand extends Command {
|
||||
return msg.reply('Please have at least 5 users in this voice channel before starting.');
|
||||
}
|
||||
const game = new Game(this.client, msg.channel, connection);
|
||||
this.client.games.set(msg.channel.id, game);
|
||||
try {
|
||||
await game.generate(connection.channel.members.filter(m => !m.user.bot).map(m => m.user));
|
||||
await game.playAudio('init');
|
||||
await game.playAudio('rule-ask');
|
||||
await msg.say('Type `yes` to hear a rule explanation.');
|
||||
const rules = await verify(msg.channel, msg.author);
|
||||
if (rules) await game.playAudio('rules');
|
||||
while (!game.shouldEnd) {
|
||||
let killed = null;
|
||||
await game.playAudio(`night-${game.turn}`);
|
||||
await game.playAudio('mafia');
|
||||
const mafia = game.players.filter(p => p.role === 'mafia');
|
||||
const choices = await Promise.all(mafia.map(player => player.dmRound()));
|
||||
const randomizer = choices.filter(c => c !== null);
|
||||
if (randomizer.length) killed = game.players.get(randomizer[Math.floor(Math.random() * randomizer.length)]);
|
||||
await game.playAudio('mafia-decision-made');
|
||||
const detective = game.players.find(p => p.role === 'detective');
|
||||
if (detective) {
|
||||
await game.playAudio('detective');
|
||||
await detective.dmRound();
|
||||
await game.playAudio('detective-decision-made');
|
||||
}
|
||||
await game.playAudio(`day-${game.turn}`);
|
||||
if (killed) {
|
||||
const story = Math.floor(Math.random() * storyCount) + 1;
|
||||
await game.playAudio(`story-${story}`);
|
||||
await game.playAudio('reveal-deceased');
|
||||
await msg.say(`Deceased: **${killed}**`);
|
||||
game.players.delete(killed.id);
|
||||
} else {
|
||||
await game.playAudio('no-deceased');
|
||||
}
|
||||
await game.playAudio('vote');
|
||||
const playersArr = Array.from(game.players.values());
|
||||
const votes = await game.getVotes(playersArr);
|
||||
if (!votes) {
|
||||
await game.playAudio('no-votes');
|
||||
continue;
|
||||
}
|
||||
const hanged = game.getHanged(votes, playersArr);
|
||||
await game.playAudio('hanged');
|
||||
await msg.say(`Hanged: **${hanged.user}**`);
|
||||
game.players.delete(hanged.id);
|
||||
++game.turn;
|
||||
await game.generate(connection.channel.members.filter(m => !m.user.bot).map(m => m.user));
|
||||
await game.playAudio('init');
|
||||
await game.playAudio('rule-ask');
|
||||
await msg.say('Type `yes` to hear a rule explanation.');
|
||||
const rules = await verify(msg.channel, msg.author);
|
||||
if (rules) await game.playAudio('rules');
|
||||
while (!game.shouldEnd) {
|
||||
let killed = null;
|
||||
await game.playAudio(`night-${game.turn}`);
|
||||
await game.playAudio('mafia');
|
||||
const mafia = game.players.filter(p => p.role === 'mafia');
|
||||
const choices = await Promise.all(mafia.map(player => player.dmRound()));
|
||||
const randomizer = choices.filter(c => c !== null);
|
||||
if (randomizer.length) killed = game.players.get(randomizer[Math.floor(Math.random() * randomizer.length)]);
|
||||
await game.playAudio('mafia-decision-made');
|
||||
const detective = game.players.find(p => p.role === 'detective');
|
||||
if (detective) {
|
||||
await game.playAudio('detective');
|
||||
await detective.dmRound();
|
||||
await game.playAudio('detective-decision-made');
|
||||
}
|
||||
const mafia = game.players.find(p => p.role === 'mafia');
|
||||
if (mafia) await game.playAudio('mafia-wins');
|
||||
else await game.playAudio('mafia-loses');
|
||||
await game.playAudio('credits');
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return null;
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
await game.playAudio(`day-${game.turn}`);
|
||||
if (killed) {
|
||||
const story = Math.floor(Math.random() * storyCount) + 1;
|
||||
await game.playAudio(`story-${story}`);
|
||||
await game.playAudio('reveal-deceased');
|
||||
await msg.say(`Deceased: **${killed}**`);
|
||||
game.players.delete(killed.id);
|
||||
} else {
|
||||
await game.playAudio('no-deceased');
|
||||
}
|
||||
await game.playAudio('vote');
|
||||
const playersArr = Array.from(game.players.values());
|
||||
const votes = await game.getVotes(playersArr);
|
||||
if (!votes) {
|
||||
await game.playAudio('no-votes');
|
||||
continue;
|
||||
}
|
||||
const hanged = game.getHanged(votes, playersArr);
|
||||
await game.playAudio('hanged');
|
||||
await msg.say(`Hanged: **${hanged.user}**`);
|
||||
game.players.delete(hanged.id);
|
||||
++game.turn;
|
||||
}
|
||||
const mafia = game.players.find(p => p.role === 'mafia');
|
||||
if (mafia) await game.playAudio('mafia-wins');
|
||||
else await game.playAudio('mafia-loses');
|
||||
await game.playAudio('credits');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
+84
-95
@@ -11,6 +11,7 @@ module.exports = class NimCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'nim',
|
||||
description: 'Play a game of nim with another user or the AI.',
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -30,52 +31,85 @@ module.exports = class NimCommand extends Command {
|
||||
async run(msg, { opponent, rows }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
}
|
||||
const board = this.generateBoard(rows);
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
let firstTurn = true;
|
||||
const objectEmoji = emoji[Math.floor(Math.random() * emoji.length)];
|
||||
while (!winner) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
if (!userTurn && opponent.bot) {
|
||||
const turn = this.computerTurn(board);
|
||||
await msg.say(`For my turn, I remove **${turn[1]}** ${objectEmoji} from **row ${turn[0] + 1}**.`);
|
||||
} else {
|
||||
await msg.say(stripIndents`
|
||||
${user}, from which row do you want to remove from? Type \`end\` to forfeit.
|
||||
After this step, you will decide how many ${objectEmoji} to remove from that row.
|
||||
|
||||
${this.displayBoard(board, objectEmoji)}
|
||||
|
||||
${firstTurn ? '_In Nim, you win by forcing the opponent to take the last object._' : ''}
|
||||
`);
|
||||
const pickFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const choice = res.content;
|
||||
if (choice.toLowerCase() === 'end') return true;
|
||||
const i = Number.parseInt(choice, 10) - 1;
|
||||
return board[i] && board[i] > 0;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: pickFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
await msg.say('Sorry, time is up!');
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
const board = this.generateBoard(rows);
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
let firstTurn = true;
|
||||
const objectEmoji = emoji[Math.floor(Math.random() * emoji.length)];
|
||||
while (!winner) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
if (!userTurn && opponent.bot) {
|
||||
const turn = this.computerTurn(board);
|
||||
await msg.say(`For my turn, I remove **${turn[1]}** ${objectEmoji} from **row ${turn[0] + 1}**.`);
|
||||
const choice = turn.first().content;
|
||||
const picked = Number.parseInt(choice, 10);
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const row = board[picked - 1];
|
||||
let rowPicked;
|
||||
if (row === 1) {
|
||||
rowPicked = 1;
|
||||
} else {
|
||||
await msg.say(stripIndents`
|
||||
${user}, from which row do you want to remove from? Type \`end\` to forfeit.
|
||||
After this step, you will decide how many ${objectEmoji} to remove from that row.
|
||||
${user}, how many ${objectEmoji} do you want to take from row ${picked}? Type \`end\` to forfeit.
|
||||
If you want to go back, type \`back\`.
|
||||
|
||||
${this.displayBoard(board, objectEmoji)}
|
||||
|
||||
${firstTurn ? '_In Nim, you win by forcing the opponent to take the last object._' : ''}
|
||||
${nums[picked - 1]}${objectEmoji.repeat(row)}
|
||||
`);
|
||||
const pickFilter = res => {
|
||||
const rowFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const choice = res.content;
|
||||
if (choice.toLowerCase() === 'end') return true;
|
||||
const i = Number.parseInt(choice, 10) - 1;
|
||||
return board[i] && board[i] > 0;
|
||||
const chosen = res.content;
|
||||
if (chosen.toLowerCase() === 'end' || chosen.toLowerCase() === 'back') return true;
|
||||
const i = Number.parseInt(chosen, 10);
|
||||
return i <= row && i > 0;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: pickFilter,
|
||||
const rowTurn = await msg.channel.awaitMessages({
|
||||
filter: rowFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
if (lastTurnTimeout) {
|
||||
if (!rowTurn.size) {
|
||||
if (lastTurnTimeout) { // eslint-disable-line max-depth
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
@@ -85,71 +119,26 @@ module.exports = class NimCommand extends Command {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
const picked = Number.parseInt(choice, 10);
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
const rowChoice = rowTurn.first().content;
|
||||
rowPicked = Number.parseInt(rowChoice, 10);
|
||||
if (rowChoice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const row = board[picked - 1];
|
||||
let rowPicked;
|
||||
if (row === 1) {
|
||||
rowPicked = 1;
|
||||
} else {
|
||||
await msg.say(stripIndents`
|
||||
${user}, how many ${objectEmoji} do you want to take from row ${picked}? Type \`end\` to forfeit.
|
||||
If you want to go back, type \`back\`.
|
||||
|
||||
${nums[picked - 1]}${objectEmoji.repeat(row)}
|
||||
`);
|
||||
const rowFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const chosen = res.content;
|
||||
if (chosen.toLowerCase() === 'end' || chosen.toLowerCase() === 'back') return true;
|
||||
const i = Number.parseInt(chosen, 10);
|
||||
return i <= row && i > 0;
|
||||
};
|
||||
const rowTurn = await msg.channel.awaitMessages({
|
||||
filter: rowFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!rowTurn.size) {
|
||||
if (lastTurnTimeout) { // eslint-disable-line max-depth
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
await msg.say('Sorry, time is up!');
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const rowChoice = rowTurn.first().content;
|
||||
rowPicked = Number.parseInt(rowChoice, 10);
|
||||
if (rowChoice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
if (rowChoice.toLowerCase() === 'back') continue;
|
||||
}
|
||||
board[picked - 1] -= rowPicked;
|
||||
if (rowChoice.toLowerCase() === 'back') continue;
|
||||
}
|
||||
if (!userTurn && firstTurn) firstTurn = false;
|
||||
if (!board.some(r => r !== 0)) {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
board[picked - 1] -= rowPicked;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(`Congrats, ${winner}! You forced your opponent to pick the final object!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
if (!userTurn && firstTurn) firstTurn = false;
|
||||
if (!board.some(r => r !== 0)) {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(`Congrats, ${winner}! You forced your opponent to pick the final object!`);
|
||||
}
|
||||
|
||||
displayBoard(board, objectEmoji) {
|
||||
|
||||
@@ -17,6 +17,7 @@ module.exports = class ObstructionCommand extends Command {
|
||||
memberName: 'obstruction',
|
||||
description: 'Play a game of Obstruction with another user.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -37,97 +38,85 @@ module.exports = class ObstructionCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be played against.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
const board = this.generateBoard(size);
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (!winner) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${user}, at what coordinates do you want to place your piece (ex. 1,1)? Type \`end\` to forfeit.
|
||||
Every piece you place will obstruct the 8 pieces around it.
|
||||
|
||||
${this.displayBoard(board)}
|
||||
`);
|
||||
const possibleMoves = this.possibleMoves(board);
|
||||
const turnFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
const coordPicked = pick.match(turnRegex);
|
||||
if (!coordPicked) return false;
|
||||
const x = Number.parseInt(coordPicked[1], 10);
|
||||
const y = Number.parseInt(coordPicked[2], 10);
|
||||
if (x > size || y > size || x < 1 || y < 1) return false;
|
||||
if (!possibleMoves.includes(`${x - 1},${y - 1}`)) return false;
|
||||
return true;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: turnFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const matched = choice.match(turnRegex);
|
||||
const x = Number.parseInt(matched[1], 10) - 1;
|
||||
const y = Number.parseInt(matched[2], 10) - 1;
|
||||
board[y][x] = userTurn ? 'X' : 'O';
|
||||
if (board[y - 1]) {
|
||||
if (board[y - 1][x]) board[y - 1][x] = 'B';
|
||||
if (board[y - 1][x - 1]) board[y - 1][x - 1] = 'B';
|
||||
if (board[y - 1][x + 1]) board[y - 1][x + 1] = 'B';
|
||||
}
|
||||
if (board[y + 1]) {
|
||||
if (board[y + 1][x]) board[y + 1][x] = 'B';
|
||||
if (board[y + 1][x + 1]) board[y + 1][x + 1] = 'B';
|
||||
if (board[y + 1][x - 1]) board[y + 1][x - 1] = 'B';
|
||||
}
|
||||
if (board[y][x - 1]) board[y][x - 1] = 'B';
|
||||
if (board[y][x + 1]) board[y][x + 1] = 'B';
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
const oppoPossible = this.possibleMoves(board);
|
||||
if (!oppoPossible.length) {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}! Your opponent has no possible moves left!
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
const board = this.generateBoard(size);
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (!winner) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${user}, at what coordinates do you want to place your piece (ex. 1,1)? Type \`end\` to forfeit.
|
||||
Every piece you place will obstruct the 8 pieces around it.
|
||||
|
||||
${this.displayBoard(board)}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const possibleMoves = this.possibleMoves(board);
|
||||
const turnFilter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
const coordPicked = pick.match(turnRegex);
|
||||
if (!coordPicked) return false;
|
||||
const x = Number.parseInt(coordPicked[1], 10);
|
||||
const y = Number.parseInt(coordPicked[2], 10);
|
||||
if (x > size || y > size || x < 1 || y < 1) return false;
|
||||
if (!possibleMoves.includes(`${x - 1},${y - 1}`)) return false;
|
||||
return true;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter: turnFilter,
|
||||
max: 1,
|
||||
time: 60000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const matched = choice.match(turnRegex);
|
||||
const x = Number.parseInt(matched[1], 10) - 1;
|
||||
const y = Number.parseInt(matched[2], 10) - 1;
|
||||
board[y][x] = userTurn ? 'X' : 'O';
|
||||
if (board[y - 1]) {
|
||||
if (board[y - 1][x]) board[y - 1][x] = 'B';
|
||||
if (board[y - 1][x - 1]) board[y - 1][x - 1] = 'B';
|
||||
if (board[y - 1][x + 1]) board[y - 1][x + 1] = 'B';
|
||||
}
|
||||
if (board[y + 1]) {
|
||||
if (board[y + 1][x]) board[y + 1][x] = 'B';
|
||||
if (board[y + 1][x + 1]) board[y + 1][x + 1] = 'B';
|
||||
if (board[y + 1][x - 1]) board[y + 1][x - 1] = 'B';
|
||||
}
|
||||
if (board[y][x - 1]) board[y][x - 1] = 'B';
|
||||
if (board[y][x + 1]) board[y][x + 1] = 'B';
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
const oppoPossible = this.possibleMoves(board);
|
||||
if (!oppoPossible.length) {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}! Your opponent has no possible moves left!
|
||||
|
||||
${this.displayBoard(board)}
|
||||
`);
|
||||
}
|
||||
|
||||
possibleMoves(board) {
|
||||
|
||||
@@ -10,6 +10,7 @@ module.exports = class PickANumberCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'pick-a-number',
|
||||
description: 'Two players pick a number between 1 and 10. Whoever\'s closer wins.',
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -22,66 +23,48 @@ module.exports = class PickANumberCommand extends Command {
|
||||
async run(msg, { opponent }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 clientOpp = opponent.id === this.client.user.id;
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
}
|
||||
await msg.say(`${msg.author}, pick a number from 1 to 10.`);
|
||||
let userTurn = true;
|
||||
let player1Pick = null;
|
||||
const filter = res => {
|
||||
if (res.author.id !== (userTurn ? msg.author.id : opponent.id)) return false;
|
||||
const num = Number.parseInt(res.content, 10);
|
||||
if (!userTurn && num === player1Pick) return false;
|
||||
return num && nums.includes(num);
|
||||
};
|
||||
const player1 = await msg.channel.awaitMessages({
|
||||
const clientOpp = opponent.id === this.client.user.id;
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
}
|
||||
await msg.say(`${msg.author}, pick a number from 1 to 10.`);
|
||||
let userTurn = true;
|
||||
let player1Pick = null;
|
||||
const filter = res => {
|
||||
if (res.author.id !== (userTurn ? msg.author.id : opponent.id)) return false;
|
||||
const num = Number.parseInt(res.content, 10);
|
||||
if (!userTurn && num === player1Pick) return false;
|
||||
return num && nums.includes(num);
|
||||
};
|
||||
const player1 = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!player1.size) return msg.say('I guess you didn\'t want to play after all...');
|
||||
player1Pick = Number.parseInt(player1.first().content, 10);
|
||||
let player2Pick;
|
||||
if (opponent.bot) {
|
||||
const valid = nums.filter(num => num !== player1Pick);
|
||||
player2Pick = valid[Math.floor(Math.random() * valid.length)];
|
||||
await msg.say(`Okay, ${clientOpp ? 'I' : `${opponent}`} pick${clientOpp ? '' : 's'} ${player2Pick}!`);
|
||||
} else {
|
||||
userTurn = false;
|
||||
await msg.say(`${opponent}, pick a number from 1 to 10, except ${player1Pick}.`);
|
||||
const player2 = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!player1.size) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('I guess you didn\'t want to play after all...');
|
||||
}
|
||||
player1Pick = Number.parseInt(player1.first().content, 10);
|
||||
let player2Pick;
|
||||
if (opponent.bot) {
|
||||
const valid = nums.filter(num => num !== player1Pick);
|
||||
player2Pick = valid[Math.floor(Math.random() * valid.length)];
|
||||
await msg.say(`Okay, ${clientOpp ? 'I' : `${opponent}`} pick${clientOpp ? '' : 's'} ${player2Pick}!`);
|
||||
} else {
|
||||
userTurn = false;
|
||||
await msg.say(`${opponent}, pick a number from 1 to 10, except ${player1Pick}.`);
|
||||
const player2 = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!player2.size) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('I guess you didn\'t want to play after all...');
|
||||
}
|
||||
player2Pick = Number.parseInt(player2.first().content, 10);
|
||||
}
|
||||
const num = Math.floor(Math.random() * 10) + 1;
|
||||
const winNum = [player1Pick, player2Pick].sort((a, b) => Math.abs(num - a) - Math.abs(num - b))[0];
|
||||
const winner = winNum === player1Pick ? msg.author : opponent;
|
||||
const clientWin = clientOpp && this.client.user.id === winner.id;
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say(`The number was **${num}**! ${clientWin ? 'I' : winner} win${clientWin ? '' : 's'}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
if (!player2.size) return msg.say('I guess you didn\'t want to play after all...');
|
||||
player2Pick = Number.parseInt(player2.first().content, 10);
|
||||
}
|
||||
const num = Math.floor(Math.random() * 10) + 1;
|
||||
const winNum = [player1Pick, player2Pick].sort((a, b) => Math.abs(num - a) - Math.abs(num - b))[0];
|
||||
const winner = winNum === player1Pick ? msg.author : opponent;
|
||||
const clientWin = clientOpp && this.client.user.id === winner.id;
|
||||
return msg.say(`The number was **${num}**! ${clientWin ? 'I' : winner} win${clientWin ? '' : 's'}!`);
|
||||
}
|
||||
};
|
||||
|
||||
+143
-163
@@ -19,6 +19,7 @@ module.exports = class PokerCommand extends Command {
|
||||
memberName: 'poker',
|
||||
description: `Play poker with up to ${max - 1} other users.`,
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'playersCount',
|
||||
@@ -31,180 +32,159 @@ module.exports = class PokerCommand extends Command {
|
||||
}
|
||||
|
||||
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,
|
||||
data: {
|
||||
deck: new Deck(),
|
||||
players: new Collection(),
|
||||
turnData: {
|
||||
pot: 0,
|
||||
currentBet: 0,
|
||||
highestBetter: null
|
||||
}
|
||||
const awaitedPlayers = await awaitPlayers(msg, playersCount, min, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) return msg.say('Game could not be started...');
|
||||
const players = new Collection();
|
||||
const deck = new Deck();
|
||||
const turnData = { pot: 0, currentBet: 0, highestBetter: 0 };
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
money: 2000,
|
||||
id: player,
|
||||
hand: [],
|
||||
user: await this.client.users.fetch(player),
|
||||
currentBet: 0,
|
||||
hasGoneOnce: false,
|
||||
strikes: 0,
|
||||
isAllIn: false
|
||||
});
|
||||
}
|
||||
let winner = null;
|
||||
const rotation = players.map(p => p.id);
|
||||
while (!winner) {
|
||||
for (const player of rotation) {
|
||||
if (players.has(player)) continue;
|
||||
removeFromArray(rotation, player);
|
||||
}
|
||||
});
|
||||
try {
|
||||
const awaitedPlayers = await awaitPlayers(msg, playersCount, min, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Game could not be started...');
|
||||
}
|
||||
const { players, deck, turnData } = this.client.games.get(msg.channel.id).data;
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
money: 2000,
|
||||
id: player,
|
||||
hand: [],
|
||||
user: await this.client.users.fetch(player),
|
||||
currentBet: 0,
|
||||
hasGoneOnce: false,
|
||||
strikes: 0,
|
||||
isAllIn: false
|
||||
});
|
||||
}
|
||||
let winner = null;
|
||||
const rotation = players.map(p => p.id);
|
||||
while (!winner) {
|
||||
for (const player of rotation) {
|
||||
if (players.has(player)) continue;
|
||||
removeFromArray(rotation, player);
|
||||
}
|
||||
const bigBlind = players.get(rotation[1]);
|
||||
bigBlind.money -= bigBlindAmount;
|
||||
bigBlind.currentBet += bigBlindAmount;
|
||||
const smallBlind = players.get(rotation[2] || rotation[0]);
|
||||
smallBlind.money -= smallBlindAmount;
|
||||
smallBlind.currentBet += smallBlindAmount;
|
||||
rotation.push(rotation[0]);
|
||||
rotation.shift();
|
||||
const folded = [];
|
||||
await msg.say('Dealing player hands...');
|
||||
for (const player of players.values()) {
|
||||
player.hand.push(...deck.draw(2));
|
||||
try {
|
||||
await player.user.send(stripIndents`
|
||||
_Back to ${msg.channel}._
|
||||
const bigBlind = players.get(rotation[1]);
|
||||
bigBlind.money -= bigBlindAmount;
|
||||
bigBlind.currentBet += bigBlindAmount;
|
||||
const smallBlind = players.get(rotation[2] || rotation[0]);
|
||||
smallBlind.money -= smallBlindAmount;
|
||||
smallBlind.currentBet += smallBlindAmount;
|
||||
rotation.push(rotation[0]);
|
||||
rotation.shift();
|
||||
const folded = [];
|
||||
await msg.say('Dealing player hands...');
|
||||
for (const player of players.values()) {
|
||||
player.hand.push(...deck.draw(2));
|
||||
try {
|
||||
await player.user.send(stripIndents`
|
||||
_Back to ${msg.channel}._
|
||||
|
||||
**Your Poker Hand:**
|
||||
${player.hand.map(c => c.textDisplay).join('\n')}
|
||||
**Your Poker Hand:**
|
||||
${player.hand.map(c => c.textDisplay).join('\n')}
|
||||
|
||||
**Money:** $${formatNumber(player.money)}
|
||||
${bigBlind.id === player.id ? '_You are the big blind._' : ''}
|
||||
${smallBlind.id === player.id ? '_You are the small blind._' : ''}
|
||||
`);
|
||||
} catch {
|
||||
await msg.say(`${player.user}, I couldn't send your hand! Turn on DMs!`);
|
||||
}
|
||||
}
|
||||
turnData.pot = bigBlindAmount + smallBlindAmount;
|
||||
turnData.currentBet = bigBlindAmount;
|
||||
turnData.highestBetter = bigBlind;
|
||||
let keepGoing = await this.gameRound(msg, players, deck, folded, turnData, bigBlind, smallBlind);
|
||||
if (!keepGoing) {
|
||||
if (players.size < 2) {
|
||||
winner = players.first();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const dealerHand = deck.draw(3);
|
||||
await msg.say(stripIndents`
|
||||
**Dealer Hand:**
|
||||
${dealerHand.map(card => card.textDisplay).join('\n')}
|
||||
|
||||
_Next betting round begins in 10 seconds._
|
||||
`);
|
||||
await delay(10000);
|
||||
keepGoing = await this.gameRound(msg, players, deck, folded, turnData, bigBlind, smallBlind);
|
||||
if (!keepGoing) {
|
||||
if (players.size < 2) {
|
||||
winner = players.first();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
dealerHand.push(deck.draw());
|
||||
await msg.say(stripIndents`
|
||||
**Dealer Hand:**
|
||||
${dealerHand.map(card => card.textDisplay).join('\n')}
|
||||
|
||||
_Next betting round begins in 10 seconds._
|
||||
`);
|
||||
await delay(10000);
|
||||
keepGoing = await this.gameRound(msg, players, deck, folded, turnData, bigBlind, smallBlind);
|
||||
if (!keepGoing) {
|
||||
if (players.size < 2) {
|
||||
winner = players.first();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
dealerHand.push(deck.draw());
|
||||
await msg.say(stripIndents`
|
||||
**Dealer Hand:**
|
||||
${dealerHand.map(card => card.textDisplay).join('\n')}
|
||||
|
||||
_Next betting round begins in 10 seconds._
|
||||
`);
|
||||
await delay(10000);
|
||||
keepGoing = await this.gameRound(msg, players, deck, folded, turnData, bigBlind, smallBlind);
|
||||
if (!keepGoing) {
|
||||
if (players.size < 2) {
|
||||
winner = players.first();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const solved = [];
|
||||
for (const playerID of rotation) {
|
||||
if (folded.includes(playerID)) continue;
|
||||
const player = players.get(playerID);
|
||||
const solvedHand = Hand.solve([
|
||||
...player.hand.map(card => card.pokersolverKey),
|
||||
...dealerHand.map(card => card.pokersolverKey)
|
||||
]);
|
||||
solvedHand.user = player;
|
||||
solved.push(solvedHand);
|
||||
}
|
||||
const winners = Hand.winners(solved);
|
||||
if (winners.length > 1) {
|
||||
await msg.say(stripIndents`
|
||||
The pot will be split between ${list(winners.map(w => `**${w.user.user}**`))}.
|
||||
${winners.map(winner.descr).join(', ')}
|
||||
|
||||
__**Results**__
|
||||
${solved.map(solve => `${solve.user.user.tag}: ${solve.descr}`).join('\n')}
|
||||
|
||||
_Next game starting in 15 seconds._
|
||||
**Money:** $${formatNumber(player.money)}
|
||||
${bigBlind.id === player.id ? '_You are the big blind._' : ''}
|
||||
${smallBlind.id === player.id ? '_You are the small blind._' : ''}
|
||||
`);
|
||||
const splitPot = turnData.pot / winners.length;
|
||||
for (const win of winners) win.user.money += splitPot;
|
||||
} else {
|
||||
await msg.say(stripIndents`
|
||||
${winners[0].user.user} takes the pot, with **${winners[0].descr}**.
|
||||
|
||||
__**Results**__
|
||||
${solved.map(solve => `${solve.user.user.tag}: ${solve.descr}`).join('\n')}
|
||||
|
||||
_Next game starting in 15 seconds._
|
||||
`);
|
||||
winners[0].user.money += turnData.pot;
|
||||
} catch {
|
||||
await msg.say(`${player.user}, I couldn't send your hand! Turn on DMs!`);
|
||||
}
|
||||
await this.resetGame(msg, players, deck);
|
||||
}
|
||||
turnData.pot = bigBlindAmount + smallBlindAmount;
|
||||
turnData.currentBet = bigBlindAmount;
|
||||
turnData.highestBetter = bigBlind;
|
||||
let keepGoing = await this.gameRound(msg, players, deck, folded, turnData, bigBlind, smallBlind);
|
||||
if (!keepGoing) {
|
||||
if (players.size < 2) {
|
||||
winner = players.first();
|
||||
break;
|
||||
}
|
||||
await delay(15000);
|
||||
continue;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say(`Congrats, ${winner.user}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const dealerHand = deck.draw(3);
|
||||
await msg.say(stripIndents`
|
||||
**Dealer Hand:**
|
||||
${dealerHand.map(card => card.textDisplay).join('\n')}
|
||||
|
||||
_Next betting round begins in 10 seconds._
|
||||
`);
|
||||
await delay(10000);
|
||||
keepGoing = await this.gameRound(msg, players, deck, folded, turnData, bigBlind, smallBlind);
|
||||
if (!keepGoing) {
|
||||
if (players.size < 2) {
|
||||
winner = players.first();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
dealerHand.push(deck.draw());
|
||||
await msg.say(stripIndents`
|
||||
**Dealer Hand:**
|
||||
${dealerHand.map(card => card.textDisplay).join('\n')}
|
||||
|
||||
_Next betting round begins in 10 seconds._
|
||||
`);
|
||||
await delay(10000);
|
||||
keepGoing = await this.gameRound(msg, players, deck, folded, turnData, bigBlind, smallBlind);
|
||||
if (!keepGoing) {
|
||||
if (players.size < 2) {
|
||||
winner = players.first();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
dealerHand.push(deck.draw());
|
||||
await msg.say(stripIndents`
|
||||
**Dealer Hand:**
|
||||
${dealerHand.map(card => card.textDisplay).join('\n')}
|
||||
|
||||
_Next betting round begins in 10 seconds._
|
||||
`);
|
||||
await delay(10000);
|
||||
keepGoing = await this.gameRound(msg, players, deck, folded, turnData, bigBlind, smallBlind);
|
||||
if (!keepGoing) {
|
||||
if (players.size < 2) {
|
||||
winner = players.first();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const solved = [];
|
||||
for (const playerID of rotation) {
|
||||
if (folded.includes(playerID)) continue;
|
||||
const player = players.get(playerID);
|
||||
const solvedHand = Hand.solve([
|
||||
...player.hand.map(card => card.pokersolverKey),
|
||||
...dealerHand.map(card => card.pokersolverKey)
|
||||
]);
|
||||
solvedHand.user = player;
|
||||
solved.push(solvedHand);
|
||||
}
|
||||
const winners = Hand.winners(solved);
|
||||
if (winners.length > 1) {
|
||||
await msg.say(stripIndents`
|
||||
The pot will be split between ${list(winners.map(w => `**${w.user.user}**`))}.
|
||||
${winners.map(winner.descr).join(', ')}
|
||||
|
||||
__**Results**__
|
||||
${solved.map(solve => `${solve.user.user.tag}: ${solve.descr}`).join('\n')}
|
||||
|
||||
_Next game starting in 15 seconds._
|
||||
`);
|
||||
const splitPot = turnData.pot / winners.length;
|
||||
for (const win of winners) win.user.money += splitPot;
|
||||
} else {
|
||||
await msg.say(stripIndents`
|
||||
${winners[0].user.user} takes the pot, with **${winners[0].descr}**.
|
||||
|
||||
__**Results**__
|
||||
${solved.map(solve => `${solve.user.user.tag}: ${solve.descr}`).join('\n')}
|
||||
|
||||
_Next game starting in 15 seconds._
|
||||
`);
|
||||
winners[0].user.money += turnData.pot;
|
||||
}
|
||||
await this.resetGame(msg, players, deck);
|
||||
if (players.size < 2) {
|
||||
winner = players.first();
|
||||
break;
|
||||
}
|
||||
await delay(15000);
|
||||
}
|
||||
return msg.say(`Congrats, ${winner.user}!`);
|
||||
}
|
||||
|
||||
determineActions(turnPlayer, currentBet, playerAllIn) {
|
||||
|
||||
@@ -14,6 +14,7 @@ module.exports = class QuizDuelCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'quiz-duel',
|
||||
description: 'Answer a series of quiz questions against other opponents.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Open Trivia DB',
|
||||
@@ -34,89 +35,80 @@ module.exports = class QuizDuelCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { players }) {
|
||||
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, players, 1, this.client.blacklist.user);
|
||||
let turn = 0;
|
||||
const pts = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
pts.set(player, {
|
||||
points: 0,
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
const questions = await this.fetchQuestions();
|
||||
let lastTurnTimeout = false;
|
||||
while (questions.length) {
|
||||
++turn;
|
||||
const question = questions[0];
|
||||
questions.shift();
|
||||
await msg.say(stripIndents`
|
||||
**${turn}. ${question.category}**
|
||||
${question.question}
|
||||
${question.answers.map((answer, i) => `**${choices[i]}.** ${answer}`).join('\n')}
|
||||
`);
|
||||
const filter = res => {
|
||||
if (!awaitedPlayers.includes(res.author.id)) return false;
|
||||
const answer = res.content.toUpperCase();
|
||||
if (choices.includes(answer)) {
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: pts.size,
|
||||
time: 30000
|
||||
});
|
||||
if (!msgs.size) {
|
||||
await msg.say(`No answers? Well, it was **${question.correct}**.`);
|
||||
if (lastTurnTimeout) {
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const answers = msgs.map(res => {
|
||||
const choice = choices.indexOf(res.content.toUpperCase());
|
||||
return {
|
||||
answer: question.answers[choice],
|
||||
id: res.author.id
|
||||
};
|
||||
});
|
||||
const correct = answers.filter(answer => answer.answer === question.correct);
|
||||
for (const answer of correct) {
|
||||
const player = pts.get(answer.id);
|
||||
if (correct[0].id === answer.id) player.points += 75;
|
||||
else player.points += 50;
|
||||
}
|
||||
await msg.say(stripIndents`
|
||||
It was... **${question.correct}**!
|
||||
|
||||
_Fastest Guess: ${correct.length ? `${pts.get(correct[0].id).user.tag} (+75 pts)` : 'No One...'}_
|
||||
|
||||
${questions.length ? '_Next round starting in 5 seconds..._' : ''}
|
||||
`);
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
if (questions.length) await delay(5000);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
const winner = pts.sort((a, b) => b.points - a.points).first().user;
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}!
|
||||
|
||||
__**Top 10:**__
|
||||
${this.makeLeaderboard(pts).slice(0, 10).join('\n')}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const awaitedPlayers = await awaitPlayers(msg, players, 1, this.client.blacklist.user);
|
||||
let turn = 0;
|
||||
const pts = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
pts.set(player, {
|
||||
points: 0,
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
const questions = await this.fetchQuestions();
|
||||
let lastTurnTimeout = false;
|
||||
while (questions.length) {
|
||||
++turn;
|
||||
const question = questions[0];
|
||||
questions.shift();
|
||||
await msg.say(stripIndents`
|
||||
**${turn}. ${question.category}**
|
||||
${question.question}
|
||||
${question.answers.map((answer, i) => `**${choices[i]}.** ${answer}`).join('\n')}
|
||||
`);
|
||||
const filter = res => {
|
||||
if (!awaitedPlayers.includes(res.author.id)) return false;
|
||||
const answer = res.content.toUpperCase();
|
||||
if (choices.includes(answer)) {
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: pts.size,
|
||||
time: 30000
|
||||
});
|
||||
if (!msgs.size) {
|
||||
await msg.say(`No answers? Well, it was **${question.correct}**.`);
|
||||
if (lastTurnTimeout) {
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const answers = msgs.map(res => {
|
||||
const choice = choices.indexOf(res.content.toUpperCase());
|
||||
return {
|
||||
answer: question.answers[choice],
|
||||
id: res.author.id
|
||||
};
|
||||
});
|
||||
const correct = answers.filter(answer => answer.answer === question.correct);
|
||||
for (const answer of correct) {
|
||||
const player = pts.get(answer.id);
|
||||
if (correct[0].id === answer.id) player.points += 75;
|
||||
else player.points += 50;
|
||||
}
|
||||
await msg.say(stripIndents`
|
||||
It was... **${question.correct}**!
|
||||
|
||||
_Fastest Guess: ${correct.length ? `${pts.get(correct[0].id).user.tag} (+75 pts)` : 'No One...'}_
|
||||
|
||||
${questions.length ? '_Next round starting in 5 seconds..._' : ''}
|
||||
`);
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
if (questions.length) await delay(5000);
|
||||
}
|
||||
const winner = pts.sort((a, b) => b.points - a.points).first().user;
|
||||
return msg.say(stripIndents`
|
||||
Congrats, ${winner}!
|
||||
|
||||
__**Top 10:**__
|
||||
${this.makeLeaderboard(pts).slice(0, 10).join('\n')}
|
||||
`);
|
||||
}
|
||||
|
||||
async fetchQuestions() {
|
||||
|
||||
@@ -11,6 +11,7 @@ module.exports = class RussianRouletteCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'russian-roulette',
|
||||
description: 'Who will pull the trigger and die first?',
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'playersCount',
|
||||
@@ -23,87 +24,73 @@ module.exports = class RussianRouletteCommand extends Command {
|
||||
}
|
||||
|
||||
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, 1, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Game could not be started...');
|
||||
}
|
||||
const players = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
}
|
||||
players.set(this.client.user.id, {
|
||||
id: this.client.user.id,
|
||||
user: this.client.user
|
||||
const awaitedPlayers = await awaitPlayers(msg, playersCount, 1, this.client.blacklist.user);
|
||||
if (!awaitedPlayers) return msg.say('Game could not be started...');
|
||||
const players = new Collection();
|
||||
for (const player of awaitedPlayers) {
|
||||
players.set(player, {
|
||||
id: player,
|
||||
user: await this.client.users.fetch(player)
|
||||
});
|
||||
const turn = shuffle(players.map(player => player.id));
|
||||
const gun = shuffle([true, false, false, false, false, false, false, false]);
|
||||
let round = 0;
|
||||
let loser = null;
|
||||
let winner = null;
|
||||
const wallOfShame = [];
|
||||
while (!loser && !winner) {
|
||||
const player = players.get(turn[0]);
|
||||
turn.push(turn[0]);
|
||||
turn.shift();
|
||||
if (gun[round]) {
|
||||
await msg.say(`**${player.user.tag}** pulls the trigger... **And dies!**`);
|
||||
loser = player;
|
||||
} else {
|
||||
const nextUp = players.get(turn[0]).user;
|
||||
await msg.say(stripIndents`
|
||||
**${player.user.tag}** pulls the trigger... **And lives...**
|
||||
${nextUp.bot ? '' : `Will you take the gun, ${nextUp}?`}
|
||||
`);
|
||||
if (!nextUp.bot) {
|
||||
let first = true;
|
||||
/* eslint-disable max-depth */
|
||||
for (const next of turn) {
|
||||
const nextPlayer = players.get(next);
|
||||
if (!first) {
|
||||
await msg.say(stripIndents`
|
||||
Coward.
|
||||
${nextPlayer.user}, will YOU take the gun?
|
||||
`);
|
||||
}
|
||||
if (first) first = false;
|
||||
const keepGoing = await verify(msg.channel, nextPlayer.user);
|
||||
if (keepGoing) break;
|
||||
wallOfShame.push(players.get(next).user.toString());
|
||||
players.delete(next);
|
||||
removeFromArray(turn, next);
|
||||
}
|
||||
/* eslint-enable max-depth */
|
||||
}
|
||||
if (players.size === 1) winner = players.first();
|
||||
round++;
|
||||
}
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner) {
|
||||
return msg.say(stripIndents`
|
||||
The winner is ${winner.user}!
|
||||
|
||||
__**Wall Of Shame:**__
|
||||
${wallOfShame.length ? wallOfShame.join('\n') : 'No one!'}
|
||||
}
|
||||
players.set(this.client.user.id, {
|
||||
id: this.client.user.id,
|
||||
user: this.client.user
|
||||
});
|
||||
const turn = shuffle(players.map(player => player.id));
|
||||
const gun = shuffle([true, false, false, false, false, false, false, false]);
|
||||
let round = 0;
|
||||
let loser = null;
|
||||
let winner = null;
|
||||
const wallOfShame = [];
|
||||
while (!loser && !winner) {
|
||||
const player = players.get(turn[0]);
|
||||
turn.push(turn[0]);
|
||||
turn.shift();
|
||||
if (gun[round]) {
|
||||
await msg.say(`**${player.user.tag}** pulls the trigger... **And dies!**`);
|
||||
loser = player;
|
||||
} else {
|
||||
const nextUp = players.get(turn[0]).user;
|
||||
await msg.say(stripIndents`
|
||||
**${player.user.tag}** pulls the trigger... **And lives...**
|
||||
${nextUp.bot ? '' : `Will you take the gun, ${nextUp}?`}
|
||||
`);
|
||||
if (!nextUp.bot) {
|
||||
let first = true;
|
||||
for (const next of turn) {
|
||||
const nextPlayer = players.get(next);
|
||||
if (!first) {
|
||||
await msg.say(stripIndents`
|
||||
Coward.
|
||||
${nextPlayer.user}, will YOU take the gun?
|
||||
`);
|
||||
}
|
||||
if (first) first = false;
|
||||
const keepGoing = await verify(msg.channel, nextPlayer.user);
|
||||
if (keepGoing) break;
|
||||
wallOfShame.push(players.get(next).user.toString());
|
||||
players.delete(next);
|
||||
removeFromArray(turn, next);
|
||||
}
|
||||
}
|
||||
if (players.size === 1) winner = players.first();
|
||||
round++;
|
||||
}
|
||||
}
|
||||
if (winner) {
|
||||
return msg.say(stripIndents`
|
||||
The loser is ${loser.user}!
|
||||
The winner is ${winner.user}!
|
||||
|
||||
__**Wall Of Shame:**__
|
||||
${wallOfShame.length ? wallOfShame.join('\n') : 'No one!'}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
return msg.say(stripIndents`
|
||||
The loser is ${loser.user}!
|
||||
|
||||
__**Wall Of Shame:**__
|
||||
${wallOfShame.length ? wallOfShame.join('\n') : 'No one!'}
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ module.exports = class SpamWarCommand extends Command {
|
||||
memberName: 'spam-war',
|
||||
description: 'See who can type more characters the fastest.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -23,40 +24,28 @@ module.exports = class SpamWarCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be played against.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
await msg.say('You get one point per character in your messages. You get 1 minute to spam.');
|
||||
await delay(5000);
|
||||
await msg.say('You have **1 minute** to spam. Go!');
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => [opponent.id, msg.author.id].includes(res.author.id),
|
||||
time: 60000
|
||||
});
|
||||
const authorMsgs = msgs
|
||||
.filter(authorMsg => authorMsg.author.id === msg.author.id)
|
||||
.reduce((a, b) => a + b.content.length, 0);
|
||||
const opponentMsgs = msgs
|
||||
.filter(opponentMsg => opponentMsg.author.id === opponent.id)
|
||||
.reduce((a, b) => a + b.content.length, 0);
|
||||
const winner = authorMsgs > opponentMsgs ? msg.author : opponent;
|
||||
const winnerPts = authorMsgs > opponentMsgs ? authorMsgs : opponentMsgs;
|
||||
const loserPts = authorMsgs > opponentMsgs ? opponentMsgs : authorMsgs;
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (authorMsgs === opponentMsgs) {
|
||||
return msg.say(`It was a tie! What are the odds? You both got **${winnerPts}** points!`);
|
||||
}
|
||||
return msg.say(`The winner is ${winner}, with **${winnerPts}** points! Your opponent only got ${loserPts}...`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
await msg.say('You get one point per character in your messages. You get 1 minute to spam.');
|
||||
await delay(5000);
|
||||
await msg.say('You have **1 minute** to spam. Go!');
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => [opponent.id, msg.author.id].includes(res.author.id),
|
||||
time: 60000
|
||||
});
|
||||
const authorMsgs = msgs
|
||||
.filter(authorMsg => authorMsg.author.id === msg.author.id)
|
||||
.reduce((a, b) => a + b.content.length, 0);
|
||||
const opponentMsgs = msgs
|
||||
.filter(opponentMsg => opponentMsg.author.id === opponent.id)
|
||||
.reduce((a, b) => a + b.content.length, 0);
|
||||
const winner = authorMsgs > opponentMsgs ? msg.author : opponent;
|
||||
const winnerPts = authorMsgs > opponentMsgs ? authorMsgs : opponentMsgs;
|
||||
const loserPts = authorMsgs > opponentMsgs ? opponentMsgs : authorMsgs;
|
||||
if (authorMsgs === opponentMsgs) {
|
||||
return msg.say(`It was a tie! What are the odds? You both got **${winnerPts}** points!`);
|
||||
}
|
||||
return msg.say(`The winner is ${winner}, with **${winnerPts}** points! Your opponent only got ${loserPts}...`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ module.exports = class TicTacToeCommand extends Command {
|
||||
group: 'games-mp',
|
||||
memberName: 'tic-tac-toe',
|
||||
description: 'Play a game of tic-tac-toe with another user or the AI.',
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -25,83 +26,71 @@ module.exports = class TicTacToeCommand extends Command {
|
||||
async run(msg, { opponent }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
}
|
||||
const sides = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
const taken = [];
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (!winner && taken.length < 9) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
const sign = userTurn ? 'X' : 'O';
|
||||
let choice;
|
||||
if (opponent.bot && !userTurn) {
|
||||
// eslint-disable-next-line new-cap
|
||||
choice = ComputerMove(sides, { aiPlayer: 'O', huPlayer: 'X' }, 'Hard');
|
||||
} else {
|
||||
await msg.say(stripIndents`
|
||||
${user}, which side do you pick? Type \`end\` to forfeit.
|
||||
|
||||
${this.displayBoard(sides)}
|
||||
`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
return valid.includes(pick) && !taken.includes(pick);
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
userTurn = !userTurn;
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sides[opponent.bot && !userTurn ? choice : Number.parseInt(choice, 10) - 1] = sign;
|
||||
taken.push(choice);
|
||||
const win = this.verifyWin(sides, msg.author, opponent);
|
||||
if (taken.length === 9 && !win) winner = 'tie';
|
||||
if (win) winner = win;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
${winner === 'tie' ? 'Oh... The cat won.' : `Congrats, ${winner}!`}
|
||||
|
||||
${this.displayBoard(sides)}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
if (!opponent.bot) {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
}
|
||||
const sides = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
const taken = [];
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
let lastTurnTimeout = false;
|
||||
while (!winner && taken.length < 9) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
const sign = userTurn ? 'X' : 'O';
|
||||
let choice;
|
||||
if (opponent.bot && !userTurn) {
|
||||
// eslint-disable-next-line new-cap
|
||||
choice = ComputerMove(sides, { aiPlayer: 'O', huPlayer: 'X' }, 'Hard');
|
||||
} else {
|
||||
await msg.say(stripIndents`
|
||||
${user}, which side do you pick? Type \`end\` to forfeit.
|
||||
|
||||
${this.displayBoard(sides)}
|
||||
`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== user.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
return valid.includes(pick) && !taken.includes(pick);
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
if (lastTurnTimeout) {
|
||||
winner = 'time';
|
||||
break;
|
||||
} else {
|
||||
userTurn = !userTurn;
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sides[opponent.bot && !userTurn ? choice : Number.parseInt(choice, 10) - 1] = sign;
|
||||
taken.push(choice);
|
||||
const win = this.verifyWin(sides, msg.author, opponent);
|
||||
if (taken.length === 9 && !win) winner = 'tie';
|
||||
if (win) winner = win;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
if (winner === 'time') return msg.say('Game ended due to inactivity.');
|
||||
return msg.say(stripIndents`
|
||||
${winner === 'tie' ? 'Oh... The cat won.' : `Congrats, ${winner}!`}
|
||||
|
||||
${this.displayBoard(sides)}
|
||||
`);
|
||||
}
|
||||
|
||||
playerWon(board, player) {
|
||||
|
||||
@@ -10,6 +10,7 @@ module.exports = class TypingRaceCommand extends Command {
|
||||
memberName: 'typing-race',
|
||||
description: 'Race a user to see who can type a sentence faster.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
@@ -23,51 +24,39 @@ module.exports = class TypingRaceCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be played against.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
const sentence = this.client.registry.commands.get('typing-test').generateSentence(5);
|
||||
const img = await this.client.registry.commands.get('typing-test').generateImage(sentence);
|
||||
await msg.say(`**Type the following sentence within 30 seconds:**`, {
|
||||
files: [{ attachment: img, name: 'typing-race.png' }]
|
||||
});
|
||||
const now = Date.now();
|
||||
const filter = res => {
|
||||
if (![opponent.id, msg.author.id].includes(res.author.id)) return false;
|
||||
return res.content.toLowerCase() === sentence;
|
||||
};
|
||||
const winner = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
const newScore = Date.now() - now;
|
||||
const highScoreGet = await this.client.redis.get('typing-test');
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get('typing-test-user');
|
||||
const scoreBeat = winner.size && (!highScore || highScore > newScore);
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set('typing-test', newScore);
|
||||
await this.client.redis.set('typing-test-user', winner.first().author.id);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!winner.size) return msg.say('Oh... No one won.');
|
||||
const wpm = (sentence.length / 5) / ((newScore / 1000) / 60);
|
||||
return msg.say(stripIndents`
|
||||
The winner is ${winner.first().author}! (Took ${newScore / 1000} seconds, ${Math.round(wpm)} WPM)
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${highScore / 1000}s (Held by ${user})
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
const sentence = this.client.registry.commands.get('typing-test').generateSentence(5);
|
||||
const img = await this.client.registry.commands.get('typing-test').generateImage(sentence);
|
||||
await msg.say(`**Type the following sentence within 30 seconds:**`, {
|
||||
files: [{ attachment: img, name: 'typing-race.png' }]
|
||||
});
|
||||
const now = Date.now();
|
||||
const filter = res => {
|
||||
if (![opponent.id, msg.author.id].includes(res.author.id)) return false;
|
||||
return res.content.toLowerCase() === sentence;
|
||||
};
|
||||
const winner = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
const newScore = Date.now() - now;
|
||||
const highScoreGet = await this.client.redis.get('typing-test');
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get('typing-test-user');
|
||||
const scoreBeat = winner.size && (!highScore || highScore > newScore);
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set('typing-test', newScore);
|
||||
await this.client.redis.set('typing-test-user', winner.first().author.id);
|
||||
}
|
||||
if (!winner.size) return msg.say('Oh... No one won.');
|
||||
const wpm = (sentence.length / 5) / ((newScore / 1000) / 60);
|
||||
return msg.say(stripIndents`
|
||||
The winner is ${winner.first().author}! (Took ${newScore / 1000} seconds, ${Math.round(wpm)} WPM)
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${highScore / 1000}s (Held by ${user})
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ module.exports = class WordChainCommand extends Command {
|
||||
memberName: 'word-chain',
|
||||
description: 'Try to come up with words that start with the last letter of your opponent\'s word.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Grady Ward',
|
||||
@@ -42,71 +43,59 @@ module.exports = class WordChainCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be played against.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
const startWord = startWords[Math.floor(Math.random() * startWords.length)];
|
||||
await msg.say(stripIndents`
|
||||
The start word will be **${startWord}**! You must answer within **${time}** seconds!
|
||||
If you think your opponent has played a word that doesn't exist, respond with **challenge** on your turn.
|
||||
Words cannot contain anything but letters. No numbers, spaces, or hyphens may be used.
|
||||
The game will start in 5 seconds...
|
||||
`);
|
||||
await delay(5000);
|
||||
let userTurn = Boolean(Math.floor(Math.random() * 2));
|
||||
const words = [];
|
||||
let winner = null;
|
||||
let lastWord = startWord;
|
||||
while (!winner) {
|
||||
const player = userTurn ? msg.author : opponent;
|
||||
const letter = lastWord.charAt(lastWord.length - 1);
|
||||
await msg.say(`It's ${player}'s turn! The letter is **${letter}**.`);
|
||||
const filter = res =>
|
||||
res.author.id === player.id && /^[a-zA-Z']+$/i.test(res.content) && res.content.length < 50;
|
||||
const wordChoice = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: time * 1000
|
||||
});
|
||||
if (!wordChoice.size) {
|
||||
await msg.say('Time!');
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
const startWord = startWords[Math.floor(Math.random() * startWords.length)];
|
||||
await msg.say(stripIndents`
|
||||
The start word will be **${startWord}**! You must answer within **${time}** seconds!
|
||||
If you think your opponent has played a word that doesn't exist, respond with **challenge** on your turn.
|
||||
Words cannot contain anything but letters. No numbers, spaces, or hyphens may be used.
|
||||
The game will start in 5 seconds...
|
||||
`);
|
||||
await delay(5000);
|
||||
let userTurn = Boolean(Math.floor(Math.random() * 2));
|
||||
const words = [];
|
||||
let winner = null;
|
||||
let lastWord = startWord;
|
||||
while (!winner) {
|
||||
const player = userTurn ? msg.author : opponent;
|
||||
const letter = lastWord.charAt(lastWord.length - 1);
|
||||
await msg.say(`It's ${player}'s turn! The letter is **${letter}**.`);
|
||||
const filter = res =>
|
||||
res.author.id === player.id && /^[a-zA-Z']+$/i.test(res.content) && res.content.length < 50;
|
||||
const wordChoice = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: time * 1000
|
||||
});
|
||||
if (!wordChoice.size) {
|
||||
await msg.say('Time!');
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
const choice = wordChoice.first().content.toLowerCase();
|
||||
if (choice === 'challenge') {
|
||||
const checked = await this.verifyWord(lastWord);
|
||||
if (!checked) {
|
||||
await msg.say(`Caught red-handed! **${lastWord}** is not valid!`);
|
||||
winner = player;
|
||||
break;
|
||||
}
|
||||
const choice = wordChoice.first().content.toLowerCase();
|
||||
if (choice === 'challenge') {
|
||||
const checked = await this.verifyWord(lastWord);
|
||||
if (!checked) {
|
||||
await msg.say(`Caught red-handed! **${lastWord}** is not valid!`);
|
||||
winner = player;
|
||||
break;
|
||||
}
|
||||
await msg.say(`Sorry, **${lastWord}** is indeed valid!`);
|
||||
continue;
|
||||
}
|
||||
if (!choice.startsWith(letter) || words.includes(choice)) {
|
||||
await msg.say('Sorry! You lose!');
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
words.push(choice);
|
||||
lastWord = choice;
|
||||
userTurn = !userTurn;
|
||||
await msg.say(`Sorry, **${lastWord}** is indeed valid!`);
|
||||
continue;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!winner) return msg.say('Oh... No one won.');
|
||||
return msg.say(`The game is over! The winner is ${winner}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
if (!choice.startsWith(letter) || words.includes(choice)) {
|
||||
await msg.say('Sorry! You lose!');
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
words.push(choice);
|
||||
lastWord = choice;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
if (!winner) return msg.say('Oh... No one won.');
|
||||
return msg.say(`The game is over! The winner is ${winner}!`);
|
||||
}
|
||||
|
||||
async verifyWord(word) {
|
||||
|
||||
@@ -11,6 +11,7 @@ module.exports = class WordSpudCommand extends Command {
|
||||
memberName: 'word-spud',
|
||||
description: 'Hot potato, but with words.',
|
||||
guildOnly: true,
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Jackbox Games',
|
||||
@@ -32,57 +33,45 @@ module.exports = class WordSpudCommand extends Command {
|
||||
if (opponent.bot) return msg.reply('Bots may not be played against.');
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.');
|
||||
if (this.client.blacklist.user.includes(opponent.id)) return msg.reply('This user is blacklisted.');
|
||||
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 {
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Looks like they declined...');
|
||||
}
|
||||
let currentWord = startWords[Math.floor(Math.random() * startWords.length)];
|
||||
let lastTurnTimeout = false;
|
||||
let gameEnd = false;
|
||||
let userTurn = false;
|
||||
while (!gameEnd) {
|
||||
const player = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${player}, continue the chain: **${currentWord} ...?**
|
||||
_Type \`end\` to end the game._
|
||||
`);
|
||||
const filter = res => res.author.id === player.id && res.content.length <= 100;
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!msgs.size) {
|
||||
await msg.say('No ideas? No problem, moving on.');
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) {
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const word = msgs.first().content.toLowerCase();
|
||||
if (word === 'end') {
|
||||
gameEnd = true;
|
||||
break;
|
||||
}
|
||||
await msg.say(`${currentWord} **${word}**? Cool!`);
|
||||
currentWord = word;
|
||||
await msg.say(`${opponent}, do you accept this challenge?`);
|
||||
const verification = await verify(msg.channel, opponent);
|
||||
if (!verification) return msg.say('Looks like they declined...');
|
||||
let currentWord = startWords[Math.floor(Math.random() * startWords.length)];
|
||||
let lastTurnTimeout = false;
|
||||
let gameEnd = false;
|
||||
let userTurn = false;
|
||||
while (!gameEnd) {
|
||||
const player = userTurn ? msg.author : opponent;
|
||||
await msg.say(stripIndents`
|
||||
${player}, continue the chain: **${currentWord} ...?**
|
||||
_Type \`end\` to end the game._
|
||||
`);
|
||||
const filter = res => res.author.id === player.id && res.content.length <= 100;
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!msgs.size) {
|
||||
await msg.say('No ideas? No problem, moving on.');
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
if (lastTurnTimeout) {
|
||||
break;
|
||||
} else {
|
||||
lastTurnTimeout = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Thanks for playing!');
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const word = msgs.first().content.toLowerCase();
|
||||
if (word === 'end') {
|
||||
gameEnd = true;
|
||||
break;
|
||||
}
|
||||
await msg.say(`${currentWord} **${word}**? Cool!`);
|
||||
currentWord = word;
|
||||
userTurn = !userTurn;
|
||||
if (lastTurnTimeout) lastTurnTimeout = false;
|
||||
}
|
||||
return msg.say('Thanks for playing!');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ module.exports = class AnagramicaCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'anagramica',
|
||||
description: 'Try to find all the anagrams for a given set of letters.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Max Irwin',
|
||||
@@ -36,72 +37,63 @@ module.exports = class AnagramicaCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { time }) {
|
||||
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.`);
|
||||
try {
|
||||
this.client.games.set(msg.channel.id, { name: this.name });
|
||||
const { valid, letters } = await this.fetchList();
|
||||
let points = 0;
|
||||
await msg.reply(stripIndents`
|
||||
**You have ${time} seconds to provide anagrams for the following letters:**
|
||||
${letters.map(letter => `\`${letter.toUpperCase()}\``).join(' ')}
|
||||
const { valid, letters } = await this.fetchList();
|
||||
let points = 0;
|
||||
await msg.reply(stripIndents`
|
||||
**You have ${time} seconds to provide anagrams for the following letters:**
|
||||
${letters.map(letter => `\`${letter.toUpperCase()}\``).join(' ')}
|
||||
|
||||
_Need to see the list again? Type \`send list\` (or \`sl\`)._
|
||||
`);
|
||||
const picked = [];
|
||||
const filter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
const choice = res.content.toLowerCase();
|
||||
if (choice === 'send list' || choice === 'sl') {
|
||||
msg.reply(letters.map(letter => `\`${letter.toUpperCase()}\``).join(' ')).catch(() => null);
|
||||
return true;
|
||||
}
|
||||
if (picked.includes(choice)) return false;
|
||||
const score = this.getScore(letters, choice);
|
||||
if (!score) return false;
|
||||
if (!valid.includes(choice)) {
|
||||
picked.push(choice);
|
||||
reactIfAble(res, res.author, FAILURE_EMOJI_ID, '❌');
|
||||
return false;
|
||||
}
|
||||
points += score;
|
||||
picked.push(choice);
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
_Need to see the list again? Type \`send list\` (or \`sl\`)._
|
||||
`);
|
||||
const picked = [];
|
||||
const filter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
const choice = res.content.toLowerCase();
|
||||
if (choice === 'send list' || choice === 'sl') {
|
||||
msg.reply(letters.map(letter => `\`${letter.toUpperCase()}\``).join(' ')).catch(() => null);
|
||||
return true;
|
||||
};
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
time: time * 1000
|
||||
});
|
||||
const highScoreGet = await this.client.redis.get('anagramica');
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get('anagramica-user');
|
||||
const scoreBeat = !highScore || highScore < points;
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set('anagramica', points);
|
||||
await this.client.redis.set('anagramica-user', msg.author.id);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
const moreWords = shuffle(valid.filter(word => !picked.includes(word))).slice(0, 5);
|
||||
if (!msgs.size) {
|
||||
return msg.reply(stripIndents`
|
||||
Couldn't even think of one? Ouch.
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${highScore} (Held by ${user})
|
||||
|
||||
Here's some words you missed: ${moreWords.map(word => `\`${word}\``).join(', ')}
|
||||
`);
|
||||
if (picked.includes(choice)) return false;
|
||||
const score = this.getScore(letters, choice);
|
||||
if (!score) return false;
|
||||
if (!valid.includes(choice)) {
|
||||
picked.push(choice);
|
||||
reactIfAble(res, res.author, FAILURE_EMOJI_ID, '❌');
|
||||
return false;
|
||||
}
|
||||
points += score;
|
||||
picked.push(choice);
|
||||
reactIfAble(res, res.author, SUCCESS_EMOJI_ID, '✅');
|
||||
return true;
|
||||
};
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
time: time * 1000
|
||||
});
|
||||
const highScoreGet = await this.client.redis.get('anagramica');
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get('anagramica-user');
|
||||
const scoreBeat = !highScore || highScore < points;
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set('anagramica', points);
|
||||
await this.client.redis.set('anagramica-user', msg.author.id);
|
||||
}
|
||||
const moreWords = shuffle(valid.filter(word => !picked.includes(word))).slice(0, 5);
|
||||
if (!msgs.size) {
|
||||
return msg.reply(stripIndents`
|
||||
Nice job! Your final score was **${points}**!
|
||||
Couldn't even think of one? Ouch.
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${highScore} (Held by ${user})
|
||||
|
||||
Here's some words you missed: ${moreWords.map(word => `\`${word}\``).join(', ')}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
return msg.reply(stripIndents`
|
||||
Nice job! Your final score was **${points}**!
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${highScore} (Held by ${user})
|
||||
|
||||
Here's some words you missed: ${moreWords.map(word => `\`${word}\``).join(', ')}
|
||||
`);
|
||||
}
|
||||
|
||||
async fetchList() {
|
||||
|
||||
@@ -43,6 +43,7 @@ module.exports = class AnimeScoreCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'anime-score',
|
||||
description: 'See if you can guess what a random anime\'s score is.',
|
||||
game: true,
|
||||
clientPermissions: ['EMBED_LINKS'],
|
||||
credit: [
|
||||
{
|
||||
@@ -56,34 +57,30 @@ module.exports = class AnimeScoreCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const anime = await this.getRandomAnime(msg.channel.nsfw);
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0x02A9FF)
|
||||
.setAuthor('AniList', 'https://i.imgur.com/iUIRC7v.png', 'https://anilist.co/')
|
||||
.setImage(anime.coverImage.large || anime.coverImage.medium || null)
|
||||
.setTitle(anime.title.english || anime.title.romaji)
|
||||
.setDescription(`_${anime.startDate.year}, ${formats[anime.format]}_`)
|
||||
.setFooter(anime.id.toString());
|
||||
await msg.reply('**You have 15 seconds, what score do you think this anime has?**', { embeds: [embed] });
|
||||
const filter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
return Boolean(Number.parseInt(res.content, 10));
|
||||
};
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
if (!msgs.size) return msg.reply(`Sorry, time is up! It was **${anime.averageScore}%**.`);
|
||||
const ans = Number.parseInt(msgs.first().content, 10);
|
||||
const close = Math.abs(ans - anime.averageScore);
|
||||
if (close <= 10 && close !== 0) return msg.reply(`Close! It was **${anime.averageScore}%**.`);
|
||||
if (ans !== anime.averageScore) return msg.reply(`Nope, sorry, it was **${anime.averageScore}%**.`);
|
||||
return msg.reply(`Nice job! It was **${anime.averageScore}%**!`);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const anime = await this.getRandomAnime(msg.channel.nsfw);
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0x02A9FF)
|
||||
.setAuthor('AniList', 'https://i.imgur.com/iUIRC7v.png', 'https://anilist.co/')
|
||||
.setImage(anime.coverImage.large || anime.coverImage.medium || null)
|
||||
.setTitle(anime.title.english || anime.title.romaji)
|
||||
.setDescription(`_${anime.startDate.year}, ${formats[anime.format]}_`)
|
||||
.setFooter(anime.id.toString());
|
||||
await msg.reply('**You have 15 seconds, what score do you think this anime has?**', { embeds: [embed] });
|
||||
const filter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
return Boolean(Number.parseInt(res.content, 10));
|
||||
};
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
if (!msgs.size) return msg.reply(`Sorry, time is up! It was **${anime.averageScore}%**.`);
|
||||
const ans = Number.parseInt(msgs.first().content, 10);
|
||||
const close = Math.abs(ans - anime.averageScore);
|
||||
if (close <= 10 && close !== 0) return msg.reply(`Close! It was **${anime.averageScore}%**.`);
|
||||
if (ans !== anime.averageScore) return msg.reply(`Nope, sorry, it was **${anime.averageScore}%**.`);
|
||||
return msg.reply(`Nice job! It was **${anime.averageScore}%**!`);
|
||||
}
|
||||
|
||||
async getRandomAnime(nsfw) {
|
||||
|
||||
@@ -26,6 +26,7 @@ module.exports = class AntidepressantOrTolkienCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'antidepressant-or-tokien',
|
||||
description: 'See if you can guess if a word is an Antidepressant or Tolkien character.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Antidepressants or Tolkien',
|
||||
|
||||
@@ -13,6 +13,7 @@ module.exports = class BlackjackCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'blackjack',
|
||||
description: 'Play a game of blackjack.',
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'deckCount',
|
||||
@@ -27,93 +28,81 @@ module.exports = class BlackjackCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { deckCount }) {
|
||||
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.`);
|
||||
try {
|
||||
this.client.games.set(msg.channel.id, { name: this.name, data: new Deck({ deckCount }) });
|
||||
const dealerHand = [];
|
||||
this.draw(msg.channel, dealerHand);
|
||||
this.draw(msg.channel, dealerHand);
|
||||
const playerHand = [];
|
||||
this.draw(msg.channel, playerHand);
|
||||
this.draw(msg.channel, playerHand);
|
||||
const dealerInitialTotal = this.calculate(dealerHand);
|
||||
const playerInitialTotal = this.calculate(playerHand);
|
||||
if (dealerInitialTotal === 21 && playerInitialTotal === 21) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Well, both of you just hit blackjack. Right away. Rigged.');
|
||||
} else if (dealerInitialTotal === 21) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Ouch, the dealer hit blackjack right away! Try again!');
|
||||
} else if (playerInitialTotal === 21) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Wow, you hit blackjack right away! Lucky you!');
|
||||
}
|
||||
let playerTurn = true;
|
||||
let win = false;
|
||||
let reason;
|
||||
while (!win) {
|
||||
if (playerTurn) {
|
||||
await msg.say(stripIndents`
|
||||
**First Dealer Card:** ${dealerHand[0].display}
|
||||
const deck = new Deck({ deckCount });
|
||||
const dealerHand = [];
|
||||
this.draw(dealerHand, deck);
|
||||
this.draw(dealerHand, deck);
|
||||
const playerHand = [];
|
||||
this.draw(playerHand, deck);
|
||||
this.draw(playerHand, deck);
|
||||
const dealerInitialTotal = this.calculate(dealerHand);
|
||||
const playerInitialTotal = this.calculate(playerHand);
|
||||
if (dealerInitialTotal === 21 && playerInitialTotal === 21) {
|
||||
return msg.say('Well, both of you just hit blackjack. Right away. Rigged.');
|
||||
} else if (dealerInitialTotal === 21) {
|
||||
return msg.say('Ouch, the dealer hit blackjack right away! Try again!');
|
||||
} else if (playerInitialTotal === 21) {
|
||||
return msg.say('Wow, you hit blackjack right away! Lucky you!');
|
||||
}
|
||||
let playerTurn = true;
|
||||
let win = false;
|
||||
let reason;
|
||||
while (!win) {
|
||||
if (playerTurn) {
|
||||
await msg.say(stripIndents`
|
||||
**First Dealer Card:** ${dealerHand[0].display}
|
||||
|
||||
**You (${this.calculate(playerHand)}):**
|
||||
${playerHand.map(card => card.display).join('\n')}
|
||||
**You (${this.calculate(playerHand)}):**
|
||||
${playerHand.map(card => card.display).join('\n')}
|
||||
|
||||
_Hit?_
|
||||
`);
|
||||
const hit = await verify(msg.channel, msg.author, { extraYes: hitWords, extraNo: standWords });
|
||||
if (hit) {
|
||||
const card = this.draw(msg.channel, playerHand);
|
||||
const total = this.calculate(playerHand);
|
||||
if (total > 21) {
|
||||
reason = `You drew ${card.display}, total of ${total}! Bust`;
|
||||
break;
|
||||
} else if (total === 21) {
|
||||
reason = `You drew ${card.display} and hit 21`;
|
||||
win = true;
|
||||
}
|
||||
} else {
|
||||
const dealerTotal = this.calculate(dealerHand);
|
||||
await msg.say(`Second dealer card is ${dealerHand[1].display}, total of ${dealerTotal}.`);
|
||||
playerTurn = false;
|
||||
_Hit?_
|
||||
`);
|
||||
const hit = await verify(msg.channel, msg.author, { extraYes: hitWords, extraNo: standWords });
|
||||
if (hit) {
|
||||
const card = this.draw(playerHand, deck);
|
||||
const total = this.calculate(playerHand);
|
||||
if (total > 21) {
|
||||
reason = `You drew ${card.display}, total of ${total}! Bust`;
|
||||
break;
|
||||
} else if (total === 21) {
|
||||
reason = `You drew ${card.display} and hit 21`;
|
||||
win = true;
|
||||
}
|
||||
} else {
|
||||
const inital = this.calculate(dealerHand);
|
||||
let card;
|
||||
if (inital < 17) card = this.draw(msg.channel, dealerHand);
|
||||
const total = this.calculate(dealerHand);
|
||||
if (total > 21) {
|
||||
reason = `Dealer drew ${card.display}, total of ${total}! Dealer bust`;
|
||||
win = true;
|
||||
} else if (total >= 17) {
|
||||
const playerTotal = this.calculate(playerHand);
|
||||
if (total === playerTotal) {
|
||||
reason = `${card ? `Dealer drew ${card.display}, making it ` : ''}${playerTotal}-${total}`;
|
||||
break;
|
||||
} else if (total > playerTotal) {
|
||||
reason = `${card ? `Dealer drew ${card.display}, making it ` : ''}${playerTotal}-**${total}**`;
|
||||
break;
|
||||
} else {
|
||||
reason = `${card ? `Dealer drew ${card.display}, making it ` : ''}**${playerTotal}**-${total}`;
|
||||
win = true;
|
||||
}
|
||||
const dealerTotal = this.calculate(dealerHand);
|
||||
await msg.say(`Second dealer card is ${dealerHand[1].display}, total of ${dealerTotal}.`);
|
||||
playerTurn = false;
|
||||
}
|
||||
} else {
|
||||
const inital = this.calculate(dealerHand);
|
||||
let card;
|
||||
if (inital < 17) card = this.draw(dealerHand, deck);
|
||||
const total = this.calculate(dealerHand);
|
||||
if (total > 21) {
|
||||
reason = `Dealer drew ${card.display}, total of ${total}! Dealer bust`;
|
||||
win = true;
|
||||
} else if (total >= 17) {
|
||||
const playerTotal = this.calculate(playerHand);
|
||||
if (total === playerTotal) {
|
||||
reason = `${card ? `Dealer drew ${card.display}, making it ` : ''}${playerTotal}-${total}`;
|
||||
break;
|
||||
} else if (total > playerTotal) {
|
||||
reason = `${card ? `Dealer drew ${card.display}, making it ` : ''}${playerTotal}-**${total}**`;
|
||||
break;
|
||||
} else {
|
||||
await msg.say(`Dealer drew ${card.display}, total of ${total}.`);
|
||||
reason = `${card ? `Dealer drew ${card.display}, making it ` : ''}**${playerTotal}**-${total}`;
|
||||
win = true;
|
||||
}
|
||||
} else {
|
||||
await msg.say(`Dealer drew ${card.display}, total of ${total}.`);
|
||||
}
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (win) return msg.say(`${reason}! You won!`);
|
||||
return msg.say(`${reason}! Too bad.`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
if (win) return msg.say(`${reason}! You won!`);
|
||||
return msg.say(`${reason}! Too bad.`);
|
||||
}
|
||||
|
||||
draw(channel, hand) {
|
||||
const deck = this.client.games.get(channel.id).data;
|
||||
draw(hand, deck) {
|
||||
const card = deck.draw();
|
||||
hand.push(card);
|
||||
return card;
|
||||
|
||||
@@ -11,6 +11,7 @@ module.exports = class BoxChoosingCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'box-choosing',
|
||||
description: 'Do you believe that there are choices in life? Taken from Higurashi Chapter 4.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: '07th Expansion',
|
||||
@@ -31,61 +32,52 @@ module.exports = class BoxChoosingCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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 {
|
||||
let i = 0;
|
||||
let path = 'before';
|
||||
let end = false;
|
||||
while (!end) {
|
||||
const line = script[path][i];
|
||||
if (!line) {
|
||||
let i = 0;
|
||||
let path = 'before';
|
||||
let end = false;
|
||||
while (!end) {
|
||||
const line = script[path][i];
|
||||
if (!line) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
await msg.say(typeof line === 'object' ? line.text : stripIndents`
|
||||
${line}
|
||||
|
||||
_Proceed?_
|
||||
`);
|
||||
if (line.options) {
|
||||
const filter = res => res.author.id === msg.author.id && line.options.includes(res.content.toLowerCase());
|
||||
const choose = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!choose.size) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
await msg.say(typeof line === 'object' ? line.text : stripIndents`
|
||||
${line}
|
||||
|
||||
_Proceed?_
|
||||
`);
|
||||
if (line.options) {
|
||||
const filter = res => res.author.id === msg.author.id && line.options.includes(res.content.toLowerCase());
|
||||
const choose = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!choose.size) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
path = '';
|
||||
const pick = line.paths[line.options.indexOf(choose.first().content.toLowerCase())];
|
||||
if ((this.red.has(msg.author.id) && pick !== 'red') || (this.blue.has(msg.author.id) && pick !== 'blue')) {
|
||||
path += 'both';
|
||||
if (this.red.has(msg.author.id)) this.red.delete(msg.author.id);
|
||||
if (this.blue.has(msg.author.id)) this.blue.delete(msg.author.id);
|
||||
} else {
|
||||
this[pick].add(msg.author.id);
|
||||
setTimeout(() => { if (this[pick].has(msg.author.id)) this[pick].delete(msg.author.id); }, 600000);
|
||||
}
|
||||
path += pick;
|
||||
i = 0;
|
||||
path = '';
|
||||
const pick = line.paths[line.options.indexOf(choose.first().content.toLowerCase())];
|
||||
if ((this.red.has(msg.author.id) && pick !== 'red') || (this.blue.has(msg.author.id) && pick !== 'blue')) {
|
||||
path += 'both';
|
||||
if (this.red.has(msg.author.id)) this.red.delete(msg.author.id);
|
||||
if (this.blue.has(msg.author.id)) this.blue.delete(msg.author.id);
|
||||
} else {
|
||||
const verification = await verify(msg.channel, msg.author, { time: 120000 });
|
||||
if (!verification) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
this[pick].add(msg.author.id);
|
||||
setTimeout(() => { if (this[pick].has(msg.author.id)) this[pick].delete(msg.author.id); }, 600000);
|
||||
}
|
||||
path += pick;
|
||||
i = 0;
|
||||
} else {
|
||||
const verification = await verify(msg.channel, msg.author, { time: 120000 });
|
||||
if (!verification) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say(script.end);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
return msg.say(script.end);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ module.exports = class CaptchaCommand extends Command {
|
||||
duration: 10
|
||||
},
|
||||
clientPermissions: ['ATTACH_FILES'],
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Christoph Mueller',
|
||||
|
||||
+13
-21
@@ -11,6 +11,7 @@ module.exports = class DoorsCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'doors',
|
||||
description: 'Open the right door, and you win the money! Make the wrong choice, and you get the fire!',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Mythbusters',
|
||||
@@ -35,27 +36,18 @@ module.exports = class DoorsCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { door }) {
|
||||
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 win = doors[Math.floor(Math.random() * doors.length)];
|
||||
const noWin = doors.filter(thisDoor => thisDoor !== win && door !== thisDoor)[0];
|
||||
await msg.reply(stripIndents`
|
||||
Well, there's nothing behind door number **${noWin}**. Do you want to stick with door ${door}?
|
||||
${this.emoji(1, noWin)} ${this.emoji(2, noWin)} ${this.emoji(3, noWin)}
|
||||
`);
|
||||
const stick = await verify(msg.channel, msg.author);
|
||||
if (!stick) door = doors.filter(thisDoor => door !== thisDoor && thisDoor !== noWin)[0];
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(stripIndents`
|
||||
${door === win ? 'You chose wisely.' : 'Hmm... Try again.'}
|
||||
${this.emoji(1, noWin, win, door)} ${this.emoji(2, noWin, win, door)} ${this.emoji(3, noWin, win, door)}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
const win = doors[Math.floor(Math.random() * doors.length)];
|
||||
const noWin = doors.filter(thisDoor => thisDoor !== win && door !== thisDoor)[0];
|
||||
await msg.reply(stripIndents`
|
||||
Well, there's nothing behind door number **${noWin}**. Do you want to stick with door ${door}?
|
||||
${this.emoji(1, noWin)} ${this.emoji(2, noWin)} ${this.emoji(3, noWin)}
|
||||
`);
|
||||
const stick = await verify(msg.channel, msg.author);
|
||||
if (!stick) door = doors.filter(thisDoor => door !== thisDoor && thisDoor !== noWin)[0];
|
||||
return msg.reply(stripIndents`
|
||||
${door === win ? 'You chose wisely.' : 'Hmm... Try again.'}
|
||||
${this.emoji(1, noWin, win, door)} ${this.emoji(2, noWin, win, door)} ${this.emoji(3, noWin, win, door)}
|
||||
`);
|
||||
}
|
||||
|
||||
emoji(door, noWin, win, chosen) {
|
||||
|
||||
@@ -11,6 +11,7 @@ module.exports = class GoogleFeudCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'google-feud',
|
||||
description: 'Attempt to determine the top suggestions for a Google search.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Google',
|
||||
@@ -27,46 +28,37 @@ module.exports = class GoogleFeudCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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 question = questions[Math.floor(Math.random() * questions.length)];
|
||||
const suggestions = await this.fetchSuggestions(question);
|
||||
if (!suggestions) return msg.say('Could not find any results.');
|
||||
const display = new Array(suggestions.length).fill('???');
|
||||
let tries = 4;
|
||||
let score = 0;
|
||||
while (display.includes('???') && tries) {
|
||||
const embed = this.makeEmbed(question, tries, suggestions, display);
|
||||
await msg.embed(embed);
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!msgs.size) {
|
||||
await msg.say('Time is up!');
|
||||
break;
|
||||
}
|
||||
const choice = msgs.first().content.toLowerCase();
|
||||
if (suggestions.includes(choice)) {
|
||||
score += 10000 - (suggestions.indexOf(choice) * 1000);
|
||||
display[suggestions.indexOf(choice)] = choice;
|
||||
} else {
|
||||
--tries;
|
||||
}
|
||||
const question = questions[Math.floor(Math.random() * questions.length)];
|
||||
const suggestions = await this.fetchSuggestions(question);
|
||||
if (!suggestions) return msg.say('Could not find any results.');
|
||||
const display = new Array(suggestions.length).fill('???');
|
||||
let tries = 4;
|
||||
let score = 0;
|
||||
while (display.includes('???') && tries) {
|
||||
const embed = this.makeEmbed(question, tries, suggestions, display);
|
||||
await msg.embed(embed);
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!msgs.size) {
|
||||
await msg.say('Time is up!');
|
||||
break;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!display.includes('???')) {
|
||||
return msg.say(`You win! Nice job, master of Google!\n**Final Score: $${formatNumber(score)}**`);
|
||||
const choice = msgs.first().content.toLowerCase();
|
||||
if (suggestions.includes(choice)) {
|
||||
score += 10000 - (suggestions.indexOf(choice) * 1000);
|
||||
display[suggestions.indexOf(choice)] = choice;
|
||||
} else {
|
||||
--tries;
|
||||
}
|
||||
const final = this.makeEmbed(question, tries, suggestions, suggestions);
|
||||
return msg.say(`Better luck next time!\n**Final Score: $${formatNumber(score)}**`, { embeds: [final] });
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
if (!display.includes('???')) {
|
||||
return msg.say(`You win! Nice job, master of Google!\n**Final Score: $${formatNumber(score)}**`);
|
||||
}
|
||||
const final = this.makeEmbed(question, tries, suggestions, suggestions);
|
||||
return msg.say(`Better luck next time!\n**Final Score: $${formatNumber(score)}**`, { embeds: [final] });
|
||||
}
|
||||
|
||||
async fetchSuggestions(question) {
|
||||
|
||||
@@ -22,6 +22,7 @@ module.exports = class GuessSongCommand extends Command {
|
||||
guildOnly: true,
|
||||
userPermissions: ['CONNECT', 'SPEAK'],
|
||||
clientPermissions: ['ATTACH_FILES'],
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Spotify',
|
||||
@@ -51,35 +52,25 @@ module.exports = class GuessSongCommand extends Command {
|
||||
const usage = this.client.registry.commands.get('join').usage();
|
||||
return msg.reply(`I am not in a voice channel. Use ${usage} to fix that!`);
|
||||
}
|
||||
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.`);
|
||||
if (!connection.canPlay) return msg.reply('I am already playing audio in this server.');
|
||||
this.client.games.set(msg.channel.id, { name: this.name });
|
||||
let songID;
|
||||
try {
|
||||
if (!this.token) await this.fetchToken();
|
||||
const data = await this.fetchRandomSong(chart);
|
||||
const { body: previewBody } = await request.get(data.preview);
|
||||
connection.play(Readable.from([previewBody]));
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
await msg.reply('**You have 30 seconds, what song is this?**');
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
this.client.games.delete(msg.channel.id);
|
||||
connection.stop();
|
||||
if (!msgs.size) return msg.reply(`Time! It's **${data.name}** by **${data.artist}**!`);
|
||||
const guess = msgs.first().content.toLowerCase();
|
||||
if (!guess.includes(data.name.toLowerCase()) && !guess.includes(data.shortName.toLowerCase())) {
|
||||
return msg.reply(`Nope! It's **${data.name}** by **${data.artist}**!`);
|
||||
}
|
||||
return msg.reply(`Nice! It's **${data.name}** by **${data.artist}**!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Song ID: \`${songID}\`.`);
|
||||
if (!this.token) await this.fetchToken();
|
||||
const data = await this.fetchRandomSong(chart);
|
||||
const { body: previewBody } = await request.get(data.preview);
|
||||
connection.play(Readable.from([previewBody]));
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
await msg.reply('**You have 30 seconds, what song is this?**');
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
connection.stop();
|
||||
if (!msgs.size) return msg.reply(`Time! It's **${data.name}** by **${data.artist}**!`);
|
||||
const guess = msgs.first().content.toLowerCase();
|
||||
if (!guess.includes(data.name.toLowerCase()) && !guess.includes(data.shortName.toLowerCase())) {
|
||||
return msg.reply(`Nope! It's **${data.name}** by **${data.artist}**!`);
|
||||
}
|
||||
return msg.reply(`Nice! It's **${data.name}** by **${data.artist}**!`);
|
||||
}
|
||||
|
||||
async fetchCharts(playlist) {
|
||||
|
||||
@@ -11,6 +11,7 @@ module.exports = class HangmanCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'hangman',
|
||||
description: 'Prevent a man from being hanged by guessing a word as fast as you can.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Grady Ward',
|
||||
@@ -29,82 +30,73 @@ module.exports = class HangmanCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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 word = words[Math.floor(Math.random() * words.length)].toLowerCase();
|
||||
let points = 0;
|
||||
let displayText = null;
|
||||
let guessed = false;
|
||||
const confirmation = [];
|
||||
const incorrect = [];
|
||||
const display = new Array(word.length).fill('_');
|
||||
while (word.length !== confirmation.length && points < 6) {
|
||||
await msg.say(stripIndents`
|
||||
${displayText === null ? 'Here we go!' : displayText ? 'Good job!' : 'Nope!'}
|
||||
\`${display.join(' ')}\`. Which letter do you choose? Type \`end\` to forfeit.
|
||||
Incorrect Tries: ${incorrect.join(', ') || 'None'}
|
||||
\`\`\`
|
||||
___________
|
||||
| |
|
||||
| ${points > 0 ? 'O' : ''}
|
||||
| ${points > 2 ? '—' : ' '}${points > 1 ? '|' : ''}${points > 3 ? '—' : ''}
|
||||
| ${points > 4 ? '/' : ''} ${points > 5 ? '\\' : ''}
|
||||
===========
|
||||
\`\`\`
|
||||
`);
|
||||
const filter = res => {
|
||||
const choice = res.content.toLowerCase();
|
||||
return res.author.id === msg.author.id && !confirmation.includes(choice) && !incorrect.includes(choice);
|
||||
};
|
||||
const guess = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!guess.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
break;
|
||||
}
|
||||
const choice = guess.first().content.toLowerCase();
|
||||
if (choice === 'end') break;
|
||||
if (choice.length > 1 && choice === word) {
|
||||
guessed = true;
|
||||
break;
|
||||
} else if (word.includes(choice)) {
|
||||
displayText = true;
|
||||
for (let i = 0; i < word.length; i++) {
|
||||
if (word.charAt(i) !== choice) continue; // eslint-disable-line max-depth
|
||||
confirmation.push(word.charAt(i));
|
||||
display[i] = word.charAt(i);
|
||||
}
|
||||
} else {
|
||||
displayText = false;
|
||||
if (choice.length === 1) incorrect.push(choice);
|
||||
points++;
|
||||
}
|
||||
const word = words[Math.floor(Math.random() * words.length)].toLowerCase();
|
||||
let points = 0;
|
||||
let displayText = null;
|
||||
let guessed = false;
|
||||
const confirmation = [];
|
||||
const incorrect = [];
|
||||
const display = new Array(word.length).fill('_');
|
||||
while (word.length !== confirmation.length && points < 6) {
|
||||
await msg.say(stripIndents`
|
||||
${displayText === null ? 'Here we go!' : displayText ? 'Good job!' : 'Nope!'}
|
||||
\`${display.join(' ')}\`. Which letter do you choose? Type \`end\` to forfeit.
|
||||
Incorrect Tries: ${incorrect.join(', ') || 'None'}
|
||||
\`\`\`
|
||||
___________
|
||||
| |
|
||||
| ${points > 0 ? 'O' : ''}
|
||||
| ${points > 2 ? '—' : ' '}${points > 1 ? '|' : ''}${points > 3 ? '—' : ''}
|
||||
| ${points > 4 ? '/' : ''} ${points > 5 ? '\\' : ''}
|
||||
===========
|
||||
\`\`\`
|
||||
`);
|
||||
const filter = res => {
|
||||
const choice = res.content.toLowerCase();
|
||||
return res.author.id === msg.author.id && !confirmation.includes(choice) && !incorrect.includes(choice);
|
||||
};
|
||||
const guess = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!guess.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
break;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
const defined = await this.defineWord(word);
|
||||
if (word.length === confirmation.length || guessed) {
|
||||
return msg.say(stripIndents`
|
||||
You won, it was ${word}!
|
||||
|
||||
${defined ? `**${defined.name}** (${defined.partOfSpeech})` : ''}
|
||||
${defined ? defined.definiton : ''}
|
||||
`);
|
||||
const choice = guess.first().content.toLowerCase();
|
||||
if (choice === 'end') break;
|
||||
if (choice.length > 1 && choice === word) {
|
||||
guessed = true;
|
||||
break;
|
||||
} else if (word.includes(choice)) {
|
||||
displayText = true;
|
||||
for (let i = 0; i < word.length; i++) {
|
||||
if (word.charAt(i) !== choice) continue; // eslint-disable-line max-depth
|
||||
confirmation.push(word.charAt(i));
|
||||
display[i] = word.charAt(i);
|
||||
}
|
||||
} else {
|
||||
displayText = false;
|
||||
if (choice.length === 1) incorrect.push(choice);
|
||||
points++;
|
||||
}
|
||||
}
|
||||
const defined = await this.defineWord(word);
|
||||
if (word.length === confirmation.length || guessed) {
|
||||
return msg.say(stripIndents`
|
||||
Too bad... It was ${word}...
|
||||
You won, it was ${word}!
|
||||
|
||||
${defined ? `**${defined.name}** (${defined.partOfSpeech})` : ''}
|
||||
${defined ? defined.definiton : ''}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
return msg.say(stripIndents`
|
||||
Too bad... It was ${word}...
|
||||
|
||||
${defined ? `**${defined.name}** (${defined.partOfSpeech})` : ''}
|
||||
${defined ? defined.definiton : ''}
|
||||
`);
|
||||
}
|
||||
|
||||
async defineWord(word) {
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = class HearingTestCommand extends Command {
|
||||
},
|
||||
guildOnly: true,
|
||||
userPermissions: ['CONNECT', 'SPEAK'],
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Noise addicts',
|
||||
@@ -36,37 +37,33 @@ module.exports = class HearingTestCommand extends Command {
|
||||
return msg.reply(`I am not in a voice channel. Use ${usage} to fix that!`);
|
||||
}
|
||||
if (!connection.canPlay) return msg.reply('I am already playing audio in this server.');
|
||||
try {
|
||||
let age;
|
||||
let range;
|
||||
let previousAge = 'all';
|
||||
let previousRange = 8;
|
||||
for (const { age: dataAge, khz, file } of data) {
|
||||
connection.play(path.join(__dirname, '..', '..', 'assets', 'sounds', 'hearing-test', file));
|
||||
await delay(3500);
|
||||
await msg.reply('Did you hear that sound? Reply with **[y]es** or **[n]o**.');
|
||||
const heard = await verify(msg.channel, msg.author);
|
||||
if (!heard || file === data[data.length - 1].file) {
|
||||
age = previousAge;
|
||||
range = previousRange;
|
||||
break;
|
||||
}
|
||||
previousAge = dataAge;
|
||||
previousRange = khz;
|
||||
}
|
||||
if (age === 'all') return msg.reply('Everyone should be able to hear that. You cannot hear.');
|
||||
if (age === 'max') {
|
||||
return msg.reply(stripIndents`
|
||||
You can hear any frequency of which a human is capable.
|
||||
The maximum frequency you were able to hear was **${range}000hz**.
|
||||
`);
|
||||
let age;
|
||||
let range;
|
||||
let previousAge = 'all';
|
||||
let previousRange = 8;
|
||||
for (const { age: dataAge, khz, file } of data) {
|
||||
connection.play(path.join(__dirname, '..', '..', 'assets', 'sounds', 'hearing-test', file));
|
||||
await delay(3500);
|
||||
await msg.reply('Did you hear that sound? Reply with **[y]es** or **[n]o**.');
|
||||
const heard = await verify(msg.channel, msg.author);
|
||||
if (!heard || file === data[data.length - 1].file) {
|
||||
age = previousAge;
|
||||
range = previousRange;
|
||||
break;
|
||||
}
|
||||
previousAge = dataAge;
|
||||
previousRange = khz;
|
||||
}
|
||||
if (age === 'all') return msg.reply('Everyone should be able to hear that. You cannot hear.');
|
||||
if (age === 'max') {
|
||||
return msg.reply(stripIndents`
|
||||
You have the hearing of someone **${Number.parseInt(age, 10) + 1} or older**.
|
||||
You can hear any frequency of which a human is capable.
|
||||
The maximum frequency you were able to hear was **${range}000hz**.
|
||||
`);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
return msg.reply(stripIndents`
|
||||
You have the hearing of someone **${Number.parseInt(age, 10) + 1} or older**.
|
||||
The maximum frequency you were able to hear was **${range}000hz**.
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@ module.exports = class HorseRaceCommand extends Command {
|
||||
duration: 10
|
||||
},
|
||||
clientPermissions: ['ATTACH_FILES'],
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Ambition',
|
||||
|
||||
@@ -11,6 +11,7 @@ module.exports = class HungerGamesCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'hunger-games',
|
||||
description: 'Simulate a Hunger Games match with up to 24 tributes.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'BrantSteele',
|
||||
@@ -36,55 +37,43 @@ module.exports = class HungerGamesCommand extends Command {
|
||||
if (removeDuplicates(tributes).length !== tributes.length) {
|
||||
return msg.reply('Please do not enter the same tribute twice.');
|
||||
}
|
||||
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 {
|
||||
let sun = true;
|
||||
let turn = 0;
|
||||
let bloodbath = true;
|
||||
const kills = {};
|
||||
for (const tribute of tributes) kills[tribute] = 0;
|
||||
const remaining = new Set(shuffle(tributes));
|
||||
while (remaining.size > 1) {
|
||||
if (!bloodbath && sun) ++turn;
|
||||
const sunEvents = bloodbath ? events.bloodbath : sun ? events.day : events.night;
|
||||
const results = [];
|
||||
const deaths = [];
|
||||
this.makeEvents(remaining, kills, sunEvents, deaths, results);
|
||||
let text = stripIndents`
|
||||
__**${bloodbath ? 'Bloodbath' : sun ? `Day ${turn}` : `Night ${turn}`}:**__
|
||||
${results.join('\n')}
|
||||
let sun = true;
|
||||
let turn = 0;
|
||||
let bloodbath = true;
|
||||
const kills = {};
|
||||
for (const tribute of tributes) kills[tribute] = 0;
|
||||
const remaining = new Set(shuffle(tributes));
|
||||
while (remaining.size > 1) {
|
||||
if (!bloodbath && sun) ++turn;
|
||||
const sunEvents = bloodbath ? events.bloodbath : sun ? events.day : events.night;
|
||||
const results = [];
|
||||
const deaths = [];
|
||||
this.makeEvents(remaining, kills, sunEvents, deaths, results);
|
||||
let text = stripIndents`
|
||||
__**${bloodbath ? 'Bloodbath' : sun ? `Day ${turn}` : `Night ${turn}`}:**__
|
||||
${results.join('\n')}
|
||||
`;
|
||||
if (deaths.length) {
|
||||
text += '\n\n';
|
||||
text += stripIndents`
|
||||
**${deaths.length} cannon shot${deaths.length === 1 ? '' : 's'} can be heard in the distance.**
|
||||
${deaths.join('\n')}
|
||||
`;
|
||||
if (deaths.length) {
|
||||
text += '\n\n';
|
||||
text += stripIndents`
|
||||
**${deaths.length} cannon shot${deaths.length === 1 ? '' : 's'} can be heard in the distance.**
|
||||
${deaths.join('\n')}
|
||||
`;
|
||||
}
|
||||
text += `\n\n_Proceed?_`;
|
||||
await msg.say(text);
|
||||
const verification = await verify(msg.channel, msg.author, { time: 120000 });
|
||||
if (!verification) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('See you next time!');
|
||||
}
|
||||
if (!bloodbath) sun = !sun;
|
||||
if (bloodbath) bloodbath = false;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
const remainingArr = Array.from(remaining);
|
||||
return msg.say(stripIndents`
|
||||
And the winner is... **${remainingArr[0]}**!
|
||||
|
||||
__**Kills Leaderboard:**__
|
||||
${this.makeLeaderboard(tributes, kills).join('\n')}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
text += `\n\n_Proceed?_`;
|
||||
await msg.say(text);
|
||||
const verification = await verify(msg.channel, msg.author, { time: 120000 });
|
||||
if (!verification) return msg.say('See you next time!');
|
||||
if (!bloodbath) sun = !sun;
|
||||
if (bloodbath) bloodbath = false;
|
||||
}
|
||||
const remainingArr = Array.from(remaining);
|
||||
return msg.say(stripIndents`
|
||||
And the winner is... **${remainingArr[0]}**!
|
||||
|
||||
__**Kills Leaderboard:**__
|
||||
${this.makeLeaderboard(tributes, kills).join('\n')}
|
||||
`);
|
||||
}
|
||||
|
||||
parseEvent(event, tributes) {
|
||||
|
||||
@@ -16,6 +16,7 @@ module.exports = class JeopardyCommand extends Command {
|
||||
usages: 2,
|
||||
duration: 10
|
||||
},
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'jService',
|
||||
@@ -38,39 +39,30 @@ module.exports = class JeopardyCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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.`);
|
||||
try {
|
||||
this.client.games.set(msg.channel.id, { name: this.name });
|
||||
const question = await this.fetchQuestion();
|
||||
const clueCard = await this.generateClueCard(question.question.replace(/<\/?i>/gi, ''));
|
||||
const connection = msg.guild ? this.client.dispatchers.get(msg.guild.id) : null;
|
||||
let playing = false;
|
||||
if (msg.guild && connection && connection.canPlay) {
|
||||
playing = true;
|
||||
connection.play(path.join(__dirname, '..', '..', 'assets', 'sounds', 'jeopardy.mp3'));
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
}
|
||||
const category = question.category ? question.category.title.toUpperCase() : '';
|
||||
await msg.reply(`${category ? `The category is: **${category}**. ` : ''}30 seconds, good luck.`, {
|
||||
files: [{ attachment: clueCard, name: 'clue-card.png' }]
|
||||
});
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (playing) connection.stop();
|
||||
const answer = question.answer.replace(/<\/?i>/gi, '*').replace(/\(|\)/g, '');
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!msgs.size) return msg.reply(`Time's up, the answer was **${answer}**.`);
|
||||
const win = msgs.first().content.toLowerCase() === answer.toLowerCase();
|
||||
if (!win) return msg.reply(`The answer was **${answer}**.`);
|
||||
return msg.reply(`The answer was **${answer}**. Good job!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
const question = await this.fetchQuestion();
|
||||
const clueCard = await this.generateClueCard(question.question.replace(/<\/?i>/gi, ''));
|
||||
const connection = msg.guild ? this.client.dispatchers.get(msg.guild.id) : null;
|
||||
let playing = false;
|
||||
if (msg.guild && connection && connection.canPlay) {
|
||||
playing = true;
|
||||
connection.play(path.join(__dirname, '..', '..', 'assets', 'sounds', 'jeopardy.mp3'));
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
}
|
||||
const category = question.category ? question.category.title.toUpperCase() : '';
|
||||
await msg.reply(`${category ? `The category is: **${category}**. ` : ''}30 seconds, good luck.`, {
|
||||
files: [{ attachment: clueCard, name: 'clue-card.png' }]
|
||||
});
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (playing) connection.stop();
|
||||
const answer = question.answer.replace(/<\/?i>/gi, '*').replace(/\(|\)/g, '');
|
||||
if (!msgs.size) return msg.reply(`Time's up, the answer was **${answer}**.`);
|
||||
const win = msgs.first().content.toLowerCase() === answer.toLowerCase();
|
||||
if (!win) return msg.reply(`The answer was **${answer}**.`);
|
||||
return msg.reply(`The answer was **${answer}**. Good job!`);
|
||||
}
|
||||
|
||||
async fetchQuestion() {
|
||||
|
||||
@@ -9,6 +9,7 @@ module.exports = class MadLibsCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'mad-libs',
|
||||
description: 'Choose words that fill in the blanks to create a crazy story!',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Mad Libs',
|
||||
@@ -25,39 +26,30 @@ module.exports = class MadLibsCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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 lib = libs[Math.floor(Math.random() * libs.length)];
|
||||
const choices = [];
|
||||
for (const word of lib.needed) {
|
||||
await msg.reply(`Give me a **${word}**.`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
if (!res.content || res.content.length > 12) {
|
||||
msg.reply('Please only use a maximum of 12 characters per word.').catch(() => null);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const choice = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!choice.size) break;
|
||||
choices.push(choice.first().content);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
let finished = lib.text;
|
||||
for (let i = 0; i < choices.length; i++) {
|
||||
finished = finished.replaceAll(`{${i}}`, `**${choices[i]}**`);
|
||||
}
|
||||
return msg.say(finished);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const lib = libs[Math.floor(Math.random() * libs.length)];
|
||||
const choices = [];
|
||||
for (const word of lib.needed) {
|
||||
await msg.reply(`Give me a **${word}**.`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
if (!res.content || res.content.length > 12) {
|
||||
msg.reply('Please only use a maximum of 12 characters per word.').catch(() => null);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const choice = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!choice.size) break;
|
||||
choices.push(choice.first().content);
|
||||
}
|
||||
let finished = lib.text;
|
||||
for (let i = 0; i < choices.length; i++) {
|
||||
finished = finished.replaceAll(`{${i}}`, `**${choices[i]}**`);
|
||||
}
|
||||
return msg.say(finished);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@ module.exports = class MathQuizCommand extends Command {
|
||||
memberName: 'math-quiz',
|
||||
description: 'See how fast you can answer a math problem in a given time limit.',
|
||||
details: `**Difficulties:** ${difficulties.join(', ')}`,
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'difficulty',
|
||||
|
||||
+19
-27
@@ -12,6 +12,7 @@ module.exports = class MemoryCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'memory',
|
||||
description: 'Test your memory.',
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'level',
|
||||
@@ -24,33 +25,24 @@ module.exports = class MemoryCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { level }) {
|
||||
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 memorize = this.genArray(level);
|
||||
const memorizeDisplay = memorize.map(word => `\`${word.toUpperCase()}\``).join(' ');
|
||||
const memorizeMsg = await msg.say(stripIndents`
|
||||
**You have 10 seconds to memorize:**
|
||||
${memorizeDisplay}
|
||||
`);
|
||||
await delay(10000);
|
||||
await memorizeMsg.edit('Type what you saw. Don\'t worry about formatting, just the words.');
|
||||
const memorizeType = memorize.join(' ');
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => msg.author.id === res.author.id,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!msgs.size) return msg.say(`Sorry, time is up! It was ${memorizeDisplay}.`);
|
||||
const answer = msgs.first().content.toLowerCase();
|
||||
if (answer !== memorizeType) return msg.say(`Sorry, you typed it wrong. It was ${memorizeDisplay}.`);
|
||||
return msg.say('Nice job! 10/10! You deserve some cake!');
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
const memorize = this.genArray(level);
|
||||
const memorizeDisplay = memorize.map(word => `\`${word.toUpperCase()}\``).join(' ');
|
||||
const memorizeMsg = await msg.say(stripIndents`
|
||||
**You have 10 seconds to memorize:**
|
||||
${memorizeDisplay}
|
||||
`);
|
||||
await delay(10000);
|
||||
await memorizeMsg.edit('Type what you saw. Don\'t worry about formatting, just the words.');
|
||||
const memorizeType = memorize.join(' ');
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => msg.author.id === res.author.id,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!msgs.size) return msg.say(`Sorry, time is up! It was ${memorizeDisplay}.`);
|
||||
const answer = msgs.first().content.toLowerCase();
|
||||
if (answer !== memorizeType) return msg.say(`Sorry, you typed it wrong. It was ${memorizeDisplay}.`);
|
||||
return msg.say('Nice job! 10/10! You deserve some cake!');
|
||||
}
|
||||
|
||||
genArray(level) {
|
||||
|
||||
@@ -15,6 +15,7 @@ module.exports = class MinesweeperCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'minesweeper',
|
||||
description: 'Play a game of Minesweeper.',
|
||||
game: true,
|
||||
args: [
|
||||
{
|
||||
key: 'size',
|
||||
@@ -28,116 +29,107 @@ module.exports = class MinesweeperCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { size }) {
|
||||
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.`);
|
||||
try {
|
||||
const game = new BombSweeper(size, size);
|
||||
this.client.games.set(msg.channel.id, { name: this.name, data: game });
|
||||
game.PlaceBombs(size + 1); // eslint-disable-line new-cap
|
||||
let win = null;
|
||||
game.onWin = () => { win = true; };
|
||||
game.onLoss = () => { win = false; };
|
||||
const flagged = [];
|
||||
const startTime = new Date();
|
||||
let cheatMode = false;
|
||||
while (win === null) {
|
||||
const currentTime = moment.duration(new Date() - startTime).format('mm:ss');
|
||||
await msg.say(stripIndents`
|
||||
${msg.author}, what coordinates do you pick (ex. 4,5)? Type \`end\` to forfeit.
|
||||
Type \`flag <coordinates>\` to flag a spot as a bomb. To remove a flag, run it again.
|
||||
You can also use ranges to mark multiple spots (ex. 4-7,5 or 7,4-5).
|
||||
const game = new BombSweeper(size, size);
|
||||
game.PlaceBombs(size + 1); // eslint-disable-line new-cap
|
||||
let win = null;
|
||||
game.onWin = () => { win = true; };
|
||||
game.onLoss = () => { win = false; };
|
||||
const flagged = [];
|
||||
const startTime = new Date();
|
||||
let cheatMode = false;
|
||||
while (win === null) {
|
||||
const currentTime = moment.duration(new Date() - startTime).format('mm:ss');
|
||||
await msg.say(stripIndents`
|
||||
${msg.author}, what coordinates do you pick (ex. 4,5)? Type \`end\` to forfeit.
|
||||
Type \`flag <coordinates>\` to flag a spot as a bomb. To remove a flag, run it again.
|
||||
You can also use ranges to mark multiple spots (ex. 4-7,5 or 7,4-5).
|
||||
|
||||
${this.displayBoard(game.board, game.mask, flagged, cheatMode)}
|
||||
**Total Mines:** ${size + 1} | **Flagged:** ${flagged.length} | **Time:** ${currentTime}
|
||||
`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'xyzzy' && !cheatMode) return true;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
const coordPicked = pick.match(turnRegex);
|
||||
if (!coordPicked) return false;
|
||||
const x = Number.parseInt(coordPicked[2], 10);
|
||||
const y = Number.parseInt(coordPicked[4], 10);
|
||||
if (x > size || y > size || x < 1 || y < 1) return false;
|
||||
if (game.mask[y - 1][x - 1]) return false;
|
||||
return true;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
break;
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
win = false;
|
||||
break;
|
||||
}
|
||||
if (choice.toLowerCase() === 'xyzzy') {
|
||||
cheatMode = true;
|
||||
await msg.say('Cheat mode is now active. No high score will be saved.');
|
||||
continue;
|
||||
}
|
||||
const coordPicked = choice.match(turnRegex);
|
||||
${this.displayBoard(game.board, game.mask, flagged, cheatMode)}
|
||||
**Total Mines:** ${size + 1} | **Flagged:** ${flagged.length} | **Time:** ${currentTime}
|
||||
`);
|
||||
const filter = res => {
|
||||
if (res.author.id !== msg.author.id) return false;
|
||||
const pick = res.content;
|
||||
if (pick.toLowerCase() === 'xyzzy' && !cheatMode) return true;
|
||||
if (pick.toLowerCase() === 'end') return true;
|
||||
const coordPicked = pick.match(turnRegex);
|
||||
if (!coordPicked) return false;
|
||||
const x = Number.parseInt(coordPicked[2], 10);
|
||||
const y = Number.parseInt(coordPicked[4], 10);
|
||||
const xRange = coordPicked[3] ? Math.abs(Number.parseInt(coordPicked[3], 10)) : null;
|
||||
const yRange = coordPicked[5] ? Math.abs(Number.parseInt(coordPicked[5], 10)) : null;
|
||||
const flag = Boolean(coordPicked[1]);
|
||||
if (xRange && yRange) {
|
||||
await msg.say('You cannot have both an X and Y range.');
|
||||
continue;
|
||||
}
|
||||
if ((yRange && flag) || (xRange && flag)) {
|
||||
await msg.say('You cannot flag a range.');
|
||||
continue;
|
||||
}
|
||||
if (xRange) {
|
||||
for (let i = x; i <= xRange; i++) {
|
||||
const keepGoing = await this.runResult(msg, game, i, y, flag, flagged, win);
|
||||
if (keepGoing === false) break;
|
||||
if (keepGoing === null) continue;
|
||||
}
|
||||
} else if (yRange) {
|
||||
for (let i = y; i <= yRange; i++) {
|
||||
const keepGoing = await this.runResult(msg, game, x, i, flag, flagged, win);
|
||||
if (keepGoing === false) break;
|
||||
if (keepGoing === null) continue;
|
||||
}
|
||||
} else {
|
||||
const keepGoing = await this.runResult(msg, game, x, y, flag, flagged, win);
|
||||
if (x > size || y > size || x < 1 || y < 1) return false;
|
||||
if (game.mask[y - 1][x - 1]) return false;
|
||||
return true;
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
break;
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
if (choice.toLowerCase() === 'end') {
|
||||
win = false;
|
||||
break;
|
||||
}
|
||||
if (choice.toLowerCase() === 'xyzzy') {
|
||||
cheatMode = true;
|
||||
await msg.say('Cheat mode is now active. No high score will be saved.');
|
||||
continue;
|
||||
}
|
||||
const coordPicked = choice.match(turnRegex);
|
||||
const x = Number.parseInt(coordPicked[2], 10);
|
||||
const y = Number.parseInt(coordPicked[4], 10);
|
||||
const xRange = coordPicked[3] ? Math.abs(Number.parseInt(coordPicked[3], 10)) : null;
|
||||
const yRange = coordPicked[5] ? Math.abs(Number.parseInt(coordPicked[5], 10)) : null;
|
||||
const flag = Boolean(coordPicked[1]);
|
||||
if (xRange && yRange) {
|
||||
await msg.say('You cannot have both an X and Y range.');
|
||||
continue;
|
||||
}
|
||||
if ((yRange && flag) || (xRange && flag)) {
|
||||
await msg.say('You cannot flag a range.');
|
||||
continue;
|
||||
}
|
||||
if (xRange) {
|
||||
for (let i = x; i <= xRange; i++) {
|
||||
const keepGoing = await this.runResult(msg, game, i, y, flag, flagged, win);
|
||||
if (keepGoing === false) break;
|
||||
if (keepGoing === null) continue;
|
||||
}
|
||||
} else if (yRange) {
|
||||
for (let i = y; i <= yRange; i++) {
|
||||
const keepGoing = await this.runResult(msg, game, x, i, flag, flagged, win);
|
||||
if (keepGoing === false) break;
|
||||
if (keepGoing === null) continue;
|
||||
}
|
||||
} else {
|
||||
const keepGoing = await this.runResult(msg, game, x, y, flag, flagged, win);
|
||||
if (keepGoing === false) break;
|
||||
if (keepGoing === null) continue;
|
||||
}
|
||||
const newScore = Date.now() - startTime;
|
||||
const highScoreGet = await this.client.redis.get(`minesweeper-${size}`);
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get(`minesweeper-${size}-user`);
|
||||
const scoreBeat = !cheatMode && win && (!highScore || highScore > newScore);
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set(`minesweeper-${size}`, newScore);
|
||||
await this.client.redis.set(`minesweeper-${size}-user`, msg.author.id);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (win === null) return msg.say('Game ended due to inactivity.');
|
||||
const newDisplayTime = moment.duration(newScore).format('mm:ss');
|
||||
const displayTime = moment.duration(highScore).format('mm:ss');
|
||||
return msg.say(stripIndents`
|
||||
${win ? `Nice job! You win! (Took ${newDisplayTime})` : 'Sorry... You lose.'}
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${displayTime} (Held by ${user})
|
||||
|
||||
${this.displayBoard(game.board)}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
const newScore = Date.now() - startTime;
|
||||
const highScoreGet = await this.client.redis.get(`minesweeper-${size}`);
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get(`minesweeper-${size}-user`);
|
||||
const scoreBeat = !cheatMode && win && (!highScore || highScore > newScore);
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set(`minesweeper-${size}`, newScore);
|
||||
await this.client.redis.set(`minesweeper-${size}-user`, msg.author.id);
|
||||
}
|
||||
if (win === null) return msg.say('Game ended due to inactivity.');
|
||||
const newDisplayTime = moment.duration(newScore).format('mm:ss');
|
||||
const displayTime = moment.duration(highScore).format('mm:ss');
|
||||
return msg.say(stripIndents`
|
||||
${win ? `Nice job! You win! (Took ${newDisplayTime})` : 'Sorry... You lose.'}
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${displayTime} (Held by ${user})
|
||||
|
||||
${this.displayBoard(game.board)}
|
||||
`);
|
||||
}
|
||||
|
||||
async runResult(msg, game, x, y, flag, flagged, win) {
|
||||
|
||||
@@ -19,6 +19,7 @@ module.exports = class PokemonAdvantageCommand extends Command {
|
||||
duration: 10
|
||||
},
|
||||
clientPermissions: ['ATTACH_FILES'],
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Pokémon',
|
||||
@@ -64,44 +65,35 @@ module.exports = class PokemonAdvantageCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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 num1 = Math.floor(Math.random() * (this.client.pokemon.pokemonCount + 1));
|
||||
const pkmn1 = await this.client.pokemon.fetch(num1);
|
||||
const num2 = Math.floor(Math.random() * (this.client.pokemon.pokemonCount + 1));
|
||||
const pkmn2 = await this.client.pokemon.fetch(num2);
|
||||
await pkmn1.fetchDefaultVariety();
|
||||
await pkmn2.fetchDefaultVariety();
|
||||
const attachment = await this.createImage(pkmn1, pkmn2, null);
|
||||
const answer = this.calculateAdvantage(pkmn1, pkmn2);
|
||||
const answerAttachment = await this.createImage(pkmn1, pkmn2, answer);
|
||||
await msg.reply(stripIndents`
|
||||
**You have 15 seconds, who\'s got the type advantage?**
|
||||
_If the Pokémon are evenly matched, type \`even\`._
|
||||
`, { files: [attachment] });
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!msgs.size) return msg.reply(`Time! It's **${answer.name}**!`, { files: [answerAttachment] });
|
||||
const guess = msgs.first().content.toLowerCase();
|
||||
const slug = this.client.pokemon.makeSlug(guess);
|
||||
if (answer === true) {
|
||||
if (guess === 'even') return msg.reply('Nice! These two are even!', { files: [answerAttachment] });
|
||||
return msg.reply('Nope! These two are even!', { files: [answerAttachment] });
|
||||
}
|
||||
if (!answer.names.includes(guess) && answer.slug !== slug) {
|
||||
return msg.reply(`Nope! It's **${answer.name}**!`, { files: [answerAttachment] });
|
||||
}
|
||||
return msg.reply(`Nice! It's **${answer.name}**!`, { files: [answerAttachment] });
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
const num1 = Math.floor(Math.random() * (this.client.pokemon.pokemonCount + 1));
|
||||
const pkmn1 = await this.client.pokemon.fetch(num1);
|
||||
const num2 = Math.floor(Math.random() * (this.client.pokemon.pokemonCount + 1));
|
||||
const pkmn2 = await this.client.pokemon.fetch(num2);
|
||||
await pkmn1.fetchDefaultVariety();
|
||||
await pkmn2.fetchDefaultVariety();
|
||||
const attachment = await this.createImage(pkmn1, pkmn2, null);
|
||||
const answer = this.calculateAdvantage(pkmn1, pkmn2);
|
||||
const answerAttachment = await this.createImage(pkmn1, pkmn2, answer);
|
||||
await msg.reply(stripIndents`
|
||||
**You have 15 seconds, who\'s got the type advantage?**
|
||||
_If the Pokémon are evenly matched, type \`even\`._
|
||||
`, { files: [attachment] });
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
if (!msgs.size) return msg.reply(`Time! It's **${answer.name}**!`, { files: [answerAttachment] });
|
||||
const guess = msgs.first().content.toLowerCase();
|
||||
const slug = this.client.pokemon.makeSlug(guess);
|
||||
if (answer === true) {
|
||||
if (guess === 'even') return msg.reply('Nice! These two are even!', { files: [answerAttachment] });
|
||||
return msg.reply('Nope! These two are even!', { files: [answerAttachment] });
|
||||
}
|
||||
if (!answer.names.includes(guess) && answer.slug !== slug) {
|
||||
return msg.reply(`Nope! It's **${answer.name}**!`, { files: [answerAttachment] });
|
||||
}
|
||||
return msg.reply(`Nice! It's **${answer.name}**!`, { files: [answerAttachment] });
|
||||
}
|
||||
|
||||
async createImage(pokemon1, pokemon2, winner) {
|
||||
|
||||
+28
-31
@@ -14,6 +14,7 @@ module.exports = class QuizCommand extends Command {
|
||||
memberName: 'quiz',
|
||||
description: 'Answer a quiz question.',
|
||||
details: `**Difficulties:** ${difficulties.join(', ')}`,
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Open Trivia DB',
|
||||
@@ -35,37 +36,33 @@ module.exports = class QuizCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { difficulty }) {
|
||||
try {
|
||||
const { body } = await request
|
||||
.get('https://opentdb.com/api.php')
|
||||
.query({
|
||||
amount: 1,
|
||||
type: 'multiple',
|
||||
encode: 'url3986',
|
||||
difficulty
|
||||
});
|
||||
if (!body.results) return msg.reply('Oh no, a question could not be fetched. Try again later!');
|
||||
const answers = body.results[0].incorrect_answers.map(answer => decodeURIComponent(answer.toLowerCase()));
|
||||
const correct = decodeURIComponent(body.results[0].correct_answer.toLowerCase());
|
||||
answers.push(correct);
|
||||
const shuffled = shuffle(answers);
|
||||
await msg.reply(stripIndents`
|
||||
**You have 15 seconds. The category is _${decodeURIComponent(body.results[0].category)}_.**
|
||||
${decodeURIComponent(body.results[0].question)}
|
||||
${shuffled.map((answer, i) => `**${choices[i]}.** ${answer}`).join('\n')}
|
||||
`);
|
||||
const filter = res => res.author.id === msg.author.id && choices.includes(res.content.toUpperCase());
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 15000
|
||||
const { body } = await request
|
||||
.get('https://opentdb.com/api.php')
|
||||
.query({
|
||||
amount: 1,
|
||||
type: 'multiple',
|
||||
encode: 'url3986',
|
||||
difficulty
|
||||
});
|
||||
if (!msgs.size) return msg.reply(`Sorry, time is up! It was ${correct}.`);
|
||||
const win = shuffled[choices.indexOf(msgs.first().content.toUpperCase())] === correct;
|
||||
if (!win) return msg.reply(`Nope, sorry, it's ${correct}.`);
|
||||
return msg.reply('Nice job! 10/10! You deserve some cake!');
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
if (!body.results) return msg.reply('Oh no, a question could not be fetched. Try again later!');
|
||||
const answers = body.results[0].incorrect_answers.map(answer => decodeURIComponent(answer.toLowerCase()));
|
||||
const correct = decodeURIComponent(body.results[0].correct_answer.toLowerCase());
|
||||
answers.push(correct);
|
||||
const shuffled = shuffle(answers);
|
||||
await msg.reply(stripIndents`
|
||||
**You have 15 seconds. The category is _${decodeURIComponent(body.results[0].category)}_.**
|
||||
${decodeURIComponent(body.results[0].question)}
|
||||
${shuffled.map((answer, i) => `**${choices[i]}.** ${answer}`).join('\n')}
|
||||
`);
|
||||
const filter = res => res.author.id === msg.author.id && choices.includes(res.content.toUpperCase());
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
if (!msgs.size) return msg.reply(`Sorry, time is up! It was ${correct}.`);
|
||||
const win = shuffled[choices.indexOf(msgs.first().content.toUpperCase())] === correct;
|
||||
if (!win) return msg.reply(`Nope, sorry, it's ${correct}.`);
|
||||
return msg.reply('Nice job! 10/10! You deserve some cake!');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,45 +10,37 @@ module.exports = class ReactionTimeCommand extends Command {
|
||||
aliases: ['reaction', 'react', 'gunfight-sp', 'sp-gunfight'],
|
||||
group: 'games-sp',
|
||||
memberName: 'reaction-time',
|
||||
description: 'Test your reaction time.'
|
||||
description: 'Test your reaction time.',
|
||||
game: true
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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 {
|
||||
await msg.say('Get Ready...');
|
||||
await delay(randomRange(1000, 30000));
|
||||
const word = words[Math.floor(Math.random() * words.length)];
|
||||
await msg.say(`TYPE \`${word.toUpperCase()}\` NOW!`);
|
||||
const filter = res => msg.author.id === res.author.id && res.content.toLowerCase() === word;
|
||||
const now = Date.now();
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
const newScore = Date.now() - now;
|
||||
const highScoreGet = await this.client.redis.get('reaction-time');
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get('reaction-time-user');
|
||||
const scoreBeat = !highScore || highScore > newScore;
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set('reaction-time', newScore);
|
||||
await this.client.redis.set('reaction-time-user', msg.author.id);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!msgs.size) return msg.say('Failed to answer within 30 seconds.');
|
||||
return msg.say(stripIndents`
|
||||
Nice one! (Took ${newScore / 1000} seconds)
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${highScore / 1000} (Held by ${user})
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
await msg.say('Get Ready...');
|
||||
await delay(randomRange(1000, 30000));
|
||||
const word = words[Math.floor(Math.random() * words.length)];
|
||||
await msg.say(`TYPE \`${word.toUpperCase()}\` NOW!`);
|
||||
const filter = res => msg.author.id === res.author.id && res.content.toLowerCase() === word;
|
||||
const now = Date.now();
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
const newScore = Date.now() - now;
|
||||
const highScoreGet = await this.client.redis.get('reaction-time');
|
||||
const highScore = highScoreGet ? Number.parseInt(highScoreGet, 10) : null;
|
||||
const highScoreUser = await this.client.redis.get('reaction-time-user');
|
||||
const scoreBeat = !highScore || highScore > newScore;
|
||||
const user = await fetchHSUserDisplay(this.client, highScoreUser);
|
||||
if (scoreBeat) {
|
||||
await this.client.redis.set('reaction-time', newScore);
|
||||
await this.client.redis.set('reaction-time-user', msg.author.id);
|
||||
}
|
||||
if (!msgs.size) return msg.say('Failed to answer within 30 seconds.');
|
||||
return msg.say(stripIndents`
|
||||
Nice one! (Took ${newScore / 1000} seconds)
|
||||
${scoreBeat ? `**New High Score!** Old:` : `High Score:`} ${highScore / 1000} (Held by ${user})
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ module.exports = class SortingHatCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'sorting-hat',
|
||||
description: 'Take a quiz to determine your Hogwarts house.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Pottermore',
|
||||
@@ -29,64 +30,52 @@ module.exports = class SortingHatCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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 points = {
|
||||
g: 0,
|
||||
s: 0,
|
||||
h: 0,
|
||||
r: 0
|
||||
};
|
||||
const blacklist = [];
|
||||
const questionNums = ['2', '3', '4', '5', '6', '7'];
|
||||
let turn = 1;
|
||||
while (turn < 9) {
|
||||
let question;
|
||||
if (turn === 1) {
|
||||
question = questions.first[Math.floor(Math.random() * questions.first.length)];
|
||||
} else if (turn === 8) {
|
||||
question = questions.last[Math.floor(Math.random() * questions.last.length)];
|
||||
} else {
|
||||
const possible = questionNums.filter(num => !blacklist.includes(num));
|
||||
const value = possible[Math.floor(Math.random() * possible.length)];
|
||||
const group = questions[value];
|
||||
blacklist.push(value);
|
||||
question = group[Math.floor(Math.random() * group.length)];
|
||||
}
|
||||
const answers = shuffle(question.answers);
|
||||
await msg.say(stripIndents`
|
||||
**${turn}.** ${question.text}
|
||||
${answers.map((answer, i) => `- **${choices[i]}.** ${answer.text}`).join('\n')}
|
||||
`);
|
||||
const filter = res =>
|
||||
res.author.id === msg.author.id && choices.slice(0, answers.length).includes(res.content.toUpperCase());
|
||||
const choice = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!choice.size) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say('Oh no, you ran out of time! Too bad.');
|
||||
}
|
||||
const answer = answers[choices.indexOf(choice.first().content.toUpperCase())];
|
||||
for (const [house, amount] of Object.entries(answer.points)) points[house] += amount;
|
||||
++turn;
|
||||
const points = {
|
||||
g: 0,
|
||||
s: 0,
|
||||
h: 0,
|
||||
r: 0
|
||||
};
|
||||
const blacklist = [];
|
||||
const questionNums = ['2', '3', '4', '5', '6', '7'];
|
||||
let turn = 1;
|
||||
while (turn < 9) {
|
||||
let question;
|
||||
if (turn === 1) {
|
||||
question = questions.first[Math.floor(Math.random() * questions.first.length)];
|
||||
} else if (turn === 8) {
|
||||
question = questions.last[Math.floor(Math.random() * questions.last.length)];
|
||||
} else {
|
||||
const possible = questionNums.filter(num => !blacklist.includes(num));
|
||||
const value = possible[Math.floor(Math.random() * possible.length)];
|
||||
const group = questions[value];
|
||||
blacklist.push(value);
|
||||
question = group[Math.floor(Math.random() * group.length)];
|
||||
}
|
||||
const houseResult = Object.keys(points).filter(h => points[h] > 0).sort((a, b) => points[b] - points[a]);
|
||||
this.client.games.delete(msg.channel.id);
|
||||
const totalPoints = houseResult.reduce((a, b) => a + points[b], 0);
|
||||
return msg.say(stripIndents`
|
||||
You are a member of... **${houses[houseResult[0]]}**!
|
||||
_${descriptions[houseResult[0]]}_
|
||||
|
||||
${houseResult.map(house => `${houses[house]}: ${Math.round((points[house] / totalPoints) * 100)}%`).join('\n')}
|
||||
const answers = shuffle(question.answers);
|
||||
await msg.say(stripIndents`
|
||||
**${turn}.** ${question.text}
|
||||
${answers.map((answer, i) => `- **${choices[i]}.** ${answer.text}`).join('\n')}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
const filter = res =>
|
||||
res.author.id === msg.author.id && choices.slice(0, answers.length).includes(res.content.toUpperCase());
|
||||
const choice = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!choice.size) return msg.say('Oh no, you ran out of time! Too bad.');
|
||||
const answer = answers[choices.indexOf(choice.first().content.toUpperCase())];
|
||||
for (const [house, amount] of Object.entries(answer.points)) points[house] += amount;
|
||||
++turn;
|
||||
}
|
||||
const houseResult = Object.keys(points).filter(h => points[h] > 0).sort((a, b) => points[b] - points[a]);
|
||||
const totalPoints = houseResult.reduce((a, b) => a + points[b], 0);
|
||||
return msg.say(stripIndents`
|
||||
You are a member of... **${houses[houseResult[0]]}**!
|
||||
_${descriptions[houseResult[0]]}_
|
||||
|
||||
${houseResult.map(house => `${houses[house]}: ${Math.round((points[house] / totalPoints) * 100)}%`).join('\n')}
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
+22
-30
@@ -13,6 +13,7 @@ module.exports = class TarotCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'tarot',
|
||||
description: 'Provides a fortune using Tarot cards.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'dariusk',
|
||||
@@ -50,38 +51,29 @@ module.exports = class TarotCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { question }) {
|
||||
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 deck = new TarotDeck();
|
||||
const cards = deck.draw(3);
|
||||
for (let i = 0; i < cards.length; i++) {
|
||||
const card = cards[i];
|
||||
await msg.say(stripIndents`
|
||||
Your ${displayNums[i]} card is **${card.name}**.
|
||||
This card is often associated with words like **${list(card.keywords)}**.
|
||||
const deck = new TarotDeck();
|
||||
const cards = deck.draw(3);
|
||||
for (let i = 0; i < cards.length; i++) {
|
||||
const card = cards[i];
|
||||
await msg.say(stripIndents`
|
||||
Your ${displayNums[i]} card is **${card.name}**.
|
||||
This card is often associated with words like **${list(card.keywords)}**.
|
||||
|
||||
One common meaning for this card is **${card.randomLightMeaning()}**.
|
||||
However, beware, as it could also mean **${card.randomShadowMeaning()}**.
|
||||
One common meaning for this card is **${card.randomLightMeaning()}**.
|
||||
However, beware, as it could also mean **${card.randomShadowMeaning()}**.
|
||||
|
||||
Would you like me to keep going? Type **[y]es** or **[n]o**.
|
||||
`, { files: [card.imagePath] });
|
||||
const verification = await verify(msg.channel, msg.author);
|
||||
if (!verification) break;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say(stripIndents`
|
||||
To finish with a recap, you asked the question: **${escapeMarkdown(question)}**
|
||||
|
||||
In response, the following cards were drawn:
|
||||
- ${cards.map(card => `${card.name} (${card.keywords.join(', ')})`).join('\n- ')}
|
||||
|
||||
I hope this gives you a good idea of what the future holds...
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
Would you like me to keep going? Type **[y]es** or **[n]o**.
|
||||
`, { files: [card.imagePath] });
|
||||
const verification = await verify(msg.channel, msg.author);
|
||||
if (!verification) break;
|
||||
}
|
||||
return msg.say(stripIndents`
|
||||
To finish with a recap, you asked the question: **${escapeMarkdown(question)}**
|
||||
|
||||
In response, the following cards were drawn:
|
||||
- ${cards.map(card => `${card.name} (${card.keywords.join(', ')})`).join('\n- ')}
|
||||
|
||||
I hope this gives you a good idea of what the future holds...
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,7 +11,8 @@ module.exports = class TypingTestCommand extends Command {
|
||||
name: 'typing-test',
|
||||
group: 'games-sp',
|
||||
memberName: 'typing-test',
|
||||
description: 'See how fast you can type a sentence.'
|
||||
description: 'See how fast you can type a sentence.',
|
||||
game: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ module.exports = class WhosThatPokemonCryCommand extends Command {
|
||||
guildOnly: true,
|
||||
userPermissions: ['CONNECT', 'SPEAK'],
|
||||
clientPermissions: ['ATTACH_FILES'],
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Pokémon',
|
||||
@@ -82,34 +83,25 @@ module.exports = class WhosThatPokemonCryCommand extends Command {
|
||||
const usage = this.client.registry.commands.get('join').usage();
|
||||
return msg.reply(`I am not in a voice channel. Use ${usage} to fix that!`);
|
||||
}
|
||||
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.`);
|
||||
if (!connection.canPlay) return msg.reply('I am already playing audio in this server.');
|
||||
this.client.games.set(msg.channel.id, { name: this.name });
|
||||
try {
|
||||
const data = await this.client.pokemon.fetch(pokemon.toString());
|
||||
const names = data.names.map(name => name.name.toLowerCase());
|
||||
const attachment = await this.client.registry.commands.get('whos-that-pokemon').createImage(data, false);
|
||||
connection.play(data.cry);
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
await msg.reply('**You have 15 seconds, who\'s that Pokémon?**');
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
connection.play(data.cry);
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!msgs.size) return msg.reply(`Time! It's **${data.name}**!`, { files: [attachment] });
|
||||
const guess = msgs.first().content.toLowerCase();
|
||||
const slug = this.client.pokemon.makeSlug(guess);
|
||||
if (!names.includes(guess) && data.slug !== slug) {
|
||||
return msg.reply(`Nope! It's **${data.name}**!`, { files: [attachment] });
|
||||
}
|
||||
return msg.reply(`Nice! It's **${data.name}**!`, { files: [attachment] });
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
const data = await this.client.pokemon.fetch(pokemon.toString());
|
||||
const names = data.names.map(name => name.name.toLowerCase());
|
||||
const attachment = await this.client.registry.commands.get('whos-that-pokemon').createImage(data, false);
|
||||
connection.play(data.cry);
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
await msg.reply('**You have 15 seconds, who\'s that Pokémon?**');
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
connection.play(data.cry);
|
||||
if (!msgs.size) return msg.reply(`Time! It's **${data.name}**!`, { files: [attachment] });
|
||||
const guess = msgs.first().content.toLowerCase();
|
||||
const slug = this.client.pokemon.makeSlug(guess);
|
||||
if (!names.includes(guess) && data.slug !== slug) {
|
||||
return msg.reply(`Nope! It's **${data.name}**!`, { files: [attachment] });
|
||||
}
|
||||
return msg.reply(`Nice! It's **${data.name}**!`, { files: [attachment] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = class WhosThatPokemonCommand extends Command {
|
||||
duration: 10
|
||||
},
|
||||
clientPermissions: ['ATTACH_FILES'],
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Pokémon',
|
||||
@@ -84,38 +85,29 @@ module.exports = class WhosThatPokemonCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { pokemon }) {
|
||||
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 data = await this.client.pokemon.fetch(pokemon.toString());
|
||||
const names = data.names.map(name => name.name.toLowerCase());
|
||||
const attachment = await this.createImage(data, true);
|
||||
const answerAttachment = await this.createImage(data, false);
|
||||
const connection = msg.guild ? this.client.dispatchers.get(msg.guild.id) : null;
|
||||
if (msg.guild && connection && connection.canPlay) {
|
||||
connection.play(path.join(__dirname, '..', '..', 'assets', 'sounds', 'whos-that-pokemon.mp3'));
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
}
|
||||
await msg.reply('**You have 15 seconds, who\'s that Pokémon?**', { files: [attachment] });
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
if (connection && data.cry) connection.play(data.cry);
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!msgs.size) return msg.reply(`Time! It's **${data.name}**!`, { files: [answerAttachment] });
|
||||
const guess = msgs.first().content.toLowerCase();
|
||||
const slug = this.client.pokemon.makeSlug(guess);
|
||||
if (!names.includes(guess) && data.slug !== slug) {
|
||||
return msg.reply(`Nope! It's **${data.name}**!`, { files: [answerAttachment] });
|
||||
}
|
||||
return msg.reply(`Nice! It's **${data.name}**!`, { files: [answerAttachment] });
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
const data = await this.client.pokemon.fetch(pokemon.toString());
|
||||
const names = data.names.map(name => name.name.toLowerCase());
|
||||
const attachment = await this.createImage(data, true);
|
||||
const answerAttachment = await this.createImage(data, false);
|
||||
const connection = msg.guild ? this.client.dispatchers.get(msg.guild.id) : null;
|
||||
if (msg.guild && connection && connection.canPlay) {
|
||||
connection.play(path.join(__dirname, '..', '..', 'assets', 'sounds', 'whos-that-pokemon.mp3'));
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
}
|
||||
await msg.reply('**You have 15 seconds, who\'s that Pokémon?**', { files: [attachment] });
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter: res => res.author.id === msg.author.id,
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
if (connection && data.cry) connection.play(data.cry);
|
||||
if (!msgs.size) return msg.reply(`Time! It's **${data.name}**!`, { files: [answerAttachment] });
|
||||
const guess = msgs.first().content.toLowerCase();
|
||||
const slug = this.client.pokemon.makeSlug(guess);
|
||||
if (!names.includes(guess) && data.slug !== slug) {
|
||||
return msg.reply(`Nope! It's **${data.name}**!`, { files: [answerAttachment] });
|
||||
}
|
||||
return msg.reply(`Nice! It's **${data.name}**!`, { files: [answerAttachment] });
|
||||
}
|
||||
|
||||
async createImage(pokemon, hide) {
|
||||
|
||||
@@ -12,6 +12,7 @@ module.exports = class WouldYouRatherCommand extends Command {
|
||||
group: 'games-sp',
|
||||
memberName: 'would-you-rather',
|
||||
description: 'Responds with a random "Would you rather ...?" question.',
|
||||
game: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'wouldurather.io',
|
||||
@@ -25,44 +26,34 @@ module.exports = class WouldYouRatherCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
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 {
|
||||
if (!this.availableQuestions) await this.fetchAvailableQuestions();
|
||||
const data = await this.fetchRandomQuestion();
|
||||
await msg.say(stripIndents`
|
||||
Would you rather...
|
||||
**1.** ${data.option1}
|
||||
**2.** ${data.option2}
|
||||
if (!this.availableQuestions) await this.fetchAvailableQuestions();
|
||||
const data = await this.fetchRandomQuestion();
|
||||
await msg.say(stripIndents`
|
||||
Would you rather...
|
||||
**1.** ${data.option1}
|
||||
**2.** ${data.option2}
|
||||
|
||||
_Respond with either **1** or **2** to continue._
|
||||
`);
|
||||
const filter = res => res.author.id === msg.author.id && choices.includes(res.content.toLowerCase());
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
time: 30000,
|
||||
max: 1
|
||||
});
|
||||
if (!msgs.size) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(stripIndents`
|
||||
No response? Too bad.
|
||||
${formatNumber(data.option1Votes)} - ${formatNumber(data.option2Votes)}
|
||||
`);
|
||||
}
|
||||
const option1 = msgs.first().content.toLowerCase() === '1';
|
||||
const totalVotes = Number.parseInt(data.option1Votes, 10) + Number.parseInt(data.option2Votes, 10);
|
||||
const numToUse = option1 ? Number.parseInt(data.option1Votes, 10) : Number.parseInt(data.option2Votes, 10);
|
||||
this.client.games.delete(msg.channel.id);
|
||||
_Respond with either **1** or **2** to continue._
|
||||
`);
|
||||
const filter = res => res.author.id === msg.author.id && choices.includes(res.content.toLowerCase());
|
||||
const msgs = await msg.channel.awaitMessages({
|
||||
filter,
|
||||
time: 30000,
|
||||
max: 1
|
||||
});
|
||||
if (!msgs.size) {
|
||||
return msg.reply(stripIndents`
|
||||
**${Math.round((numToUse / totalVotes) * 100)}%** of people agree!
|
||||
No response? Too bad.
|
||||
${formatNumber(data.option1Votes)} - ${formatNumber(data.option2Votes)}
|
||||
`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const option1 = msgs.first().content.toLowerCase() === '1';
|
||||
const totalVotes = Number.parseInt(data.option1Votes, 10) + Number.parseInt(data.option2Votes, 10);
|
||||
const numToUse = option1 ? Number.parseInt(data.option1Votes, 10) : Number.parseInt(data.option2Votes, 10);
|
||||
return msg.reply(stripIndents`
|
||||
**${Math.round((numToUse / totalVotes) * 100)}%** of people agree!
|
||||
${formatNumber(data.option1Votes)} - ${formatNumber(data.option2Votes)}
|
||||
`);
|
||||
}
|
||||
|
||||
async fetchAvailableQuestions() {
|
||||
|
||||
@@ -32,16 +32,12 @@ module.exports = class PokedexAbilityCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { ability }) {
|
||||
try {
|
||||
const data = await this.client.pokemon.abilities.fetch(ability);
|
||||
if (!data) return msg.say('Could not find any results.');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setTitle(data.name)
|
||||
.setDescription(data.description || 'No description available.');
|
||||
return msg.embed(embed);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const data = await this.client.pokemon.abilities.fetch(ability);
|
||||
if (!data) return msg.say('Could not find any results.');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setTitle(data.name)
|
||||
.setDescription(data.description || 'No description available.');
|
||||
return msg.embed(embed);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ module.exports = class PokedexCryCommand extends Command {
|
||||
return null;
|
||||
} catch (err) {
|
||||
await reactIfAble(msg, this.client.user, '⚠️');
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -46,10 +46,6 @@ module.exports = class PokedexImageCommand extends Command {
|
||||
}
|
||||
|
||||
run(msg, { pokemon }) {
|
||||
try {
|
||||
return msg.say(`#${pokemon.displayID} - ${pokemon.name}`, { files: [pokemon.spriteImageURL] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
return msg.say(`#${pokemon.displayID} - ${pokemon.name}`, { files: [pokemon.spriteImageURL] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,18 +32,14 @@ module.exports = class PokedexItemCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { item }) {
|
||||
try {
|
||||
const data = await this.client.pokemon.items.fetch(item);
|
||||
if (!data) return msg.say('Could not find any results.');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setTitle(data.name)
|
||||
.setDescription(data.description || 'No description available.')
|
||||
.setThumbnail(data.spriteURL)
|
||||
.addField('❯ Cost', `${data.cost} ¥`, true);
|
||||
return msg.embed(embed);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const data = await this.client.pokemon.items.fetch(item);
|
||||
if (!data) return msg.say('Could not find any results.');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setTitle(data.name)
|
||||
.setDescription(data.description || 'No description available.')
|
||||
.setThumbnail(data.spriteURL)
|
||||
.addField('❯ Cost', `${data.cost} ¥`, true);
|
||||
return msg.embed(embed);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -54,28 +54,24 @@ module.exports = class PokedexLocationCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { pokemon }) {
|
||||
try {
|
||||
if (!pokemon.gameDataCached) await pokemon.fetchGameData();
|
||||
if (!pokemon.encounters) await pokemon.fetchEncounters();
|
||||
const desc = pokemon.encounters.length
|
||||
? pokemon.encounters
|
||||
.map(location => `${location.name} (${location.versions.map(v => versions[v]).join('/')})`)
|
||||
.join('\n')
|
||||
: 'Location Unknown';
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(`#${pokemon.displayID} - ${pokemon.name}`, 'attachment://box.png', pokemon.serebiiURL)
|
||||
.setDescription(desc)
|
||||
.setThumbnail(pokemon.spriteImageURL);
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
if (!pokemon.gameDataCached) await pokemon.fetchGameData();
|
||||
if (!pokemon.encounters) await pokemon.fetchEncounters();
|
||||
const desc = pokemon.encounters.length
|
||||
? pokemon.encounters
|
||||
.map(location => `${location.name} (${location.versions.map(v => versions[v]).join('/')})`)
|
||||
.join('\n')
|
||||
: 'Location Unknown';
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(`#${pokemon.displayID} - ${pokemon.name}`, 'attachment://box.png', pokemon.serebiiURL)
|
||||
.setDescription(desc)
|
||||
.setThumbnail(pokemon.spriteImageURL);
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,22 +32,18 @@ module.exports = class PokedexMoveCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { move }) {
|
||||
try {
|
||||
const data = await this.client.pokemon.moves.fetch(move);
|
||||
if (!data) return msg.say('Could not find any results.');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setTitle(data.name)
|
||||
.setDescription(data.description ? data.cleanDescription : 'No description available.')
|
||||
.addField('❯ Accuracy', `${data.accuracy}%`, true)
|
||||
.addField('❯ Power', data.power.toString() || '???', true)
|
||||
.addField('❯ PP', data.pp.toString(), true)
|
||||
.addField('❯ Type', data.type.toString(), true)
|
||||
.addField('❯ Contest Type', data.contestType || 'N/A', true)
|
||||
.addField('❯ Class', data.class, true);
|
||||
return msg.embed(embed);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const data = await this.client.pokemon.moves.fetch(move);
|
||||
if (!data) return msg.say('Could not find any results.');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setTitle(data.name)
|
||||
.setDescription(data.description ? data.cleanDescription : 'No description available.')
|
||||
.addField('❯ Accuracy', `${data.accuracy}%`, true)
|
||||
.addField('❯ Power', data.power.toString() || '???', true)
|
||||
.addField('❯ PP', data.pp.toString(), true)
|
||||
.addField('❯ Type', data.type.toString(), true)
|
||||
.addField('❯ Contest Type', data.contestType || 'N/A', true)
|
||||
.addField('❯ Class', data.class, true);
|
||||
return msg.embed(embed);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -59,24 +59,20 @@ module.exports = class PokedexMovesetCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { pokemon }) {
|
||||
try {
|
||||
if (!pokemon.gameDataCached) await pokemon.fetchGameData();
|
||||
if (!pokemon.moveSet.length) return msg.say('This Pokémon\'s moves are not yet documented.');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(`#${pokemon.displayID} - ${pokemon.name}`, 'attachment://box.png', pokemon.serebiiURL)
|
||||
.setDescription(pokemon.moveSet.map(move => `**Level ${move.level}:** ${move.move.name}`).join('\n'))
|
||||
.setThumbnail(pokemon.spriteImageURL)
|
||||
.setFooter(`Moveset data taken from ${versions[pokemon.moveSetVersion]}.`);
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
if (!pokemon.gameDataCached) await pokemon.fetchGameData();
|
||||
if (!pokemon.moveSet.length) return msg.say('This Pokémon\'s moves are not yet documented.');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(`#${pokemon.displayID} - ${pokemon.name}`, 'attachment://box.png', pokemon.serebiiURL)
|
||||
.setDescription(pokemon.moveSet.map(move => `**Level ${move.level}:** ${move.move.name}`).join('\n'))
|
||||
.setThumbnail(pokemon.spriteImageURL)
|
||||
.setFooter(`Moveset data taken from ${versions[pokemon.moveSetVersion]}.`);
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -54,61 +54,57 @@ module.exports = class PokedexCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { pokemon, form }) {
|
||||
try {
|
||||
if (!pokemon.gameDataCached) await pokemon.fetchGameData();
|
||||
const displayForms = pokemon.varieties.filter(vrity => vrity.statsDiffer);
|
||||
const variety = displayForms.find(vrity => {
|
||||
if (!form || form === 'normal') return vrity.default;
|
||||
if (!vrity.name) return false;
|
||||
return vrity.name.toLowerCase() === form;
|
||||
});
|
||||
if (!variety) {
|
||||
const varieties = displayForms.map(vrity => vrity.name || 'Normal');
|
||||
return msg.say(`Invalid form. The forms available for this Pokémon are: ${list(varieties, 'and')}`);
|
||||
}
|
||||
const statTotal = pokemon.baseStatTotal(variety.id);
|
||||
const repeat = {
|
||||
hp: Math.round((variety.stats.hp / 255) * 10) * 2,
|
||||
atk: Math.round((variety.stats.atk / 255) * 10) * 2,
|
||||
def: Math.round((variety.stats.def / 255) * 10) * 2,
|
||||
sAtk: Math.round((variety.stats.sAtk / 255) * 10) * 2,
|
||||
sDef: Math.round((variety.stats.sDef / 255) * 10) * 2,
|
||||
spd: Math.round((variety.stats.spd / 255) * 10) * 2,
|
||||
total: Math.round((statTotal / 1125) * 10) * 2
|
||||
};
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(
|
||||
`#${pokemon.displayID} - ${pokemon.name}`,
|
||||
'attachment://box.png',
|
||||
pokemon.serebiiURL
|
||||
)
|
||||
.setThumbnail(pokemon.formSpriteImageURL(variety.id))
|
||||
.addField(`❯ Base Stats (${variety.name || 'Normal'} Form)`, stripIndents`
|
||||
\`HP: [${'█'.repeat(repeat.hp)}${' '.repeat(20 - repeat.hp)}]\` **${variety.stats.hp}**
|
||||
\`Attack: [${'█'.repeat(repeat.atk)}${' '.repeat(20 - repeat.atk)}]\` **${variety.stats.atk}**
|
||||
\`Defense: [${'█'.repeat(repeat.def)}${' '.repeat(20 - repeat.def)}]\` **${variety.stats.def}**
|
||||
\`Sp. Attack: [${'█'.repeat(repeat.sAtk)}${' '.repeat(20 - repeat.sAtk)}]\` **${variety.stats.sAtk}**
|
||||
\`Sp. Defense: [${'█'.repeat(repeat.sDef)}${' '.repeat(20 - repeat.sDef)}]\` **${variety.stats.sDef}**
|
||||
\`Speed: [${'█'.repeat(repeat.spd)}${' '.repeat(20 - repeat.spd)}]\` **${variety.stats.spd}**
|
||||
\`-----------------------------------\`
|
||||
\`Total: [${'█'.repeat(repeat.total)}${' '.repeat(20 - repeat.total)}]\` **${statTotal}**
|
||||
`)
|
||||
.addField('❯ Abilities', variety.abilities.map(ability => ability.name).join('/'))
|
||||
.addField('❯ Other Forms', stripIndents`
|
||||
_Use ${this.usage(`${pokemon.id} <form>`)} to get stats for another form._
|
||||
|
||||
**Forms Available:** ${displayForms.map(vrity => `\`${vrity.name || 'Normal'}\``).join(', ')}
|
||||
`);
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
if (!pokemon.gameDataCached) await pokemon.fetchGameData();
|
||||
const displayForms = pokemon.varieties.filter(vrity => vrity.statsDiffer);
|
||||
const variety = displayForms.find(vrity => {
|
||||
if (!form || form === 'normal') return vrity.default;
|
||||
if (!vrity.name) return false;
|
||||
return vrity.name.toLowerCase() === form;
|
||||
});
|
||||
if (!variety) {
|
||||
const varieties = displayForms.map(vrity => vrity.name || 'Normal');
|
||||
return msg.say(`Invalid form. The forms available for this Pokémon are: ${list(varieties, 'and')}`);
|
||||
}
|
||||
const statTotal = pokemon.baseStatTotal(variety.id);
|
||||
const repeat = {
|
||||
hp: Math.round((variety.stats.hp / 255) * 10) * 2,
|
||||
atk: Math.round((variety.stats.atk / 255) * 10) * 2,
|
||||
def: Math.round((variety.stats.def / 255) * 10) * 2,
|
||||
sAtk: Math.round((variety.stats.sAtk / 255) * 10) * 2,
|
||||
sDef: Math.round((variety.stats.sDef / 255) * 10) * 2,
|
||||
spd: Math.round((variety.stats.spd / 255) * 10) * 2,
|
||||
total: Math.round((statTotal / 1125) * 10) * 2
|
||||
};
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(
|
||||
`#${pokemon.displayID} - ${pokemon.name}`,
|
||||
'attachment://box.png',
|
||||
pokemon.serebiiURL
|
||||
)
|
||||
.setThumbnail(pokemon.formSpriteImageURL(variety.id))
|
||||
.addField(`❯ Base Stats (${variety.name || 'Normal'} Form)`, stripIndents`
|
||||
\`HP: [${'█'.repeat(repeat.hp)}${' '.repeat(20 - repeat.hp)}]\` **${variety.stats.hp}**
|
||||
\`Attack: [${'█'.repeat(repeat.atk)}${' '.repeat(20 - repeat.atk)}]\` **${variety.stats.atk}**
|
||||
\`Defense: [${'█'.repeat(repeat.def)}${' '.repeat(20 - repeat.def)}]\` **${variety.stats.def}**
|
||||
\`Sp. Attack: [${'█'.repeat(repeat.sAtk)}${' '.repeat(20 - repeat.sAtk)}]\` **${variety.stats.sAtk}**
|
||||
\`Sp. Defense: [${'█'.repeat(repeat.sDef)}${' '.repeat(20 - repeat.sDef)}]\` **${variety.stats.sDef}**
|
||||
\`Speed: [${'█'.repeat(repeat.spd)}${' '.repeat(20 - repeat.spd)}]\` **${variety.stats.spd}**
|
||||
\`-----------------------------------\`
|
||||
\`Total: [${'█'.repeat(repeat.total)}${' '.repeat(20 - repeat.total)}]\` **${statTotal}**
|
||||
`)
|
||||
.addField('❯ Abilities', variety.abilities.map(ability => ability.name).join('/'))
|
||||
.addField('❯ Other Forms', stripIndents`
|
||||
_Use ${this.usage(`${pokemon.id} <form>`)} to get stats for another form._
|
||||
|
||||
**Forms Available:** ${displayForms.map(vrity => `\`${vrity.name || 'Normal'}\``).join(', ')}
|
||||
`);
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
+54
-58
@@ -76,66 +76,62 @@ module.exports = class PokedexCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { pokemon }) {
|
||||
try {
|
||||
if (!pokemon.gameDataCached) await pokemon.fetchGameData();
|
||||
const defaultVariety = pokemon.varieties.find(variety => variety.default);
|
||||
const typesShown = pokemon.varieties.filter(variety => {
|
||||
if (variety.default) return true;
|
||||
return !arrayEquals(defaultVariety.types, variety.types);
|
||||
});
|
||||
const feet = Math.floor(pokemon.height / 12);
|
||||
const evoChain = pokemon.chain.data.map(pkmn => {
|
||||
if (Array.isArray(pkmn)) {
|
||||
return pkmn.map(pkmn2 => {
|
||||
const found = this.client.pokemon.get(pkmn2);
|
||||
if (found.id === pokemon.id) return `**${found.name}**`;
|
||||
return found.name;
|
||||
}).join('/');
|
||||
}
|
||||
const found = this.client.pokemon.get(pkmn);
|
||||
if (found.id === pokemon.id) return `**${found.name}**`;
|
||||
return found.name;
|
||||
}).join(' -> ');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(`#${pokemon.displayID} - ${pokemon.name}`, 'attachment://box.png', pokemon.serebiiURL)
|
||||
.setDescription(stripIndents`
|
||||
**${pokemon.genus}**
|
||||
${pokemon.entries.length ? pokemon.entries[Math.floor(Math.random() * pokemon.entries.length)] : 'No data.'}
|
||||
`)
|
||||
.setThumbnail(pokemon.spriteImageURL)
|
||||
.addField('❯ Introduced In', games[genGames[pokemon.generation]], true)
|
||||
.addField('❯ Height', `${feet}'${Math.floor(pokemon.height) - (feet * 12)}"`, true)
|
||||
.addField('❯ Weight', `${pokemon.weight} lbs.`, true)
|
||||
.addField('❯ Types', typesShown.map(variety => {
|
||||
const showParens = variety.name && typesShown.length > 1;
|
||||
return `${variety.types.join('/')}${showParens ? ` (${variety.name})` : ''}`;
|
||||
}).join('\n'), true)
|
||||
.addField('❯ Class', firstUpperCase(pokemon.class), true)
|
||||
.addField('❯ Gender Rate', pokemon.genderRate.genderless
|
||||
? 'Genderless'
|
||||
: `♂️ ${pokemon.genderRate.male}% ♀️ ${pokemon.genderRate.female}%`, true)
|
||||
.addField('❯ Evolution Chain', `${evoChain}${pokemon.mega ? ` -> ${this.megaEvolveEmoji}` : ''}`)
|
||||
.addField('❯ Held Items', pokemon.heldItems.length
|
||||
? pokemon.heldItems.map(item => `${item.data.name} (${item.rarity}%)`).join('\n')
|
||||
: 'None');
|
||||
if (msg.guild && pokemon.cry) {
|
||||
const connection = msg.guild ? this.client.dispatchers.get(msg.guild.id) : null;
|
||||
if (connection) {
|
||||
connection.play(pokemon.cry);
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
}
|
||||
if (!pokemon.gameDataCached) await pokemon.fetchGameData();
|
||||
const defaultVariety = pokemon.varieties.find(variety => variety.default);
|
||||
const typesShown = pokemon.varieties.filter(variety => {
|
||||
if (variety.default) return true;
|
||||
return !arrayEquals(defaultVariety.types, variety.types);
|
||||
});
|
||||
const feet = Math.floor(pokemon.height / 12);
|
||||
const evoChain = pokemon.chain.data.map(pkmn => {
|
||||
if (Array.isArray(pkmn)) {
|
||||
return pkmn.map(pkmn2 => {
|
||||
const found = this.client.pokemon.get(pkmn2);
|
||||
if (found.id === pokemon.id) return `**${found.name}**`;
|
||||
return found.name;
|
||||
}).join('/');
|
||||
}
|
||||
const found = this.client.pokemon.get(pkmn);
|
||||
if (found.id === pokemon.id) return `**${found.name}**`;
|
||||
return found.name;
|
||||
}).join(' -> ');
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(`#${pokemon.displayID} - ${pokemon.name}`, 'attachment://box.png', pokemon.serebiiURL)
|
||||
.setDescription(stripIndents`
|
||||
**${pokemon.genus}**
|
||||
${pokemon.entries.length ? pokemon.entries[Math.floor(Math.random() * pokemon.entries.length)] : 'No data.'}
|
||||
`)
|
||||
.setThumbnail(pokemon.spriteImageURL)
|
||||
.addField('❯ Introduced In', games[genGames[pokemon.generation]], true)
|
||||
.addField('❯ Height', `${feet}'${Math.floor(pokemon.height) - (feet * 12)}"`, true)
|
||||
.addField('❯ Weight', `${pokemon.weight} lbs.`, true)
|
||||
.addField('❯ Types', typesShown.map(variety => {
|
||||
const showParens = variety.name && typesShown.length > 1;
|
||||
return `${variety.types.join('/')}${showParens ? ` (${variety.name})` : ''}`;
|
||||
}).join('\n'), true)
|
||||
.addField('❯ Class', firstUpperCase(pokemon.class), true)
|
||||
.addField('❯ Gender Rate', pokemon.genderRate.genderless
|
||||
? 'Genderless'
|
||||
: `♂️ ${pokemon.genderRate.male}% ♀️ ${pokemon.genderRate.female}%`, true)
|
||||
.addField('❯ Evolution Chain', `${evoChain}${pokemon.mega ? ` -> ${this.megaEvolveEmoji}` : ''}`)
|
||||
.addField('❯ Held Items', pokemon.heldItems.length
|
||||
? pokemon.heldItems.map(item => `${item.data.name} (${item.rarity}%)`).join('\n')
|
||||
: 'None');
|
||||
if (msg.guild && pokemon.cry) {
|
||||
const connection = msg.guild ? this.client.dispatchers.get(msg.guild.id) : null;
|
||||
if (connection) {
|
||||
connection.play(pokemon.cry);
|
||||
await reactIfAble(msg, this.client.user, '🔉');
|
||||
}
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
get megaEvolveEmoji() {
|
||||
|
||||
+20
-25
@@ -60,31 +60,26 @@ module.exports = class SmogonCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { pokemon }) {
|
||||
try {
|
||||
const fetchGames = genGames.slice(pokemon.generation, pokemon.missingno ? 2 : genGames.length);
|
||||
if (!pokemon.missingno) await pokemon.fetchSmogonTiers(...fetchGames);
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(`#${pokemon.displayID} - ${pokemon.name}`, 'attachment://box.png', pokemon.serebiiURL)
|
||||
.setThumbnail(pokemon.spriteImageURL);
|
||||
for (const game of fetchGames) {
|
||||
embed.addField(`❯ ${games[game]}`,
|
||||
`[${pokemon.smogonTiers[game].join('/')}](${pokemon.smogonURL(game)})`, true);
|
||||
}
|
||||
if (fetchGames.length % 3 !== 0 && fetchGames.length > 3) {
|
||||
for (let i = 0; i < 3 - (fetchGames.length % 3); i++) {
|
||||
embed.addField('\u200B', '\u200B', true);
|
||||
}
|
||||
}
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
const fetchGames = genGames.slice(pokemon.generation, pokemon.missingno ? 2 : genGames.length);
|
||||
if (!pokemon.missingno) await pokemon.fetchSmogonTiers(...fetchGames);
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0xED1C24)
|
||||
.setAuthor(`#${pokemon.displayID} - ${pokemon.name}`, 'attachment://box.png', pokemon.serebiiURL)
|
||||
.setThumbnail(pokemon.spriteImageURL);
|
||||
for (const game of fetchGames) {
|
||||
embed.addField(`❯ ${games[game]}`, `[${pokemon.smogonTiers[game].join('/')}](${pokemon.smogonURL(game)})`, true);
|
||||
}
|
||||
if (fetchGames.length % 3 !== 0 && fetchGames.length > 3) {
|
||||
for (let i = 0; i < 3 - (fetchGames.length % 3); i++) {
|
||||
embed.addField('\u200B', '\u200B', true);
|
||||
}
|
||||
}
|
||||
return msg.channel.send({
|
||||
embeds: [embed],
|
||||
files: [{
|
||||
attachment: await pokemon.generateBoxImage(),
|
||||
name: 'box.png'
|
||||
}]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,17 +21,13 @@ module.exports = class BirdCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request
|
||||
.get('https://shibe.online/api/birds')
|
||||
.query({
|
||||
count: 1,
|
||||
urls: true,
|
||||
httpsUrls: true
|
||||
});
|
||||
return msg.say({ files: [body[0]] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request
|
||||
.get('https://shibe.online/api/birds')
|
||||
.query({
|
||||
count: 1,
|
||||
urls: true,
|
||||
httpsUrls: true
|
||||
});
|
||||
return msg.say({ files: [body[0]] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,25 +22,21 @@ module.exports = class BunnyCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request
|
||||
.get('https://api.bunnies.io/v2/loop/random/')
|
||||
.query({ media: 'gif,png' });
|
||||
let fileToSend;
|
||||
let fileType = 'gif';
|
||||
const gif = await request.get(body.media.gif);
|
||||
if (Buffer.byteLength(gif.body) > 8e+6) {
|
||||
const poster = await request.get(body.media.poster);
|
||||
fileToSend = poster.body;
|
||||
fileType = 'png';
|
||||
} else {
|
||||
fileToSend = gif.body;
|
||||
}
|
||||
return msg.say(facts[Math.floor(Math.random() * facts.length)], {
|
||||
files: [{ attachment: fileToSend, name: `${body.id}.${fileType}` }]
|
||||
});
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
const { body } = await request
|
||||
.get('https://api.bunnies.io/v2/loop/random/')
|
||||
.query({ media: 'gif,png' });
|
||||
let fileToSend;
|
||||
let fileType = 'gif';
|
||||
const gif = await request.get(body.media.gif);
|
||||
if (Buffer.byteLength(gif.body) > 8e+6) {
|
||||
const poster = await request.get(body.media.poster);
|
||||
fileToSend = poster.body;
|
||||
fileType = 'png';
|
||||
} else {
|
||||
fileToSend = gif.body;
|
||||
}
|
||||
return msg.say(facts[Math.floor(Math.random() * facts.length)], {
|
||||
files: [{ attachment: fileToSend, name: `${body.id}.${fileType}` }]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,14 +24,10 @@ module.exports = class CatCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request
|
||||
.get('https://api.thecatapi.com/v1/images/search')
|
||||
.query({ limit: 1 })
|
||||
.set({ 'x-api-key': THECATAPI_KEY });
|
||||
return msg.say(facts[Math.floor(Math.random() * facts.length)], { files: [body[0].url] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request
|
||||
.get('https://api.thecatapi.com/v1/images/search')
|
||||
.query({ limit: 1 })
|
||||
.set({ 'x-api-key': THECATAPI_KEY });
|
||||
return msg.say(facts[Math.floor(Math.random() * facts.length)], { files: [body[0].url] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,14 +24,10 @@ module.exports = class DogCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request
|
||||
.get('https://api.thedogapi.com/v1/images/search')
|
||||
.query({ limit: 1 })
|
||||
.set({ 'x-api-key': THEDOGAPI_KEY });
|
||||
return msg.say(facts[Math.floor(Math.random() * facts.length)], { files: [body[0].url] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request
|
||||
.get('https://api.thedogapi.com/v1/images/search')
|
||||
.query({ limit: 1 })
|
||||
.set({ 'x-api-key': THEDOGAPI_KEY });
|
||||
return msg.say(facts[Math.floor(Math.random() * facts.length)], { files: [body[0].url] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,11 +22,7 @@ module.exports = class DuckCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request.get('https://random-d.uk/api/v1/random');
|
||||
return msg.say({ files: [body.url] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request.get('https://random-d.uk/api/v1/random');
|
||||
return msg.say({ files: [body.url] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,11 +20,7 @@ module.exports = class FoxCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request.get('https://randomfox.ca/floof/');
|
||||
return msg.say({ files: [body.image] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request.get('https://randomfox.ca/floof/');
|
||||
return msg.say({ files: [body.image] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,11 +21,7 @@ module.exports = class GooseCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request.get('https://nekos.life/api/v2/img/goose');
|
||||
return msg.say({ files: [body.url] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request.get('https://nekos.life/api/v2/img/goose');
|
||||
return msg.say({ files: [body.url] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,13 +21,9 @@ module.exports = class InspirationCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { text } = await request
|
||||
.get('https://inspirobot.me/api')
|
||||
.query({ generate: true });
|
||||
return msg.say({ files: [text] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { text } = await request
|
||||
.get('https://inspirobot.me/api')
|
||||
.query({ generate: true });
|
||||
return msg.say({ files: [text] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,15 +22,11 @@ module.exports = class LightNovelCoverCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { text } = await request.get('https://salty-salty-studios.com/shiz/lncovers.php');
|
||||
const $ = cheerio.load(text);
|
||||
const cover = $('img').first();
|
||||
return msg.say(cover.attr('alt'), {
|
||||
files: [`https://salty-salty-studios.com/shiz/${cover.attr('src')}`]
|
||||
});
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { text } = await request.get('https://salty-salty-studios.com/shiz/lncovers.php');
|
||||
const $ = cheerio.load(text);
|
||||
const cover = $('img').first();
|
||||
return msg.say(cover.attr('alt'), {
|
||||
files: [`https://salty-salty-studios.com/shiz/${cover.attr('src')}`]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,11 +20,7 @@ module.exports = class LizardCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request.get('https://nekos.life/api/v2/img/lizard');
|
||||
return msg.say({ files: [body.url] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request.get('https://nekos.life/api/v2/img/lizard');
|
||||
return msg.say({ files: [body.url] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,11 +42,7 @@ module.exports = class LoremPicsumCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { width, height, seed }) {
|
||||
try {
|
||||
const { body } = await request.get(`https://picsum.photos/${seed ? `seed/${seed}/` : ''}${width}/${height}`);
|
||||
return msg.say({ files: [{ attachment: body, name: `${width}x${height}.jpg` }] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request.get(`https://picsum.photos/${seed ? `seed/${seed}/` : ''}${width}/${height}`);
|
||||
return msg.say({ files: [{ attachment: body, name: `${width}x${height}.jpg` }] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,17 +21,13 @@ module.exports = class ShibaCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request
|
||||
.get('https://shibe.online/api/shibes')
|
||||
.query({
|
||||
count: 1,
|
||||
urls: true,
|
||||
httpsUrls: true
|
||||
});
|
||||
return msg.say({ files: [body[0]] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request
|
||||
.get('https://shibe.online/api/shibes')
|
||||
.query({
|
||||
count: 1,
|
||||
urls: true,
|
||||
httpsUrls: true
|
||||
});
|
||||
return msg.say({ files: [body[0]] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,12 +21,8 @@ module.exports = class AdviceCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { text } = await request.get('http://api.adviceslip.com/advice');
|
||||
const body = JSON.parse(text);
|
||||
return msg.say(`${body.slip.advice} (#${body.slip.id})`);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { text } = await request.get('http://api.adviceslip.com/advice');
|
||||
const body = JSON.parse(text);
|
||||
return msg.say(`${body.slip.advice} (#${body.slip.id})`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,11 +20,7 @@ module.exports = class BoredomCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request.get('https://www.boredapi.com/api/activity/');
|
||||
return msg.say(`${body.activity} (${body.type})`);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request.get('https://www.boredapi.com/api/activity/');
|
||||
return msg.say(`${body.activity} (${body.type})`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -26,11 +26,7 @@ module.exports = class ChuckNorrisCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { body } = await request.get('https://api.chucknorris.io/jokes/random');
|
||||
return msg.say(body.value);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request.get('https://api.chucknorris.io/jokes/random');
|
||||
return msg.say(body.value);
|
||||
}
|
||||
};
|
||||
|
||||
+19
-23
@@ -20,30 +20,26 @@ module.exports = class FactCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const article = await this.randomWikipediaArticle();
|
||||
const { body } = await request
|
||||
.get('https://en.wikipedia.org/w/api.php')
|
||||
.query({
|
||||
action: 'query',
|
||||
prop: 'extracts',
|
||||
format: 'json',
|
||||
titles: article,
|
||||
exintro: '',
|
||||
explaintext: '',
|
||||
redirects: '',
|
||||
formatversion: 2
|
||||
});
|
||||
let fact = body.query.pages[0].extract;
|
||||
if (fact.length > 200) {
|
||||
const facts = fact.split('.');
|
||||
fact = `${facts[0]}.`;
|
||||
if (fact.length < 200 && facts.length > 1) fact += `${facts[1]}.`;
|
||||
}
|
||||
return msg.say(fact);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
const article = await this.randomWikipediaArticle();
|
||||
const { body } = await request
|
||||
.get('https://en.wikipedia.org/w/api.php')
|
||||
.query({
|
||||
action: 'query',
|
||||
prop: 'extracts',
|
||||
format: 'json',
|
||||
titles: article,
|
||||
exintro: '',
|
||||
explaintext: '',
|
||||
redirects: '',
|
||||
formatversion: 2
|
||||
});
|
||||
let fact = body.query.pages[0].extract;
|
||||
if (fact.length > 200) {
|
||||
const facts = fact.split('.');
|
||||
fact = `${facts[0]}.`;
|
||||
if (fact.length < 200 && facts.length > 1) fact += `${facts[1]}.`;
|
||||
}
|
||||
return msg.say(fact);
|
||||
}
|
||||
|
||||
async randomWikipediaArticle() {
|
||||
|
||||
@@ -22,13 +22,9 @@ module.exports = class FmlCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { text } = await request.get('http://www.fmylife.com/random');
|
||||
const $ = cheerio.load(text, { normalizeWhitespace: true });
|
||||
const fml = $('a.block').first().text().trim();
|
||||
return msg.say(fml);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { text } = await request.get('http://www.fmylife.com/random');
|
||||
const $ = cheerio.load(text, { normalizeWhitespace: true });
|
||||
const fml = $('a.block').first().text().trim();
|
||||
return msg.say(fml);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,11 +21,7 @@ module.exports = class GithubZenCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { text } = await request.get('https://api.github.com/zen');
|
||||
return msg.say(text);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { text } = await request.get('https://api.github.com/zen');
|
||||
return msg.say(text);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,19 +23,15 @@ module.exports = class JokeCommand extends Command {
|
||||
|
||||
async run(msg) {
|
||||
const blacklist = msg.channel.nsfw ? blacklistFlags : blacklistFlags.concat(nsfw);
|
||||
try {
|
||||
const { body } = await request
|
||||
.get('https://v2.jokeapi.dev/joke/Any')
|
||||
.query({ blacklistFlags: blacklist.join(',') });
|
||||
if (body.type === 'twopart') {
|
||||
return msg.say(stripIndents`
|
||||
${body.setup}
|
||||
${body.delivery}
|
||||
`);
|
||||
}
|
||||
return msg.say(body.joke);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
const { body } = await request
|
||||
.get('https://v2.jokeapi.dev/joke/Any')
|
||||
.query({ blacklistFlags: blacklist.join(',') });
|
||||
if (body.type === 'twopart') {
|
||||
return msg.say(stripIndents`
|
||||
${body.setup}
|
||||
${body.delivery}
|
||||
`);
|
||||
}
|
||||
return msg.say(body.joke);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,11 +20,7 @@ module.exports = class LightNovelTitleCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { text } = await request.get('https://salty-salty-studios.com/shiz/ln.php');
|
||||
return msg.say(text.match(/<h1>(.+)<\/h1>/i)[1]);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { text } = await request.get('https://salty-salty-studios.com/shiz/ln.php');
|
||||
return msg.say(text.match(/<h1>(.+)<\/h1>/i)[1]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,11 +21,7 @@ module.exports = class MtgCardCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const { url } = await request.get('https://scryfall.com/random?q=is%3Aspell+game%3Apaper');
|
||||
return msg.say(url);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { url } = await request.get('https://scryfall.com/random?q=is%3Aspell+game%3Apaper');
|
||||
return msg.say(url);
|
||||
}
|
||||
};
|
||||
|
||||
+10
-14
@@ -30,19 +30,15 @@ module.exports = class NameCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { gender }) {
|
||||
try {
|
||||
const { body } = await request
|
||||
.get('https://randomuser.me/api/')
|
||||
.query({
|
||||
inc: 'name',
|
||||
noinfo: '',
|
||||
gender: gender === 'both' ? '' : gender,
|
||||
nat: 'AU,US,CA,GB'
|
||||
});
|
||||
const data = body.results[0].name;
|
||||
return msg.say(`${data.first} ${data.last}`);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request
|
||||
.get('https://randomuser.me/api/')
|
||||
.query({
|
||||
inc: 'name',
|
||||
noinfo: '',
|
||||
gender: gender === 'both' ? '' : gender,
|
||||
nat: 'AU,US,CA,GB'
|
||||
});
|
||||
const data = body.results[0].name;
|
||||
return msg.say(`${data.first} ${data.last}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ module.exports = class NumberFactCommand extends Command {
|
||||
return msg.say(text);
|
||||
} catch (err) {
|
||||
if (err.status === 404) return msg.say('Could not find any results.');
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,19 +23,15 @@ module.exports = class PunCommand extends Command {
|
||||
|
||||
async run(msg) {
|
||||
const blacklist = msg.channel.nsfw ? blacklistFlags : blacklistFlags.concat(nsfw);
|
||||
try {
|
||||
const { body } = await request
|
||||
.get('https://v2.jokeapi.dev/joke/Pun')
|
||||
.query({ blacklistFlags: blacklist.join(',') });
|
||||
if (body.type === 'twopart') {
|
||||
return msg.say(stripIndents`
|
||||
${body.setup}
|
||||
${body.delivery}
|
||||
`);
|
||||
}
|
||||
return msg.say(body.joke);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
const { body } = await request
|
||||
.get('https://v2.jokeapi.dev/joke/Pun')
|
||||
.query({ blacklistFlags: blacklist.join(',') });
|
||||
if (body.type === 'twopart') {
|
||||
return msg.say(stripIndents`
|
||||
${body.setup}
|
||||
${body.delivery}
|
||||
`);
|
||||
}
|
||||
return msg.say(body.joke);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -26,16 +26,12 @@ module.exports = class SuperpowerCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
try {
|
||||
const id = await this.random();
|
||||
const article = await this.fetchSuperpower(id);
|
||||
return msg.reply(stripIndents`
|
||||
Your superpower is... **${article.title}**!
|
||||
_${article.abstract.split('1')[0].trim()}_
|
||||
`);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const id = await this.random();
|
||||
const article = await this.fetchSuperpower(id);
|
||||
return msg.reply(stripIndents`
|
||||
Your superpower is... **${article.title}**!
|
||||
_${article.abstract.split('1')[0].trim()}_
|
||||
`);
|
||||
}
|
||||
|
||||
async random() {
|
||||
|
||||
@@ -65,35 +65,31 @@ module.exports = class FriendshipCommand extends Command {
|
||||
}
|
||||
const firstAvatarURL = first.displayAvatarURL({ format: 'png', size: 512 });
|
||||
const secondAvatarURL = second.displayAvatarURL({ format: 'png', size: 512 });
|
||||
try {
|
||||
const firstAvatarData = await request.get(firstAvatarURL);
|
||||
const firstAvatar = await loadImage(firstAvatarData.body);
|
||||
const secondAvatarData = await request.get(secondAvatarURL);
|
||||
const secondAvatar = await loadImage(secondAvatarData.body);
|
||||
const base = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'friendship.png'));
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(firstAvatar, 70, 56, 400, 400);
|
||||
ctx.drawImage(secondAvatar, 730, 56, 400, 400);
|
||||
ctx.drawImage(base, 0, 0);
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.fillStyle = 'green';
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(40);
|
||||
ctx.fillText('~Xiao\'s Friendship Meter~', 600, 15);
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillText(first.username, 270, 448);
|
||||
ctx.fillText(second.username, 930, 448);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(60);
|
||||
ctx.fillStyle = percentColor(level / 100, percentColors);
|
||||
ctx.fillText(`~${level}%~`, 600, 230);
|
||||
ctx.fillText(this.calculateLevelText(level, self, owner, authorUser, botUser), 600, 296);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(90);
|
||||
ctx.fillText(level > 49 ? '👍' : '👎', 600, 100);
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'friendship.png' }] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const firstAvatarData = await request.get(firstAvatarURL);
|
||||
const firstAvatar = await loadImage(firstAvatarData.body);
|
||||
const secondAvatarData = await request.get(secondAvatarURL);
|
||||
const secondAvatar = await loadImage(secondAvatarData.body);
|
||||
const base = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'friendship.png'));
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(firstAvatar, 70, 56, 400, 400);
|
||||
ctx.drawImage(secondAvatar, 730, 56, 400, 400);
|
||||
ctx.drawImage(base, 0, 0);
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.fillStyle = 'green';
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(40);
|
||||
ctx.fillText('~Xiao\'s Friendship Meter~', 600, 15);
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillText(first.username, 270, 448);
|
||||
ctx.fillText(second.username, 930, 448);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(60);
|
||||
ctx.fillStyle = percentColor(level / 100, percentColors);
|
||||
ctx.fillText(`~${level}%~`, 600, 230);
|
||||
ctx.fillText(this.calculateLevelText(level, self, owner, authorUser, botUser), 600, 296);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(90);
|
||||
ctx.fillText(level > 49 ? '👍' : '👎', 600, 100);
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'friendship.png' }] });
|
||||
}
|
||||
|
||||
calculateLevelText(level, self, owner, authorUser, botUser) {
|
||||
|
||||
@@ -68,35 +68,31 @@ module.exports = class ShipCommand extends Command {
|
||||
}
|
||||
const firstAvatarURL = first.displayAvatarURL({ format: 'png', size: 512 });
|
||||
const secondAvatarURL = second.displayAvatarURL({ format: 'png', size: 512 });
|
||||
try {
|
||||
const firstAvatarData = await request.get(firstAvatarURL);
|
||||
const firstAvatar = await loadImage(firstAvatarData.body);
|
||||
const secondAvatarData = await request.get(secondAvatarURL);
|
||||
const secondAvatar = await loadImage(secondAvatarData.body);
|
||||
const base = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'ship.png'));
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(firstAvatar, 70, 56, 400, 400);
|
||||
ctx.drawImage(secondAvatar, 730, 56, 400, 400);
|
||||
ctx.drawImage(base, 0, 0);
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.fillStyle = '#ff6c6c';
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(40);
|
||||
ctx.fillText('~Xiao\'s Compatability Meter~', 600, 15);
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillText(first.username, 270, 448);
|
||||
ctx.fillText(second.username, 930, 448);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(60);
|
||||
ctx.fillStyle = percentColor(level / 100, percentColors);
|
||||
ctx.fillText(`~${level}%~`, 600, 230);
|
||||
ctx.fillText(this.calculateLevelText(level, self, owner, authorUser, botUser), 600, 296);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(90);
|
||||
ctx.fillText(level > 49 ? '❤️' : '💔', 600, 100);
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'ship.png' }] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const firstAvatarData = await request.get(firstAvatarURL);
|
||||
const firstAvatar = await loadImage(firstAvatarData.body);
|
||||
const secondAvatarData = await request.get(secondAvatarURL);
|
||||
const secondAvatar = await loadImage(secondAvatarData.body);
|
||||
const base = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'ship.png'));
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(firstAvatar, 70, 56, 400, 400);
|
||||
ctx.drawImage(secondAvatar, 730, 56, 400, 400);
|
||||
ctx.drawImage(base, 0, 0);
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.fillStyle = '#ff6c6c';
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(40);
|
||||
ctx.fillText('~Xiao\'s Compatability Meter~', 600, 15);
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillText(first.username, 270, 448);
|
||||
ctx.fillText(second.username, 930, 448);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(60);
|
||||
ctx.fillStyle = percentColor(level / 100, percentColors);
|
||||
ctx.fillText(`~${level}%~`, 600, 230);
|
||||
ctx.fillText(this.calculateLevelText(level, self, owner, authorUser, botUser), 600, 296);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(90);
|
||||
ctx.fillText(level > 49 ? '❤️' : '💔', 600, 100);
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'ship.png' }] });
|
||||
}
|
||||
|
||||
calculateLevelText(level, self, owner, authorUser, botUser) {
|
||||
|
||||
@@ -62,35 +62,31 @@ module.exports = class ThinkOfCommand extends Command {
|
||||
}
|
||||
const firstAvatarURL = first.displayAvatarURL({ format: 'png', size: 512 });
|
||||
const secondAvatarURL = second.displayAvatarURL({ format: 'png', size: 512 });
|
||||
try {
|
||||
const firstAvatarData = await request.get(firstAvatarURL);
|
||||
const firstAvatar = await loadImage(firstAvatarData.body);
|
||||
const secondAvatarData = await request.get(secondAvatarURL);
|
||||
const secondAvatar = await loadImage(secondAvatarData.body);
|
||||
const base = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'friendship.png'));
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(firstAvatar, 70, 56, 400, 400);
|
||||
ctx.drawImage(secondAvatar, 730, 56, 400, 400);
|
||||
ctx.drawImage(base, 0, 0);
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.fillStyle = 'green';
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(40);
|
||||
ctx.fillText('~Xiao\'s Thought Reader~', 600, 15);
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillText(first.username, 270, 448);
|
||||
ctx.fillText(second.username, 930, 448);
|
||||
ctx.fillStyle = thought.color;
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(40);
|
||||
ctx.fillText('thinks they are', 600, 230);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(60);
|
||||
ctx.fillText(thought.text, 600, 296);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(90);
|
||||
ctx.fillText(thought.emoji, 600, 100);
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'think-of.png' }] });
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const firstAvatarData = await request.get(firstAvatarURL);
|
||||
const firstAvatar = await loadImage(firstAvatarData.body);
|
||||
const secondAvatarData = await request.get(secondAvatarURL);
|
||||
const secondAvatar = await loadImage(secondAvatarData.body);
|
||||
const base = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'friendship.png'));
|
||||
const canvas = createCanvas(base.width, base.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(firstAvatar, 70, 56, 400, 400);
|
||||
ctx.drawImage(secondAvatar, 730, 56, 400, 400);
|
||||
ctx.drawImage(base, 0, 0);
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.fillStyle = 'green';
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(40);
|
||||
ctx.fillText('~Xiao\'s Thought Reader~', 600, 15);
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillText(first.username, 270, 448);
|
||||
ctx.fillText(second.username, 930, 448);
|
||||
ctx.fillStyle = thought.color;
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(40);
|
||||
ctx.fillText('thinks they are', 600, 230);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(60);
|
||||
ctx.fillText(thought.text, 600, 296);
|
||||
ctx.font = this.client.fonts.get('Pinky Cupid.otf').toCanvasString(90);
|
||||
ctx.fillText(thought.emoji, 600, 100);
|
||||
return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'think-of.png' }] });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -39,15 +39,11 @@ module.exports = class AnilistCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { query }) {
|
||||
try {
|
||||
const data = await this.search(query);
|
||||
if (!data || !data.id || !data.name) return msg.say('Could not find any results.');
|
||||
return msg.say(`<https://anilist.co/user/${data.name}>`, {
|
||||
files: [{ attachment: `https://img.anili.st/user/${data.id}`, name: 'anilist.png' }]
|
||||
});
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const data = await this.search(query);
|
||||
if (!data || !data.id || !data.name) return msg.say('Could not find any results.');
|
||||
return msg.say(`<https://anilist.co/user/${data.name}>`, {
|
||||
files: [{ attachment: `https://img.anili.st/user/${data.id}`, name: 'anilist.png' }]
|
||||
});
|
||||
}
|
||||
|
||||
async search(query) {
|
||||
|
||||
@@ -71,25 +71,21 @@ module.exports = class AnimeCharacterCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { query }) {
|
||||
try {
|
||||
const id = await this.search(query);
|
||||
if (!id) return msg.say('Could not find any results.');
|
||||
const character = await this.fetchCharacter(id);
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0x02A9FF)
|
||||
.setAuthor('AniList', 'https://i.imgur.com/iUIRC7v.png', 'https://anilist.co/')
|
||||
.setURL(character.siteUrl)
|
||||
.setThumbnail(character.image.large || character.image.medium || null)
|
||||
.setTitle(`${character.name.first || ''}${character.name.last ? ` ${character.name.last}` : ''}`)
|
||||
.setDescription(character.description ? cleanAnilistHTML(character.description, false) : 'No description.')
|
||||
.addField('❯ Appearances', trimArray(character.media.edges.map(edge => {
|
||||
const title = edge.node.title.english || edge.node.title.romaji;
|
||||
return embedURL(`${title} (${types[edge.node.type]})`, edge.node.siteUrl);
|
||||
}), 5).join(', '));
|
||||
return msg.embed(embed);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const id = await this.search(query);
|
||||
if (!id) return msg.say('Could not find any results.');
|
||||
const character = await this.fetchCharacter(id);
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0x02A9FF)
|
||||
.setAuthor('AniList', 'https://i.imgur.com/iUIRC7v.png', 'https://anilist.co/')
|
||||
.setURL(character.siteUrl)
|
||||
.setThumbnail(character.image.large || character.image.medium || null)
|
||||
.setTitle(`${character.name.first || ''}${character.name.last ? ` ${character.name.last}` : ''}`)
|
||||
.setDescription(character.description ? cleanAnilistHTML(character.description, false) : 'No description.')
|
||||
.addField('❯ Appearances', trimArray(character.media.edges.map(edge => {
|
||||
const title = edge.node.title.english || edge.node.title.romaji;
|
||||
return embedURL(`${title} (${types[edge.node.type]})`, edge.node.siteUrl);
|
||||
}), 5).join(', '));
|
||||
return msg.embed(embed);
|
||||
}
|
||||
|
||||
async search(query) {
|
||||
|
||||
@@ -91,31 +91,27 @@ module.exports = class AnimeStaffCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { query }) {
|
||||
try {
|
||||
const id = await this.search(query);
|
||||
if (!id) return msg.say('Could not find any results.');
|
||||
const staff = await this.fetchStaff(id);
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0x02A9FF)
|
||||
.setAuthor('AniList', 'https://i.imgur.com/iUIRC7v.png', 'https://anilist.co/')
|
||||
.setURL(staff.siteUrl)
|
||||
.setThumbnail(staff.image.large || staff.image.medium || null)
|
||||
.setTitle(`${staff.name.first || ''}${staff.name.last ? ` ${staff.name.last}` : ''}`)
|
||||
.setDescription(staff.description ? cleanAnilistHTML(staff.description, false) : 'No description.')
|
||||
.addField('❯ Voice Roles',
|
||||
staff.characterMedia.edges.length ? trimArray(staff.characterMedia.edges.map(edge => {
|
||||
const title = edge.node.title.english || edge.node.title.romaji;
|
||||
return embedURL(`${title} (${roles[edge.characterRole]})`, edge.node.siteUrl);
|
||||
}), 5).join(', ') : 'None')
|
||||
.addField('❯ Production Roles',
|
||||
staff.staffMedia.edges.length ? trimArray(staff.staffMedia.edges.map(edge => {
|
||||
const title = edge.node.title.english || edge.node.title.romaji;
|
||||
return embedURL(`${title} (${types[edge.node.type]})`, edge.node.siteUrl);
|
||||
}), 5).join(', ') : 'None');
|
||||
return msg.embed(embed);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const id = await this.search(query);
|
||||
if (!id) return msg.say('Could not find any results.');
|
||||
const staff = await this.fetchStaff(id);
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0x02A9FF)
|
||||
.setAuthor('AniList', 'https://i.imgur.com/iUIRC7v.png', 'https://anilist.co/')
|
||||
.setURL(staff.siteUrl)
|
||||
.setThumbnail(staff.image.large || staff.image.medium || null)
|
||||
.setTitle(`${staff.name.first || ''}${staff.name.last ? ` ${staff.name.last}` : ''}`)
|
||||
.setDescription(staff.description ? cleanAnilistHTML(staff.description, false) : 'No description.')
|
||||
.addField('❯ Voice Roles',
|
||||
staff.characterMedia.edges.length ? trimArray(staff.characterMedia.edges.map(edge => {
|
||||
const title = edge.node.title.english || edge.node.title.romaji;
|
||||
return embedURL(`${title} (${roles[edge.characterRole]})`, edge.node.siteUrl);
|
||||
}), 5).join(', ') : 'None')
|
||||
.addField('❯ Production Roles',
|
||||
staff.staffMedia.edges.length ? trimArray(staff.staffMedia.edges.map(edge => {
|
||||
const title = edge.node.title.english || edge.node.title.romaji;
|
||||
return embedURL(`${title} (${types[edge.node.type]})`, edge.node.siteUrl);
|
||||
}), 5).join(', ') : 'None');
|
||||
return msg.embed(embed);
|
||||
}
|
||||
|
||||
async search(query) {
|
||||
|
||||
+24
-28
@@ -110,34 +110,30 @@ module.exports = class AnimeCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { query }) {
|
||||
try {
|
||||
const id = await this.search(query);
|
||||
if (!id) return msg.say('Could not find any results.');
|
||||
const anime = await this.fetchAnime(id);
|
||||
if (!this.personalList) await this.fetchPersonalList();
|
||||
const entry = this.personalList.find(ani => ani.mediaId === id);
|
||||
const malScore = await this.fetchMALScore(anime.idMal);
|
||||
const malURL = `https://myanimelist.net/anime/${anime.idMal}`;
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0x02A9FF)
|
||||
.setAuthor('AniList', 'https://i.imgur.com/iUIRC7v.png', 'https://anilist.co/')
|
||||
.setURL(anime.siteUrl)
|
||||
.setThumbnail(anime.coverImage.large || anime.coverImage.medium || null)
|
||||
.setTitle(anime.title.english || anime.title.romaji)
|
||||
.setDescription(anime.description ? cleanAnilistHTML(anime.description) : 'No description.')
|
||||
.addField('❯ Status', statuses[anime.status], true)
|
||||
.addField('❯ Episodes', anime.episodes?.toString() || '???', true)
|
||||
.addField('❯ Season', anime.season ? `${seasons[anime.season]} ${anime.startDate.year}` : '???', true)
|
||||
.addField('❯ Average Score', anime.averageScore ? `${anime.averageScore}%` : '???', true)
|
||||
.addField(`❯ MAL Score`, malScore ? embedURL(malScore, malURL) : '???', true)
|
||||
.addField(`❯ ${ANILIST_USERNAME}'s Score`, entry && entry.score ? `${entry.score}/10` : '???', true)
|
||||
.addField('❯ External Links', anime.externalLinks.length
|
||||
? anime.externalLinks.map(link => `[${link.site}](${link.url})`).join(', ')
|
||||
: 'None');
|
||||
return msg.embed(embed);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const id = await this.search(query);
|
||||
if (!id) return msg.say('Could not find any results.');
|
||||
const anime = await this.fetchAnime(id);
|
||||
if (!this.personalList) await this.fetchPersonalList();
|
||||
const entry = this.personalList.find(ani => ani.mediaId === id);
|
||||
const malScore = await this.fetchMALScore(anime.idMal);
|
||||
const malURL = `https://myanimelist.net/anime/${anime.idMal}`;
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(0x02A9FF)
|
||||
.setAuthor('AniList', 'https://i.imgur.com/iUIRC7v.png', 'https://anilist.co/')
|
||||
.setURL(anime.siteUrl)
|
||||
.setThumbnail(anime.coverImage.large || anime.coverImage.medium || null)
|
||||
.setTitle(anime.title.english || anime.title.romaji)
|
||||
.setDescription(anime.description ? cleanAnilistHTML(anime.description) : 'No description.')
|
||||
.addField('❯ Status', statuses[anime.status], true)
|
||||
.addField('❯ Episodes', anime.episodes?.toString() || '???', true)
|
||||
.addField('❯ Season', anime.season ? `${seasons[anime.season]} ${anime.startDate.year}` : '???', true)
|
||||
.addField('❯ Average Score', anime.averageScore ? `${anime.averageScore}%` : '???', true)
|
||||
.addField(`❯ MAL Score`, malScore ? embedURL(malScore, malURL) : '???', true)
|
||||
.addField(`❯ ${ANILIST_USERNAME}'s Score`, entry && entry.score ? `${entry.score}/10` : '???', true)
|
||||
.addField('❯ External Links', anime.externalLinks.length
|
||||
? anime.externalLinks.map(link => `[${link.site}](${link.url})`).join(', ')
|
||||
: 'None');
|
||||
return msg.embed(embed);
|
||||
}
|
||||
|
||||
async search(query) {
|
||||
|
||||
+10
-14
@@ -30,19 +30,15 @@ module.exports = class DefineCommand extends Command {
|
||||
}
|
||||
|
||||
async run(msg, { word }) {
|
||||
try {
|
||||
const { body } = await request
|
||||
.get(`https://www.dictionaryapi.com/api/v3/references/collegiate/json/${word}`)
|
||||
.query({ key: WEBSTER_KEY });
|
||||
if (!body.length) return msg.say('Could not find any results.');
|
||||
const data = body[0];
|
||||
if (typeof data === 'string') return msg.say(`Could not find any results. Did you mean **${data}**?`);
|
||||
return msg.say(stripIndents`
|
||||
**${data.meta.stems[0]}** (${data.fl})
|
||||
${data.shortdef.map((definition, i) => `(${i + 1}) ${definition}`).join('\n')}
|
||||
`);
|
||||
} catch (err) {
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
const { body } = await request
|
||||
.get(`https://www.dictionaryapi.com/api/v3/references/collegiate/json/${word}`)
|
||||
.query({ key: WEBSTER_KEY });
|
||||
if (!body.length) return msg.say('Could not find any results.');
|
||||
const data = body[0];
|
||||
if (typeof data === 'string') return msg.say(`Could not find any results. Did you mean **${data}**?`);
|
||||
return msg.say(stripIndents`
|
||||
**${data.meta.stems[0]}** (${data.fl})
|
||||
${data.shortdef.map((definition, i) => `(${i + 1}) ${definition}`).join('\n')}
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user