Finish removing "Oh no, an error occurred"

This commit is contained in:
Dragon Fire
2024-03-30 11:59:42 -04:00
parent f6b59c2d46
commit a135cac031
119 changed files with 3418 additions and 4116 deletions
+4 -12
View File
@@ -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;
}
}
};
+39 -50
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+4 -12
View File
@@ -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
View File
@@ -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) {
+87 -98
View File
@@ -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
View File
@@ -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) {
+77 -88
View File
@@ -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) {
+84 -95
View File
@@ -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) {
+38 -49
View File
@@ -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!`);
}
};
+98 -109
View File
@@ -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) {
+29 -40
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+74 -82
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+76 -87
View File
@@ -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) {
+39 -56
View File
@@ -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
View File
@@ -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) {
+74 -82
View File
@@ -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() {
+60 -73
View File
@@ -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!'}
`);
}
};
+23 -34
View File
@@ -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}...`);
}
};
+65 -76
View File
@@ -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) {
+34 -45
View File
@@ -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})
`);
}
};
+49 -60
View File
@@ -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) {
+38 -49
View File
@@ -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!');
}
};
+48 -56
View File
@@ -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() {
+25 -28
View File
@@ -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',
+65 -76
View File
@@ -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;
+41 -49
View File
@@ -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);
}
};
+1
View File
@@ -15,6 +15,7 @@ module.exports = class CaptchaCommand extends Command {
duration: 10
},
clientPermissions: ['ATTACH_FILES'],
game: true,
credit: [
{
name: 'Christoph Mueller',
+13 -21
View File
@@ -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) {
+29 -37
View File
@@ -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) {
+18 -27
View File
@@ -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) {
+60 -68
View File
@@ -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) {
+24 -27
View File
@@ -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**.
`);
}
};
+1
View File
@@ -20,6 +20,7 @@ module.exports = class HorseRaceCommand extends Command {
duration: 10
},
clientPermissions: ['ATTACH_FILES'],
game: true,
credit: [
{
name: 'Ambition',
+35 -46
View File
@@ -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) {
+24 -32
View File
@@ -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() {
+25 -33
View File
@@ -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);
}
};
+1
View File
@@ -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
View File
@@ -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) {
+94 -102
View File
@@ -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) {
+29 -37
View File
@@ -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
View File
@@ -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!');
}
};
+27 -35
View File
@@ -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})
`);
}
};
+45 -56
View File
@@ -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
View File
@@ -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...
`);
}
};
+2 -1
View File
@@ -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
});
}
+19 -27
View File
@@ -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] });
}
};
+23 -31
View File
@@ -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) {
+24 -33
View File
@@ -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() {
+7 -11
View File
@@ -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);
}
};
+1 -1
View File
@@ -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;
}
}
};
+1 -5
View File
@@ -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] });
}
};
+9 -13
View File
@@ -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);
}
};
+19 -23
View File
@@ -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'
}]
});
}
};
+13 -17
View File
@@ -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);
}
};
+15 -19
View File
@@ -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'
}]
});
}
};
+51 -55
View File
@@ -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
View File
@@ -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
View File
@@ -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'
}]
});
}
};
+8 -12
View File
@@ -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]] });
}
};
+15 -19
View File
@@ -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}` }]
});
}
};
+5 -9
View File
@@ -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] });
}
};
+5 -9
View File
@@ -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] });
}
};
+2 -6
View File
@@ -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] });
}
};
+2 -6
View File
@@ -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] });
}
};
+2 -6
View File
@@ -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] });
}
};
+4 -8
View File
@@ -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] });
}
};
+6 -10
View File
@@ -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')}`]
});
}
};
+2 -6
View File
@@ -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] });
}
};
+2 -6
View File
@@ -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` }] });
}
};
+8 -12
View File
@@ -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]] });
}
};
+3 -7
View File
@@ -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})`);
}
};
+2 -6
View File
@@ -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})`);
}
};
+2 -6
View File
@@ -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
View File
@@ -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() {
+4 -8
View File
@@ -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);
}
};
+2 -6
View File
@@ -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);
}
};
+9 -13
View File
@@ -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);
}
};
+2 -6
View File
@@ -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]);
}
};
+2 -6
View File
@@ -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
View File
@@ -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}`);
}
};
+1 -1
View File
@@ -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;
}
}
};
+9 -13
View File
@@ -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);
}
};
+6 -10
View File
@@ -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() {
+25 -29
View File
@@ -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) {
+25 -29
View File
@@ -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) {
+26 -30
View File
@@ -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' }] });
}
};
+5 -9
View File
@@ -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) {
+15 -19
View File
@@ -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) {
+21 -25
View File
@@ -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
View File
@@ -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
View File
@@ -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