mirror of
https://github.com/arthur-pbty/xiao.git
synced 2026-06-03 23:36:43 +02:00
153 lines
4.7 KiB
JavaScript
153 lines
4.7 KiB
JavaScript
const Command = require('../../framework/Command');
|
|
const { Collection } = require('@discordjs/collection');
|
|
const { stripIndents } = require('common-tags');
|
|
const { awaitPlayers, reactIfAble } = require('../../util/Util');
|
|
const nums = require('../../assets/json/bingo');
|
|
const { SUCCESS_EMOJI_ID } = process.env;
|
|
const rows = Object.keys(nums);
|
|
const callNums = Array.from({ length: 75 }, (v, i) => i + 1);
|
|
|
|
module.exports = class BingoCommand extends Command {
|
|
constructor(client) {
|
|
super(client, {
|
|
name: 'bingo',
|
|
group: 'games-mp',
|
|
memberName: 'bingo',
|
|
description: 'Play bingo with up to 99 other users.',
|
|
guildOnly: true,
|
|
game: true,
|
|
args: [
|
|
{
|
|
key: 'playersCount',
|
|
type: 'integer',
|
|
min: 1,
|
|
max: 100
|
|
}
|
|
]
|
|
});
|
|
}
|
|
|
|
async run(msg, { playersCount }) {
|
|
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() {
|
|
const result = [];
|
|
for (const [rowID, values] of Object.entries(nums)) {
|
|
const picked = [];
|
|
for (let i = 0; i < 5; i++) {
|
|
const valid = values.filter(value => !picked.includes(value));
|
|
picked.push(valid[Math.floor(Math.random() * valid.length)]);
|
|
}
|
|
const sorted = picked.sort((a, b) => a - b);
|
|
if (rowID === 'N') sorted[2] = 'FR';
|
|
result.push(sorted);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
generateBoardDisplay(board, called) {
|
|
const mapped = board.map((values, i) => {
|
|
const row = rows[i];
|
|
const mapVal = values.map(value => {
|
|
if (called.includes(value) || value === 'FR') return 'XX';
|
|
return value.toString().padStart(2, '0');
|
|
}).join(' | ');
|
|
return `${row} | ${mapVal}`;
|
|
}).join('\n--------------------------\n');
|
|
return stripIndents`
|
|
\`\`\`
|
|
${mapped}
|
|
\`\`\`
|
|
`;
|
|
}
|
|
|
|
findRowValue(num) {
|
|
if (nums.B.includes(num)) return 'B';
|
|
if (nums.I.includes(num)) return 'I';
|
|
if (nums.N.includes(num)) return 'N';
|
|
if (nums.G.includes(num)) return 'G';
|
|
if (nums.O.includes(num)) return 'O';
|
|
return null;
|
|
}
|
|
|
|
checkLine(called, a, b, c, d, e) {
|
|
return called.includes(a)
|
|
&& called.includes(b)
|
|
&& called.includes(c)
|
|
&& called.includes(d)
|
|
&& called.includes(e);
|
|
}
|
|
|
|
checkBingo(bd, ca) {
|
|
for (let r = 0; r < rows.length; r++) {
|
|
if (this.checkLine(ca, bd[r][0], bd[r][1], bd[r][2], bd[r][3], bd[r][4])) return true;
|
|
}
|
|
for (let c = 0; c < rows.length; c++) {
|
|
if (this.checkLine(ca, bd[0][c], bd[1][c], bd[2][c], bd[3][c], bd[4][c])) return true;
|
|
}
|
|
if (this.checkLine(ca, bd[0][0], bd[1][1], bd[2][2], bd[3][3], bd[4][4])) return true;
|
|
if (this.checkLine(ca, bd[4][0], bd[3][1], bd[2][2], bd[1][3], bd[0][4])) return true;
|
|
return false;
|
|
}
|
|
};
|