jillo-bot/src/lib/game.ts

153 lines
5.1 KiB
TypeScript

import { Interaction, Message, TextBasedChannel, User } from 'discord.js';
export const RANDOM_WORDS = [
'tarsorado', 'aboba', 'robtop', 'viprin', 'milk', 'milking station', 'radiation', 'extreme', 'glogging', 'glogged',
'penis', 'deadlocked', 'cream', 'dragon cream', 'urine', 'communal', 'piss', 'matpat', 'big and round', 'easy',
'cum', 'glue', 'tampon', 'contaminated water', 'centrifuge', 'inflation', 'plutonium', 'uranium', 'thorium',
'imposter', 'sounding', '💥', '🥵', '🎊', '!!!', '...', '???', '?..', '?!', '!', '?', 'balls itch', 'robert',
'gas leak', 'among us', 'stick a finger', 'overclock', 'breed', 'gay sex', 'breedable', 'cock vore', 'appendix',
'mukbang', 'edging', 'onlyfans', 'productive', 'mandelbrot', 'novosibirsk', 'oops!', 'farting', 'memory leak',
'pepsi can'
];
export function randomWord() {
return RANDOM_WORDS[Math.floor(Math.random() * RANDOM_WORDS.length)];
}
const DONE_EMOJI = '👍';
const BAD_EMOJI = '👎';
const DEFAULT_EMOJI = '🪙';
const STOP_EMOJI = '⏹️';
function formatMessage(users: User[], time: number, name: string, ended = false) {
return `Starting a **${name}** game (${users.length} player${users.length !== 1 ? 's' : ''})\n`
+ users.map(user => `- ${user.toString()}`).join('\n') + '\n'
+ (time <= 0 ?
(ended ? '**Already ended!**' : '**Already started**') :
`Starting in **${Math.ceil(time / 1000)}s** - react ${STOP_EMOJI} to begin now`
);
}
export async function startGame(interaction: Interaction, startingUser: User, name: string, callback: (players: User[], channel: TextBasedChannel) => Promise<void>) {
if (!interaction.isChatInputCommand()) return;
let participants: User[] = [startingUser];
const duration = 25_000;
const m = await interaction.reply({
fetchReply: true,
content: formatMessage(participants, duration, name)
});
if (!(m instanceof Message)) return;
const emoji = m.guild?.emojis.cache.random();
await m.react(emoji || DEFAULT_EMOJI);
await m.react(STOP_EMOJI);
const started = Date.now();
const collector = m.createReactionCollector({
filter: (reaction, user) =>
!user.bot && (
(
(emoji ? reaction.emoji.id === emoji.id : reaction.emoji.name === DEFAULT_EMOJI) &&
!participants.find(u => user.id === u.id)
) || (reaction.emoji.name === STOP_EMOJI && user.id === startingUser.id)
),
time: duration,
dispose: true
});
const updateInterval = setInterval(() => {
m.edit(formatMessage(participants, duration - (Date.now() - started), name));
}, 3_000);
collector.on('collect', (reaction, user) => {
if (reaction.emoji.name === STOP_EMOJI) {
collector.stop();
} else {
participants.push(user);
m.edit(formatMessage(participants, duration - (Date.now() - started), name));
}
});
collector.on('remove', (_, user) => {
participants = participants.filter(u => u.id !== user.id);
m.edit(formatMessage(participants, duration - (Date.now() - started), name));
});
collector.on('end', async () => {
clearInterval(updateInterval);
m.edit(formatMessage(participants, 0, name));
await callback(participants, m.channel);
m.edit(formatMessage(participants, 0, name, true));
});
}
export async function getTextResponse(user: User, prompt: string, filter: (content: string) => boolean = () => true): Promise<string | null> {
const msg = await user.send(prompt);
try {
const collected = await msg.channel.awaitMessages({
max: 1,
time: 45_000,
errors: ['time'],
filter: (msg) => {
const valid = msg.content !== '' && msg.content.length <= 2000 && filter(msg.content);
if (!valid) msg.react(BAD_EMOJI);
return valid;
}
});
const message = collected.first() as Message;
await message.react(DONE_EMOJI);
return message.content;
} catch (err) {
return null;
}
}
export async function getTextResponsePrettyPlease(user: User, prompt: string, filter: (content: string) => boolean = () => true): Promise<string> {
const resp = await getTextResponse(user, prompt, filter);
if (resp) return resp;
user.send('Took too long... Surprise... Added...... :)');
return randomWord();
}
function* chunks(arr: unknown[], n: number) {
for (let i = 0; i < arr.length; i += n) {
yield arr.slice(i, i + n);
}
}
export async function sendSegments(segments: string[], channel: TextBasedChannel) {
const content = [];
let contentBuffer = '';
while (segments.length > 0) {
const segment = segments.splice(0, 1)[0];
const newMsg = contentBuffer + '\n' + segment;
if (newMsg.length > 2000) {
content.push(contentBuffer);
contentBuffer = '';
if (segment.length > 2000) {
content.push(...([...(chunks(segment.split(''), 2000))].map(s => s.join(''))));
} else {
contentBuffer = segment;
}
} else {
contentBuffer = newMsg;
}
}
if (contentBuffer !== '') content.push(contentBuffer);
content.forEach(async content => {
await channel.send({
content: content,
allowedMentions: {
parse: ['users']
}
});
});
}