-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Counting game #535
base: main
Are you sure you want to change the base?
Counting game #535
Changes from 3 commits
93aa164
aa8822a
a6dc113
99cad69
e64c9bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,18 +14,30 @@ import { PDFDocument } from 'pdf-lib'; | |
import { Logger } from 'winston'; | ||
import { applyBonusByUserId } from '../components/coin'; | ||
import { vars } from '../config'; | ||
import { sendKickEmbed } from '../utils/embeds'; | ||
import { sendKickEmbed, DEFAULT_EMBED_COLOUR } from '../utils/embeds'; | ||
import { convertPdfToPic } from '../utils/pdfToPic'; | ||
import { openDB } from '../components/db'; | ||
import { spawnSync } from 'child_process'; | ||
import { User } from 'discord.js'; | ||
import { getCoinEmoji } from '../components/emojis'; | ||
import { adjustCoinBalanceByUserId, UserCoinEvent } from '../components/coin'; | ||
|
||
const ANNOUNCEMENTS_CHANNEL_ID: string = vars.ANNOUNCEMENTS_CHANNEL_ID; | ||
const RESUME_CHANNEL_ID: string = vars.RESUME_CHANNEL_ID; | ||
const COUNTING_CHANNEL_ID: string = vars.COUNTING_CHANNEL_ID; | ||
const IRC_USER_ID: string = vars.IRC_USER_ID; | ||
const PDF_FILE_PATH = 'tmp/resume.pdf'; | ||
const HEIC_FILE_PATH = 'tmp/img.heic'; | ||
const CONVERTED_IMG_PATH = 'tmp/img.jpg'; | ||
|
||
// Variables and constants associated with the counting game | ||
const coinsPerMessage = 0.1; // Number of coins awarded = coinsPerMessage * highest counting number * messages sent by user | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change this to 0.25 to avoid floating point errors (ex. 18.900000000000002). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In general, we prefer to keep all constant variable names capitalized and snake-cased (see above format). |
||
const countingAuthorDelay = 1; // The minimum number of users that must count for someone to go again | ||
const previousCountingAuthors: Array<User> = []; // Stores the most recent counters | ||
const authorMessageCounts: Map<User, number> = new Map(); // Stores how many messages each user sent | ||
const coinAwardNumberThreshold = 20; // The minimum number that must be reached for coins to be awarded | ||
let currentCountingNumber = 1; | ||
|
||
/* | ||
* If honeypot is to exist again, then add HONEYPOT_CHANNEL_ID to the config | ||
* and add a check for a message's channel ID being equal to HONEYPOT_CHANNEL_ID | ||
|
@@ -93,13 +105,12 @@ const convertResumePdfsIntoImages = async ( | |
message: Message, | ||
): Promise<Message<boolean> | undefined> => { | ||
const attachment = message.attachments.first(); | ||
const hasAttachment = attachment; | ||
const isPDF = attachment && attachment.contentType === 'application/pdf'; | ||
const isImage = | ||
attachment && attachment.contentType && attachment.contentType.startsWith('image'); | ||
|
||
// If no resume pdf is provided, nuke message and DM user about why their message got nuked | ||
if (!(hasAttachment && (isPDF || isImage))) { | ||
if (!(attachment && (isPDF || isImage))) { | ||
const user = message.author.id; | ||
const channel = message.channelId; | ||
|
||
|
@@ -200,6 +211,82 @@ const convertResumePdfsIntoImages = async ( | |
} | ||
}; | ||
|
||
const countingGameLogic = async ( | ||
client: Client, | ||
message: Message, | ||
): Promise<Message<boolean> | undefined> => { | ||
// Check to see if game should end | ||
let reasonForFailure = ''; | ||
if (isNaN(Number(message.content))) { | ||
// Message was not a number | ||
reasonForFailure = `"${message.content}" is not a number!`; | ||
} else if (previousCountingAuthors.find((author) => author === message.author)) { | ||
// Author is still on cooldown | ||
reasonForFailure = `<@${message.author.id}> counted too recently!`; | ||
} else if (Number(message.content) != currentCountingNumber) { | ||
// Wrong number was sent | ||
reasonForFailure = `${message.content} is not the next number! The next number was ${currentCountingNumber}.`; | ||
} | ||
|
||
if (reasonForFailure) { | ||
return endCountingGame(client, message, reasonForFailure); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Subtract currentCountingNumber by 1 when the game ends because this value of currentCountingNumber was not actually reached. |
||
} | ||
|
||
// If checks passed, continue the game | ||
currentCountingNumber++; | ||
message.react('✅'); | ||
previousCountingAuthors.unshift(message.author); // Add current author to list of authors on cooldown | ||
while (previousCountingAuthors.length > countingAuthorDelay) { | ||
previousCountingAuthors.pop(); // Remove last author from cooldown | ||
} | ||
const currentAuthorCount: number | undefined = authorMessageCounts.get(message.author); | ||
authorMessageCounts.set(message.author, currentAuthorCount ? currentAuthorCount + 1 : 1); | ||
|
||
return; | ||
}; | ||
|
||
const endCountingGame = async ( | ||
client: Client, | ||
message: Message, | ||
reasonForFailure: string, | ||
): Promise<Message<boolean> | undefined> => { | ||
// Builds game over embed | ||
const endGameEmbed = new EmbedBuilder() | ||
.setColor(DEFAULT_EMBED_COLOUR) | ||
.setTitle('Counting Game Over') | ||
.addFields([ | ||
{ | ||
name: 'Reason for Game Over', | ||
value: reasonForFailure, | ||
}, | ||
]); | ||
|
||
if (currentCountingNumber < coinAwardNumberThreshold) { | ||
endGameEmbed.setDescription( | ||
`Coins will not be awarded because the threshold, ${coinAwardNumberThreshold}, was not reached.`, | ||
); | ||
} else { | ||
const sortedAuthorMessageCounts: Array<[User, number]> = Array.from(authorMessageCounts).sort( | ||
(a, b) => b[1] - a[1], | ||
); // Turns map into descending sorted array | ||
const coinsAwarded: Array<string> = ['**Coins awarded:**']; | ||
for (const pair of sortedAuthorMessageCounts) { | ||
pair[1] *= coinsPerMessage * currentCountingNumber; // Changes number of messages sent to number of coins awarded | ||
coinsAwarded.push(`<@${pair[0].id}> - ${pair[1]} ${getCoinEmoji()}`); | ||
await adjustCoinBalanceByUserId(message.author.id, pair[1], UserCoinEvent.Counting); | ||
} | ||
|
||
endGameEmbed.setDescription(coinsAwarded.join('\n')); | ||
} | ||
|
||
currentCountingNumber = 1; | ||
message.react('❌'); | ||
previousCountingAuthors.length = 0; | ||
authorMessageCounts.clear(); | ||
|
||
return await message.channel?.send({ embeds: [endGameEmbed] }); | ||
}; | ||
|
||
export const initMessageCreate = async ( | ||
client: Client, | ||
logger: Logger, | ||
|
@@ -219,6 +306,10 @@ export const initMessageCreate = async ( | |
await convertResumePdfsIntoImages(client, message); | ||
} | ||
|
||
if (message.channelId === COUNTING_CHANNEL_ID) { | ||
await countingGameLogic(client, message); | ||
} | ||
|
||
// Ignore DMs; include announcements, thread, and regular text channels | ||
if (message.channel.type !== ChannelType.DM) { | ||
await applyBonusByUserId(message.author.id); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add this variable into config/vars.template.json for future devs.