more gaming
This commit is contained in:
parent
93f34d1681
commit
f6fe3ca2e9
249
commands/connect4.js
Normal file
249
commands/connect4.js
Normal file
|
@ -0,0 +1,249 @@
|
|||
const Revolt = require('revolt.js');
|
||||
const { client, config } = require('..');
|
||||
const getUser = require('../util/get_user');
|
||||
|
||||
/**
|
||||
* @type {Map<String, { createdBy: String, opponent: String, messageID: String }>}
|
||||
*/
|
||||
let sessions = new Map();
|
||||
const gameEndEmitter = new (require('events'));
|
||||
let playerSymbol = 'ඞ';
|
||||
let invisColor = '242424';
|
||||
// Note to myself: https://katex.org/docs/supported.html
|
||||
|
||||
module.exports.meta = {
|
||||
name: 'connect4',
|
||||
aliases: [ 'connect-4' ],
|
||||
description: 'Play connect 4.'
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param { Revolt.Message } message
|
||||
* @param { string[] } args
|
||||
*/
|
||||
module.exports.run = async (message, args) => new Promise(async (resolve, reject) => {
|
||||
if ((await client.channels.fetch(message.channel)).channel_type !== 'Group')
|
||||
return client.channels.sendMessage(message.channel, ':x: You can\'t play here.');
|
||||
|
||||
if (args[0]?.toLowerCase() === 'stop' || args[0]?.toLowerCase() === 'end') {
|
||||
if (!sessions.get(message.channel)?.messageID)
|
||||
return client.channels.sendMessage(message.channel, `:x: No ongoing match found.`);
|
||||
|
||||
sessions.delete(message.channel);
|
||||
gameEndEmitter.emit(message.channel);
|
||||
await client.channels.sendMessage(message.channel, `:white_check_mark: Game stopped`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sessions.get(message.channel))
|
||||
return client.channels.sendMessage(message.channel, `:x: There's an ongoing match ` +
|
||||
`[here](https://app.revolt.chat/channel/${message.channel}/${sessions.get(message.channel).messageID}), ` +
|
||||
`please wait for it to finish or use \`${config.prefix}connect4 stop\`.`);
|
||||
|
||||
if (!args[0])
|
||||
return client.channels.sendMessage(message.channel, ':x: Please specify the ID or username of your opponent.');
|
||||
|
||||
let opponent = await getUser(args.join(' '));
|
||||
if (!opponent)
|
||||
return client.channels.sendMessage(message.channel, 'I can\'t find that user.');
|
||||
if (opponent._id === client.user._id)
|
||||
return client.channels.sendMessage(message.channel, ':x: You can\'t play against me. (yet)');
|
||||
if (opponent._id === message.author)
|
||||
return client.channels.sendMessage(message.channel, ':x: You can\'t play against yourself, dumbus');
|
||||
if (client.channels.get(message.channel).recipients?.indexOf(opponent._id) === -1)
|
||||
return client.channels.sendMessage(message.channel, ':x: That user is not in this group.');
|
||||
|
||||
let field = [
|
||||
[' ', ' ', ' ', ' ', ' ', ' ', ' '],
|
||||
[' ', ' ', ' ', ' ', ' ', ' ', ' '],
|
||||
[' ', ' ', ' ', ' ', ' ', ' ', ' '],
|
||||
[' ', ' ', ' ', ' ', ' ', ' ', ' '],
|
||||
[' ', ' ', ' ', ' ', ' ', ' ', ' '],
|
||||
[' ', ' ', ' ', ' ', ' ', ' ', ' '],
|
||||
];
|
||||
|
||||
let red = await client.users.fetch(message.author);
|
||||
let blue = opponent;
|
||||
let currentPlayer = 'R';
|
||||
let winner = null;
|
||||
if (Math.random() > 0.5) [red, blue] = [blue, red];
|
||||
if (Math.random() > 0.5) currentPlayer = 'B';
|
||||
|
||||
let text;
|
||||
let msg;
|
||||
let resendTip = true;
|
||||
const updateMsg = async () => {
|
||||
text = `Blue: <@${blue._id}> \u200b Red: <@${red._id}>\n`
|
||||
+ `${winner === null ? `**${currentPlayer === 'R' ? 'Red' : 'Blue'}'s turn**` : ''}\n\u200b\n`
|
||||
+ '| 1 | 2 | 3 | 4 | 5 | 6 | 7 |\n'
|
||||
+ '|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n';
|
||||
|
||||
field.forEach(row => {
|
||||
row.forEach(p => {
|
||||
let color
|
||||
if (p !== ' ')
|
||||
color = p === 'B' ? 'blue' : 'red';
|
||||
else
|
||||
color = invisColor;
|
||||
|
||||
text += `| $\\color{${color}}\\huge\\text{\u200b ${playerSymbol} \u200b}$`;
|
||||
});
|
||||
text += '|\n';
|
||||
});
|
||||
|
||||
if (winner === false) {
|
||||
text += '\n\u200b\n# No winner'
|
||||
} else if (winner !== null) {
|
||||
if (Math.random() > 0.8) {
|
||||
text += `\n\u200b\n# $\\color{${winner === 'B' ? 'red' : 'blue'}}\\huge\\text{𓀐}$ ` +
|
||||
`$\\color{${winner === 'B' ? 'blue' : 'red'}}\\huge\\text{𓂺ඞ}$\n` +
|
||||
`# <@${(winner === 'R' ? blue : red)._id}> got fucked by <@${(winner === 'R' ? red : blue)._id}>!`;
|
||||
} else {
|
||||
text += `\n\u200b\n# <@${(winner === 'R' ? red : blue)._id}> wins`;
|
||||
}
|
||||
} else if (resendTip) {
|
||||
text += `\n\u200b\n##### Tip: Use \`${config.prefix}resend\` to move this message to the bottom`;
|
||||
}
|
||||
|
||||
|
||||
if (!msg) {
|
||||
msg = await client.channels.sendMessage(message.channel, text);
|
||||
sessions.set(message.channel, { messageID: msg._id, createdBy: message.author, opponent: opponent._id });
|
||||
} else
|
||||
await client.channels.editMessage(message.channel, msg._id, { content: text });
|
||||
}
|
||||
|
||||
await updateMsg();
|
||||
|
||||
const end = awaitMessages(message.channel, mesg => {
|
||||
if (mesg.content?.toLowerCase() === `${config.prefix}resend` && (mesg.author === red._id || mesg.author === blue._id)) {
|
||||
let oldID = msg?._id;
|
||||
msg = null;
|
||||
resendTip = false;
|
||||
updateMsg();
|
||||
client.channels.deleteMessage(message.channel, oldID)
|
||||
.catch(console.warn);
|
||||
return;
|
||||
}
|
||||
|
||||
let [num, bruh] = mesg.content.split(' ');
|
||||
num = Number(num) - 1;
|
||||
if (bruh || isNaN(num) || num > 6 || num < 0) return;
|
||||
|
||||
if (mesg.author !== red._id && mesg.author !== blue._id)
|
||||
return client.channels.sendMessage(message.channel, `You are not part of this game, <@${mesg.author}>`);
|
||||
|
||||
if ((currentPlayer === 'R' ? red : blue)._id !== mesg.author)
|
||||
return client.channels.sendMessage(message.channel, `It's not your turn, <@${mesg.author}>`);
|
||||
|
||||
if (field[0][num] !== ' ')
|
||||
return client.channels.sendMessage(message.channel, 'That row is occupied.');
|
||||
|
||||
let i;
|
||||
for (i = 5; field[i][num] !== ' '; i--) {}
|
||||
|
||||
field[i][num] = currentPlayer;
|
||||
currentPlayer = currentPlayer === 'R' ? 'B' : 'R';
|
||||
|
||||
let w = getWinner(field);
|
||||
if (w === false) {
|
||||
winner = false;
|
||||
client.channels.sendMessage(message.channel, 'Draw: Nobody wins');
|
||||
end();
|
||||
}
|
||||
if (w) {
|
||||
winner = w;
|
||||
client.channels.sendMessage(message.channel, `<@${w === 'R' ? red._id : blue._id}> wins`);
|
||||
end();
|
||||
}
|
||||
|
||||
updateMsg();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} channel
|
||||
* @param {function} callback
|
||||
*/
|
||||
|
||||
const emitter = new (require('events'));
|
||||
client.on('message', message => {
|
||||
emitter.emit('message', message);
|
||||
});
|
||||
|
||||
function awaitMessages(channel, callback) {
|
||||
let ended = false;
|
||||
const listener = emitter.on('message', message => {
|
||||
if (message.channel === channel && !ended) {
|
||||
callback(message);
|
||||
}
|
||||
});
|
||||
|
||||
gameEndEmitter.on(channel, () => ended = true);
|
||||
return () => {
|
||||
// somehow remove the listener idk how
|
||||
gameEndEmitter.emit(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {('R'|'B'|' ')[][]} field
|
||||
* @returns {null|'R'|'B'|boolean}
|
||||
*/
|
||||
const getWinner = field => {
|
||||
// Horizontal
|
||||
for (let i = 0; i < 6; i++) {
|
||||
for (let j = 0; j < 4; j++) {
|
||||
if (field[i][j] !== ' ' &&
|
||||
field[i][j + 1] === field[i][j] &&
|
||||
field[i][j + 2] === field[i][j] &&
|
||||
field[i][j + 3] === field[i][j]
|
||||
) return field[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (let j = 0; j < 7; j++) {
|
||||
if (field[i][j] !== ' ' &&
|
||||
field[i + 1][j] === field[i][j] &&
|
||||
field[i + 2][j] === field[i][j] &&
|
||||
field[i + 3][j] === field[i][j]
|
||||
) return field[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// Diagonal (Top left - bottom right)
|
||||
for (let i = 0; i < 6; i++) {
|
||||
for (let j = 0; j < 7; j++) {
|
||||
if (field[i][j] !== ' ' &&
|
||||
field[i + 1]?.[j + 1] === field[i][j] &&
|
||||
field[i + 2]?.[j + 2] === field[i][j] &&
|
||||
field[i + 3]?.[j + 3] === field[i][j]
|
||||
) return field[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// Diagonal (Top right - bottom left)
|
||||
for (let i = 0; i < 6; i++) {
|
||||
for (let j = 0; j < 7; j++) {
|
||||
if (field[i][j] !== ' ' &&
|
||||
field[i - 1]?.[j + 1] === field[i][j] &&
|
||||
field[i - 2]?.[j + 2] === field[i][j] &&
|
||||
field[i - 3]?.[j + 3] === field[i][j]
|
||||
) return field[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
let draw = true;
|
||||
for (let i = 0; i < 6; i++) {
|
||||
for (let j = 0; j < 7; j++) {
|
||||
if (field[i][j] === ' ') draw = false;
|
||||
}
|
||||
}
|
||||
if (draw) return false;
|
||||
return null;
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
const Revolt = require('revolt.js');
|
||||
const { client, config } = require('..');
|
||||
const getUser = require('../util/get_user');
|
||||
|
||||
|
@ -5,6 +6,7 @@ const getUser = require('../util/get_user');
|
|||
* @type {Map<String, { createdBy: String, opponent: String, messageID: String }>}
|
||||
*/
|
||||
let sessions = new Map();
|
||||
const gameEndEmitter = new (require('events'));
|
||||
|
||||
module.exports.meta = {
|
||||
name: 'tictactoe',
|
||||
|
@ -26,6 +28,7 @@ module.exports.run = async (message, args) => new Promise(async (resolve, reject
|
|||
return client.channels.sendMessage(message.channel, `:x: No ongoing match found.`);
|
||||
|
||||
sessions.delete(message.channel);
|
||||
gameEndEmitter.emit(message.channel);
|
||||
await client.channels.sendMessage(message.channel, `:white_check_mark: Game stopped`);
|
||||
return;
|
||||
}
|
||||
|
@ -142,6 +145,13 @@ function awaitMessages(channel, callback) {
|
|||
callback(message);
|
||||
}
|
||||
});
|
||||
|
||||
gameEndEmitter.on(channel, () => ended = true);
|
||||
return () => {
|
||||
// somehow remove the listener idk how
|
||||
gameEndEmitter.emit(channel);
|
||||
}
|
||||
|
||||
return () => {
|
||||
// somehow remove the listener idk how
|
||||
ended = true;
|
||||
|
|
Loading…
Reference in a new issue