Skip to content

Commit

Permalink
nothing to see here (#359)
Browse files Browse the repository at this point in the history
* Add emoji watcher gag

* Random message deletion

* Add typing status gag

* Enforce american spellings

* chaos community vote

* init commands

* remove message deletion

* reply then delete

* extract consts

* add timeout

* prettier
  • Loading branch information
dylangarcia authored Apr 1, 2024
1 parent 4b3f04b commit 650bb7d
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 0 deletions.
59 changes: 59 additions & 0 deletions src/features/april-fools/american-spelling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ChannelHandlers } from "../../types";

const AMERICAN_SPELLING_MAP: Record<string, string> = {
colour: "color",
flavour: "flavor",
honour: "honor",
humour: "humor",
labour: "labor",
neighbour: "neighbor",
rumour: "rumor",
savour: "savor",
valour: "valor",
behaviour: "behavior",
favour: "favor",
harbour: "harbor",
odour: "odor",
armour: "armor",
};

const SUPER_SARCASTIC_REPLIES_TO_BRITISH_SPELLING_WORDS = [
"Oh, splendid, another dose of British charm! But I'm afraid we're strictly American today, darling.",
"Well, well, well, what do we have here? Looks like someone's trying to add a little extra 'u' to our lives. Nice try!",
"Oh, lovely attempt at being fancy! But sorry, old chap, we're sticking to our American roots today.",
"Ah, a bit of British flair, how quaint! But alas, it's not quite the style we're going for today.",
"Oh, bravo! Another British gem shining through. But sorry, it's strictly red, white, and blue today!",
"Well, aren't you just a rebel with your extra letters? Sorry, but we're cutting ties with the 'u' today.",
"Ah, the British invasion continues! But I'm afraid your linguistic imperialism won't fly here today.",
"Oh, delightful! Another nod to our friends across the pond. But sorry, we're staying true to our American roots today.",
"Splendid attempt at British sophistication! But sorry, we're keeping it simple and straightforward today.",
"Oh, look at you being all fancy with your British spellings! But I'm afraid it's strictly Yankee Doodle Dandy around here today.",
];

export default {
handleMessage: async ({ msg: maybeMessage }) => {
const msg = maybeMessage.partial
? await maybeMessage.fetch()
: maybeMessage;

const content = msg.content.toLowerCase();
const hasBadWord = Object.keys(AMERICAN_SPELLING_MAP).find((word) =>
content.match(new RegExp(`\\b${word}\\b`, "i")),
);

if (!hasBadWord) {
return;
}

await msg.reply(
SUPER_SARCASTIC_REPLIES_TO_BRITISH_SPELLING_WORDS[
Math.floor(
Math.random() *
SUPER_SARCASTIC_REPLIES_TO_BRITISH_SPELLING_WORDS.length,
)
],
);

await msg.delete();
},
} as ChannelHandlers;
176 changes: 176 additions & 0 deletions src/features/april-fools/community-timeout-vote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { GuildMember, MessageReaction, TextChannel, User } from "discord.js";
import { ChannelHandlers } from "../../types";
import { sleep } from "../../helpers/misc";

const RECENT_CHATTERS = new Set<string>();

let timedOutUserId: string | null = null;
let isProcessingPlea = false;
let isWorthy = true;
let dissenter: GuildMember | null = null;
let conformer: GuildMember | null = null;

const TIMEOUT_DURATION_MINS = 10;
const VOTING_DURATION_MINS = 2;
const NUM_RECENT_CHATTERS_TO_TRIGGER_CHAOS = 10;

const getRandomReactorId = (
reactions: MessageReaction,
botId: string,
): User | null => {
const users = reactions.users.cache;
const usersArray = Array.from(users.values());
const randomUser = usersArray[Math.floor(Math.random() * usersArray.length)];

if (usersArray.length === 1 && randomUser.id === botId) {
return null;
}

while (randomUser.id === botId) {
console.log("Trying to get a random user again");
return getRandomReactorId(reactions, botId);
}

return randomUser;
};

