mirror of
https://github.com/arthur-pbty/xiao.git
synced 2026-06-22 10:19:11 +02:00
Split Single and Multi Player Games
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
const Command = require('../../structures/Command');
|
||||
const { randomRange, verify } = require('../../util/Util');
|
||||
|
||||
module.exports = class BalloonPopCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'balloon-pop',
|
||||
group: 'mp-games',
|
||||
memberName: 'balloon-pop',
|
||||
description: 'Don\'t let yourself be the last one to pump the balloon before it pops!',
|
||||
credit: [
|
||||
{
|
||||
name: 'PAC-MAN Party',
|
||||
url: 'http://pacman.com/en/pac-man-games/pac-man-party'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
prompt: 'What user would you like to play against?',
|
||||
type: 'user'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { opponent }) {
|
||||
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.');
|
||||
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 userTurn = false;
|
||||
let winner = null;
|
||||
let remains = 500;
|
||||
let turns = 0;
|
||||
while (!winner) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
let pump;
|
||||
++turns;
|
||||
if (turns === 1) {
|
||||
await msg.say(`${user} pumps the balloon!`);
|
||||
pump = true;
|
||||
} else {
|
||||
await msg.say(`${user}, do you pump the balloon again?`);
|
||||
pump = await verify(msg.channel, user);
|
||||
}
|
||||
if (pump) {
|
||||
remains -= randomRange(25, 75);
|
||||
const popped = Math.floor(Math.random() * remains);
|
||||
if (popped <= 0) {
|
||||
await msg.say('The balloon pops!');
|
||||
winner = userTurn ? opponent : msg.author;
|
||||
break;
|
||||
}
|
||||
if (turns >= 3) {
|
||||
await msg.say(`${user} steps back!`);
|
||||
turns = 0;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
} else {
|
||||
turns = 0;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say(`And the winner is... ${winner}! Great job!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
const Command = require('../../structures/Command');
|
||||
const Battle = require('../../structures/battle/Battle');
|
||||
const { randomRange, verify } = require('../../util/Util');
|
||||
|
||||
module.exports = class BattleCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'battle',
|
||||
aliases: ['fight', 'death-battle'],
|
||||
group: 'mp-games',
|
||||
memberName: 'battle',
|
||||
description: 'Engage in a turn-based battle against another user or the AI.',
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
prompt: 'What user would you like to battle?',
|
||||
type: 'user',
|
||||
default: () => this.client.user
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { opponent }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not battle yourself.');
|
||||
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() * 3);
|
||||
if (miss) {
|
||||
await msg.say(`${battle.attacker}'s special attack missed!`);
|
||||
} else {
|
||||
const damage = randomRange(battle.defender.guard ? 50 : 100, battle.defender.guard ? 100 : 150);
|
||||
await msg.say(`${battle.attacker} deals **${damage}** damage!`);
|
||||
battle.defender.dealDamage(damage);
|
||||
}
|
||||
battle.attacker.useMP(50);
|
||||
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 **150** damage!`);
|
||||
battle.defender.dealDamage(150);
|
||||
battle.attacker.useMP(100);
|
||||
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();
|
||||
} else {
|
||||
await msg.say('I do not understand what you want to do.');
|
||||
}
|
||||
}
|
||||
const { winner } = battle;
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say(`The match is over! Congrats, ${winner}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
const Command = require('../../structures/Command');
|
||||
const { stripIndents } = require('common-tags');
|
||||
const { verify } = require('../../util/Util');
|
||||
const emojis = ['⬆', '↗', '➡', '↘', '⬇', '↙', '⬅', '↖'];
|
||||
|
||||
module.exports = class EmojiEmojiRevolutionCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'emoji-emoji-revolution',
|
||||
aliases: ['eer'],
|
||||
group: 'mp-games',
|
||||
memberName: 'emoji-emoji-revolution',
|
||||
description: 'Can you type arrow emoji faster than anyone else has ever typed them before?',
|
||||
guildOnly: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
prompt: 'What user would you like to play against?',
|
||||
type: 'user'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { opponent }) {
|
||||
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.');
|
||||
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;
|
||||
while (turn < 10) {
|
||||
++turn;
|
||||
const emoji = emojis[Math.floor(Math.random() * emojis.length)];
|
||||
await msg.say(emoji);
|
||||
const filter = res => [msg.author.id, opponent.id].includes(res.author.id) && res.content === emoji;
|
||||
const win = await msg.channel.awaitMessages(filter, {
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!win.size) {
|
||||
await msg.say('Hmm... No one even tried that round.');
|
||||
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}
|
||||
`);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
const Command = require('../../structures/Command');
|
||||
const { delay, randomRange, verify } = require('../../util/Util');
|
||||
const words = ['fire', 'draw', 'shoot', 'bang', 'pull', 'boom'];
|
||||
|
||||
module.exports = class GunfightCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'gunfight',
|
||||
aliases: ['western-gunfight'],
|
||||
group: 'mp-games',
|
||||
memberName: 'gunfight',
|
||||
description: 'Engage in a western gunfight against another user. High noon.',
|
||||
guildOnly: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
prompt: 'What user would you like to gunfight?',
|
||||
type: 'user'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { opponent }) {
|
||||
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.');
|
||||
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 winner = await msg.channel.awaitMessages(filter, {
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!winner.size) return msg.say('Oh... No one won.');
|
||||
return msg.say(`The winner is ${winner.first().author}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,123 @@
|
||||
const Command = require('../../structures/Command');
|
||||
const { stripIndents, oneLine } = require('common-tags');
|
||||
const request = require('node-superfetch');
|
||||
const { shuffle, verify } = require('../../util/Util');
|
||||
const choices = ['A', 'B', 'C', 'D'];
|
||||
|
||||
module.exports = class QuizDuelCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'quiz-duel',
|
||||
aliases: ['trivia-duel'],
|
||||
group: 'mp-games',
|
||||
memberName: 'quiz-duel',
|
||||
description: 'Answer a series of quiz questions against an opponent.',
|
||||
credit: [
|
||||
{
|
||||
name: 'Open Trivia DB',
|
||||
url: 'https://opentdb.com/'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
prompt: 'What user would you like to play against?',
|
||||
type: 'user'
|
||||
},
|
||||
{
|
||||
key: 'maxPts',
|
||||
label: 'maximum amount of points',
|
||||
prompt: 'What amount of points should determine the winner?',
|
||||
type: 'integer',
|
||||
min: 1,
|
||||
max: 10
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { opponent, maxPts }) {
|
||||
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.');
|
||||
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 winner = null;
|
||||
let userPoints = 0;
|
||||
let oppoPoints = 0;
|
||||
while (!winner) {
|
||||
const question = await this.fetchQuestion();
|
||||
await msg.say(stripIndents`
|
||||
**You have 15 seconds to answer this question.**
|
||||
${question.question}
|
||||
${question.answers.map((answer, i) => `**${choices[i]}.** ${answer}`).join('\n')}
|
||||
`);
|
||||
const answered = [];
|
||||
const filter = res => {
|
||||
const choice = res.content.toUpperCase();
|
||||
if (!choices.includes(choice) || answered.includes(res.author.id)) return false;
|
||||
if (![msg.author.id, opponent.id].includes(res.author.id)) return false;
|
||||
answered.push(res.author.id);
|
||||
if (question.answers[choices.indexOf(res.content.toUpperCase())] !== question.correct) {
|
||||
msg.say(`${res.author}, that's incorrect!`).catch(() => null);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const msgs = await msg.channel.awaitMessages(filter, {
|
||||
max: 1,
|
||||
time: 15000
|
||||
});
|
||||
if (!msgs.size) {
|
||||
await msg.say(`Sorry, time is up! It was ${question.correct}.`);
|
||||
continue;
|
||||
}
|
||||
const result = msgs.first();
|
||||
const userWin = result.author.id === msg.author.id;
|
||||
if (userWin) ++userPoints;
|
||||
else ++oppoPoints;
|
||||
if (userPoints >= maxPts) winner = msg.author;
|
||||
else if (oppoPoints >= maxPts) winner = opponent;
|
||||
const score = oneLine`
|
||||
${userWin ? '**' : ''}${userPoints}${userWin ? '**' : ''} -
|
||||
${userWin ? '' : '**'}${oppoPoints}${userWin ? '' : '**'}
|
||||
`;
|
||||
await msg.say(`Nice one, ${result.author}! The score is now ${score}!`);
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
if (!winner) return msg.say('Aww, no one won...');
|
||||
return msg.say(`Congrats, ${winner}, you won!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchQuestion() {
|
||||
const { body } = await request
|
||||
.get('https://opentdb.com/api.php')
|
||||
.query({
|
||||
amount: 1,
|
||||
type: 'multiple',
|
||||
encode: 'url3986'
|
||||
});
|
||||
if (!body.results) return this.fetchQuestion();
|
||||
const question = body.results[0];
|
||||
const answers = question.incorrect_answers.map(answer => decodeURIComponent(answer.toLowerCase()));
|
||||
const correct = decodeURIComponent(question.correct_answer.toLowerCase());
|
||||
answers.push(correct);
|
||||
const shuffled = shuffle(answers);
|
||||
return {
|
||||
question: decodeURIComponent(question.question),
|
||||
answers: shuffled,
|
||||
correct
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
const Command = require('../../structures/Command');
|
||||
const { stripIndents } = require('common-tags');
|
||||
const { shuffle, verify } = require('../../util/Util');
|
||||
|
||||
module.exports = class RussianRouletteCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'russian-roulette',
|
||||
aliases: ['r-roulette', 'russia-gun'],
|
||||
group: 'mp-games',
|
||||
memberName: 'russian-roulette',
|
||||
description: 'Who will pull the trigger and die first?',
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
prompt: 'What user would you like to gunfight?',
|
||||
type: 'user',
|
||||
default: () => this.client.user
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { opponent }) {
|
||||
if (opponent.id === msg.author.id) return msg.reply('You may not challenge yourself.');
|
||||
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...');
|
||||
}
|
||||
}
|
||||
let userTurn = true;
|
||||
const gun = shuffle([true, false, false, false, false, false, false, false]);
|
||||
let round = 0;
|
||||
let winner = null;
|
||||
while (!winner) {
|
||||
const player = userTurn ? msg.author : opponent;
|
||||
const notPlayer = userTurn ? opponent : msg.author;
|
||||
if (gun[round]) {
|
||||
await msg.say(`**${player.tag}** pulls the trigger... **And dies!**`);
|
||||
winner = notPlayer;
|
||||
} else {
|
||||
await msg.say(stripIndents`
|
||||
**${player.tag}** pulls the trigger... **And lives...**
|
||||
${opponent.bot ? 'Continue?' : `Will you take the gun, ${notPlayer}?`} (${8 - round - 1} shots left)
|
||||
`);
|
||||
const keepGoing = await verify(msg.channel, opponent.bot ? msg.author : notPlayer);
|
||||
if (!keepGoing) winner = notPlayer;
|
||||
round++;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say(`The winner is ${winner}!`);
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
const Command = require('../../structures/Command');
|
||||
const { stripIndents } = require('common-tags');
|
||||
const { verify } = require('../../util/Util');
|
||||
|
||||
module.exports = class TicTacToeCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'tic-tac-toe',
|
||||
group: 'mp-games',
|
||||
memberName: 'tic-tac-toe',
|
||||
description: 'Play a game of tic-tac-toe with another user.',
|
||||
guildOnly: true,
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
prompt: 'What user would you like to challenge?',
|
||||
type: 'user'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { opponent }) {
|
||||
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.');
|
||||
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 sides = ['0', '1', '2', '3', '4', '5', '6', '7', '8'];
|
||||
const taken = [];
|
||||
let userTurn = true;
|
||||
let winner = null;
|
||||
while (!winner && taken.length < 9) {
|
||||
const user = userTurn ? msg.author : opponent;
|
||||
const sign = userTurn ? 'X' : 'O';
|
||||
await msg.say(stripIndents`
|
||||
${user}, which side do you pick?
|
||||
\`\`\`
|
||||
${sides[0]} | ${sides[1]} | ${sides[2]}
|
||||
—————————
|
||||
${sides[3]} | ${sides[4]} | ${sides[5]}
|
||||
—————————
|
||||
${sides[6]} | ${sides[7]} | ${sides[8]}
|
||||
\`\`\`
|
||||
`);
|
||||
const filter = res => {
|
||||
const choice = res.content;
|
||||
return res.author.id === user.id && sides.includes(choice) && !taken.includes(choice);
|
||||
};
|
||||
const turn = await msg.channel.awaitMessages(filter, {
|
||||
max: 1,
|
||||
time: 30000
|
||||
});
|
||||
if (!turn.size) {
|
||||
await msg.say('Sorry, time is up!');
|
||||
userTurn = !userTurn;
|
||||
continue;
|
||||
}
|
||||
const choice = turn.first().content;
|
||||
sides[Number.parseInt(choice, 10)] = sign;
|
||||
taken.push(choice);
|
||||
if (this.verifyWin(sides)) winner = userTurn ? msg.author : opponent;
|
||||
userTurn = !userTurn;
|
||||
}
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.say(winner ? `Congrats, ${winner}!` : 'Oh... The cat won.');
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
verifyWin(sides) {
|
||||
return (sides[0] === sides[1] && sides[0] === sides[2])
|
||||
|| (sides[0] === sides[3] && sides[0] === sides[6])
|
||||
|| (sides[3] === sides[4] && sides[3] === sides[5])
|
||||
|| (sides[1] === sides[4] && sides[1] === sides[7])
|
||||
|| (sides[6] === sides[7] && sides[6] === sides[8])
|
||||
|| (sides[2] === sides[5] && sides[2] === sides[8])
|
||||
|| (sides[0] === sides[4] && sides[0] === sides[8])
|
||||
|| (sides[2] === sides[4] && sides[2] === sides[6]);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,121 @@
|
||||
const Command = require('../../structures/Command');
|
||||
const request = require('node-superfetch');
|
||||
const { stripIndents } = require('common-tags');
|
||||
const { delay, verify } = require('../../util/Util');
|
||||
const startWords = require('../../assets/json/word-list');
|
||||
const { WEBSTER_KEY } = process.env;
|
||||
|
||||
module.exports = class WordChainCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'word-chain',
|
||||
group: 'mp-games',
|
||||
memberName: 'word-chain',
|
||||
description: 'Try to come up with words that start with the last letter of your opponent\'s word.',
|
||||
guildOnly: true,
|
||||
credit: [
|
||||
{
|
||||
name: 'Moby Word Lists by Grady Ward',
|
||||
url: 'http://www.gutenberg.org/ebooks/3201'
|
||||
}
|
||||
],
|
||||
args: [
|
||||
{
|
||||
key: 'opponent',
|
||||
prompt: 'What user would you like to challenge?',
|
||||
type: 'user'
|
||||
},
|
||||
{
|
||||
key: 'time',
|
||||
prompt: 'How long do you want to wait for input of new words (in seconds)?',
|
||||
type: 'integer',
|
||||
default: 10,
|
||||
max: 10,
|
||||
min: 1
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, { opponent, time }) {
|
||||
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.');
|
||||
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 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 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
async verifyWord(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 false;
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.status === 404) return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user