tictactoe

master
Jan 2021-03-03 16:07:46 +01:00
parent 05d0972ec8
commit b6b9eb66ab
6 changed files with 219 additions and 14 deletions

View File

@ -15,7 +15,7 @@ module.exports.meta = {
*/
module.exports.run = async (message, args) => new Promise(async (resolve, reject) => {
const channel = await client.channels.fetch(message.channel);
if (channel.channel_type != "Group") return client.channels.sendMessage(message.channel, `You can't earn XP in this channel.`);
if (channel.channel_type !== "Group") return client.channels.sendMessage(message.channel, `You can't earn XP in this channel.`);
let groupLevels = levels.get(message.channel);
const { xp, level, enabled } = (groupLevels?.[message.author] || {});

174
commands/tictactoe.js Normal file
View File

@ -0,0 +1,174 @@
const Revolt = require('revolt.js');
const { client, logger, config } = require('..');
const { levels, levelups } = require('../util/levels');
const getUser = require('../util/get_user');
/**
* @type {Map<String, { createdBy: String, opponent: String, messageID: String }>}
*/
let sessions = new Map();
module.exports.meta = {
name: 'tictactoe',
aliases: [],
description: 'Play tic tac toe.'
}
/**
*
* @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') {
if (!sessions.get(message.channel)?.messageID)
return client.channels.sendMessage(message.channel, `:x: No ongoing match found.`);
sessions.delete(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}tictactoe 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 x = message.author;
let o = opponent._id;
if (Math.random() > 0.5) [x, o] = [o, x];
let turn = Math.random() > 0.5 ? 'X' : 'O';
let winner = null;
let text;
let msg;
const updateMsg = async () => {
text =
`**X**: <@${x}> \u200b **O**: <@${o}>\n\u200b\n` +
`|${turn}| \u200b \u200b **1** \u200b \u200b | \u200b \u200b **2** \u200b \u200b | \u200b \u200b **3** \u200b \u200b |\n` +
`|-|:-:|:-:|:-:|\n` +
`|**A**|${field[0][0]}|${field[0][1]}|${field[0][2]}|\n` +
`|**B**|${field[1][0]}|${field[1][1]}|${field[1][2]}|\n` +
`|**C**|${field[2][0]}|${field[2][1]}|${field[2][2]}|\n` +
(winner ? `\n\u200b\n# Winner: <@${winner === 'X' ? x : o}>\n\u200b` : '');
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, msg => {
let [ column, row, bruh ] = msg.content?.toLowerCase().split('');
if (column === 'a') column = 0;
if (column === 'b') column = 1;
if (column === 'c') column = 2;
row = Number(row); row--;
column = Number(column); // Prevent borking
if ((isNaN(row) || isNaN(column)) || bruh) return;
if (field[column]?.[row] !== ' ')
return client.channels.sendMessage(msg.channel, 'That field is not available.');
let curPlayer = turn === 'X' ? x : o;
if (msg.author !== x && msg.author !== o)
return client.channels.sendMessage(message.channel, `<@${msg.author}>, you are not part of this game.`);
if (msg.author !== curPlayer)
return client.channels.sendMessage(message.channel, `<@${msg.author}>, it's <@${curPlayer}>'s turn.`);
field[column][row] = turn;
turn = turn === 'X' ? 'O' : 'X';
let w = getWinner(field);
console.log(w);
if (w) {
end();
winner = w;
updateMsg();
sessions.delete(message.channel);
client.channels.sendMessage(message.channel, `<@${w === 'X' ? x : o}> wins!`);
} else {
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);
}
});
return () => {
// somehow remove the listener idk how
ended = true;
}
}
/**
* @param {('X'|'O'|' ')[][]} field
*/
const getWinner = field => {
let winner = null;
['X', 'O'].forEach(player => {
// Horizontal lines
for (let i = 0; i < 3; i++) {
if (field[i][0] === player &&
field[i][1] === player &&
field[i][2] === player) if (!winner) winner = player;
}
// Vertical lines
for (let i = 0; i < 3; i++) {
if (field[0][i] === player &&
field[1][i] === player &&
field[2][i] === player) if (!winner) winner = player;
}
// Diagonal lines
if ((field[0][0] === player || field[0][2] === player) &&
(field[2][0] === player || field[2][2] === player) &&
(field[1][1] === player)) if (!winner) winner = player;
});
return winner;
}

View File

@ -1,5 +1,7 @@
const Revolt = require('revolt.js');
const { client, logger, config } = require('..');
const getUser = require('../util/get_user');
const { levels, levelups } = require('../util/levels');
module.exports.meta = {
name: 'whois',
@ -13,18 +15,22 @@ module.exports.meta = {
* @param { string[] } args
*/
module.exports.run = async (message, args) => new Promise(async (resolve, reject) => {
let uid = args[0];
if (!uid)
return client.channels.sendMessage(message.channel, 'Please <@mention> the target user or type their ID.');
if (!args[0])
return client.channels.sendMessage(message.channel, ':x: Please specify the user\'s name or ID.');
let target = await getUser(args.join(' '));
if (!target)
return client.channels.sendMessage(message.channel, ':x: I can\'t find that user. Type their name or ID.');
if (uid.startsWith('<@') && uid.endsWith('>')) uid = uid.substr(2, uid.length - 3);
const avatarURL = `https://api.revolt.chat/users/${target._id}/avatar`;
const { xp, level, enabled } = (levels.get(message.channel)?.[target._id] || {});
const target = await client.users.fetch(uid)
.catch(e => { return reject(e) });
let msgContent =
`${JSON.stringify(target)}`
let msgContent = `> ## \u200b ${target.username}\n` +
`> \u200b\n` +
`> **ID**: \`${target._id}\`\n` +
`> **Online**: \`${target.online ?? 'Unknown'}\`\n` +
`> **XP**: \`${xp ? `${xp} XP, Level ${level}. Level up in ${levelups.find(l => l > xp) - xp} XP` : 'None'}\`\n` +
`> [\\[Avatar\\]](${avatarURL})\n`
await client.channels.sendMessage(message.channel, msgContent);
});

View File

@ -22,8 +22,10 @@ const logger = new Logger(config.debug ? LogLevel.Debug : LogLevel.Standard);
const client = new Revolt.Client(config.revoltClient);
client.on("message", async message => {
const author = await client.users.fetch(message.author);
const channel = await client.channels.fetch(message.channel);
const author = await client.users.fetch(message.author).catch(()=>{});
const channel = await client.channels.fetch(message.channel).catch(()=>{});
if (!author || !channel) return logger.debug(`Received message with unknown author or channel`);
if (author._id === client.user._id)
return logger.debug(`Sent message -> ${channel.name} => ${message.content}`);

View File

@ -1,10 +1,12 @@
/**
/**if () {
} else
* Automatically accepts friend requests and
* sends requests to users messaging the bot.
* Required for users to add it to groups.
*/
const { client, logger, config } = require('..');
const { client, logger } = require('..');
client.on("packet", async packet => {
try {

21
util/get_user.js Normal file
View File

@ -0,0 +1,21 @@
const { client, logger, config } = require('..');
module.exports = async (input) => {
try {
let output;
if (input.startsWith('<@') && input.endsWith('>'))
output = input.substr(2, input.length - 3);
else {
if (input.startsWith('@')) input = input.substr(1);
if (client.users.get(input))
output = input;
else
output = client.users.toArray().find(user => user.username?.toLowerCase() === input?.toLowerCase())?._id;
}
if (!output) output = input;
return await client.users.fetch(output)
.catch(()=>{});
} catch(e) {
console.error(e);
}
}