/**
* This feature allows the community to vote on whether a user should be timed out.
* If the user gets timed out, they have to write a pleading message in a certain channel and the AI gods have to deem them worthy enough to be untimedout.
* If they are deemed worthy, it randomly times one of the community voters out for an hour and they can't plead.
*/
export default {
handleMessage: async ({ msg: maybeMessage, bot }) => {
const msg = maybeMessage.partial
? await maybeMessage.fetch()
: maybeMessage;

if (msg.author.bot) {
return;
}

if (timedOutUserId === msg.author.id) {
if (isProcessingPlea || !isWorthy) {
await msg.delete();
return;
}

isProcessingPlea = true;
await msg.reply("Let's see if the AI gods deem you worthy....");
await sleep(3 + Math.floor(Math.random() * 7));
isProcessingPlea = false;
isWorthy = Math.random() > 0.5;

if (isWorthy) {
await msg.reply(
"The AI gods have deemed you worthy. You are free to go.",
);
timedOutUserId = null;

if (conformer) {
try {
await conformer.timeout(TIMEOUT_DURATION_MINS * 60 * 1000);
} catch (error) {
console.error(error);
}
const channel = msg.channel as TextChannel;
await channel.send(`Chaos reigns upon <@${conformer.id}> instead.`);
}
return;
}

await msg.reply(
"The AI gods have deemed you unworthy. You will remain timed out.",
);

await msg.guild?.members.cache
.get(timedOutUserId)
?.timeout(TIMEOUT_DURATION_MINS * 60 * 1000);

sleep(TIMEOUT_DURATION_MINS * 60).then(() => {
// If the person is still timed out, remove the timeout
// Otherwise, somebody else has been timed out so we just let it go
if (timedOutUserId === msg.author.id) {
timedOutUserId = null;
}
});

return;
}

RECENT_CHATTERS.add(msg.author.id);

if (RECENT_CHATTERS.size >= NUM_RECENT_CHATTERS_TO_TRIGGER_CHAOS) {
// Get a random user from recent chatters
const userIds = Array.from(RECENT_CHATTERS);
const randomUser = userIds[Math.floor(Math.random() * userIds.length)];
const user = await msg.client.users.fetch(randomUser);
if (!user) return;

const channel = msg.channel as TextChannel;
const message = await channel.send(
`Chaos is here. React with 👍 to time out <@${user.id}> or 👎 to let them live.`,
);

const filter = (reaction: MessageReaction, user: User) =>
user.id !== message.author.id && user.id !== bot.user?.id;

const collector = message.createReactionCollector({
filter,
time: 1000 * 60 * VOTING_DURATION_MINS,
});

await message.react("👍");
await message.react("👎");

collector.on("end", async () => {
const yesReactions = message.reactions.cache.find(
(reaction) => reaction.emoji.name === "👍",
);
const noReactions = message.reactions.cache.find(
(reaction) => reaction.emoji.name === "👎",
);

if (!yesReactions || !noReactions) {
return;
}

const randomConformerId = bot?.user?.id
? getRandomReactorId(yesReactions, bot.user.id)
: null;
conformer = randomConformerId
? await message.guild?.members.fetch(randomConformerId)
: null;

const randomDissenterId = bot?.user?.id
? getRandomReactorId(noReactions, bot.user.id)
: null;
dissenter = randomDissenterId
? await message.guild?.members.fetch(randomDissenterId)
: null;

if (
yesReactions?.count &&
yesReactions.count > (noReactions?.count ?? 0)
) {
await channel.send(
`The community has spoken. <@${user.id}> has been timed out. <@${user.id}>, your next message is your one attempt to plead your case. If the AI gods deem you worthy, you will be spared and chaos will reign on somebody else.`,
);

timedOutUserId = user.id;
} else {
await channel.send(
`The community has spared <@${user.id}>. Do not let this happen again.`,
);

if (dissenter) {
await dissenter.timeout(TIMEOUT_DURATION_MINS * 60 * 1000);
await channel.send(`Chaos reigns upon <@${dissenter.id}> instead.`);
}
}
});

RECENT_CHATTERS.clear();
}
},
} as ChannelHandlers;
31 changes: 31 additions & 0 deletions src/features/april-fools/im-watching-you.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { sleep } from "../../helpers/misc";
import { ChannelHandlers } from "../../types";

const EMOJIS = [
[0.02, "👀"],
[0.02, "🤔"],
[0.02, "❓"],
] as const;

export default {
handleMessage: async ({ msg: maybeMessage }) => {
const msg = maybeMessage.partial
? await maybeMessage.fetch()
: maybeMessage;

for (const [chance, emoji] of EMOJIS) {
const random = Math.random();
if (random < chance) {
const resp = await msg.react(emoji);

// For added chaos, remove the reaction in ~30-60s
const duration = Math.floor(Math.random() * 30) + 30;
sleep(duration).then(() => {
resp.remove();
});

return;
}
}
},
} as ChannelHandlers;
19 changes: 19 additions & 0 deletions src/features/april-fools/typing-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ChannelHandlers } from "../../types";

const CHANCE_TO_TYPE = 0.02;

export default {
handleMessage: async ({ msg: maybeMessage }) => {
const msg = maybeMessage.partial
? await maybeMessage.fetch()
: maybeMessage;

const random = Math.random();
if (random > CHANCE_TO_TYPE) {
return;
}

const channel = msg.channel;
await channel.sendTyping(); // This will start typing for 10 seconds (a Discord value, not customizable)
},
} as ChannelHandlers;
10 changes: 10 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ import { scheduleTask } from "./helpers/schedule";
import { discordToken } from "./helpers/env";
import { registerCommand, deployCommands } from "./helpers/deploy-commands";
import resumeReviewPdf from "./features/resume-review";
import imWatchingYou from "./features/april-fools/im-watching-you";
import typingStatus from "./features/april-fools/typing-status";
import americanSpelling from "./features/april-fools/american-spelling";
import communityTimeoutVote from "./features/april-fools/community-timeout-vote";

export const bot = new discord.Client({
intents: [
Expand Down Expand Up @@ -185,6 +189,12 @@ const threadChannels = [CHANNELS.helpJs, CHANNELS.helpThreadsReact];
addHandler(threadChannels, autothread);

addHandler(CHANNELS.resumeReview, resumeReviewPdf);
addHandler(CHANNELS.random, [
imWatchingYou,
typingStatus,
americanSpelling,
communityTimeoutVote,
]);

bot.on("ready", () => {
deployCommands(bot);
Expand Down

0 comments on commit 650bb7d

Please sign in to comment.