Skip to content
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

Prevent back-to-back combo breaking in the counting game #808

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"db:validateSchema": "docker exec -it tripbot npx prisma validate",
"db:generateClient": "npx prisma generate && docker exec -it tripbot npx prisma generate",
"db:pushDev": "docker exec -it tripbot npx prisma db push && npm run tripbot:db:generate",
"db:migrateDev": "docker exec -it tripbot npx prisma migrate dev -n welcome_fix",
"db:migrateDev": "docker exec -it tripbot npx prisma migrate dev -n counting_breaks",
"db:seed": "docker exec -it tripbot npx prisma db seed",
"## PGADMIN ##": "",
"pgadmin": "docker compose --project-name tripbot up -d --force-recreate --build tripbot_pgadmin",
Expand Down
88 changes: 72 additions & 16 deletions src/discord/commands/guild/d.counting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@

const F = f(__filename);

interface ComboHistoryObj {

Check failure on line 22 in src/discord/commands/guild/d.counting.ts

View workflow job for this annotation

GitHub Actions / Lint

'ComboHistoryObj' is defined but never used
user_id: string | null;
game_id: string;
count: Number;
last_broken_at: number;
}

function calcTotalPot(
number:number,
users:number,
Expand Down Expand Up @@ -272,6 +279,17 @@
if (!countingData) return; // If not a counting channel then ignore all messages
log.debug(F, `countingData: ${JSON.stringify(countingData, null, 2)} `);

// Get recent combo breakers
const recentComboBreakers = await db.counting_breaks.findMany({
where: {
game_id: countingData.type,
},
orderBy: {
last_broken_at: 'desc'

Check failure on line 288 in src/discord/commands/guild/d.counting.ts

View workflow job for this annotation

GitHub Actions / Lint

Missing trailing comma
},
take: 4,
});

// Process the new message. If it's the next number after current_number, then update the DB
// If it's not the next number, then still update the db with the user who broke the combo

Expand Down Expand Up @@ -306,10 +324,10 @@
{ before: message.id },
) as Collection<string, Message<true>>;
const lastMessage = channelMessages
.filter(m => m.author.id === message.author.id) // Messages sent by the user
.filter(m => !Number.isNaN(parseInt(m.cleanContent, 10))) // That are numbers
.filter(m => m.createdTimestamp > Date.now() - (1000 * 60 * 60)) // That are within one hour
.sort((a, b) => b.createdTimestamp - a.createdTimestamp) // Sorted by most recent
.filter((m: { author: { id: any; }; }) => m.author.id === message.author.id) // Messages sent by the user
.filter((m: { cleanContent: string; }) => !Number.isNaN(parseInt(m.cleanContent, 10))) // That are numbers
.filter((m: { createdTimestamp: number; }) => m.createdTimestamp > Date.now() - (1000 * 60 * 60)) // That are within one hour
.sort((a: { createdTimestamp: number; }, b: { createdTimestamp: number; }) => b.createdTimestamp - a.createdTimestamp) // Sorted by most recent
.first(); // Get the first one

if (lastMessage && countingData.type === 'TOKEN'
Expand All @@ -321,6 +339,28 @@
if (number !== countingData.current_number + 1) {
await message.channel.messages.fetch(countingData.current_number_message_id);

//const comboBreakingHistory: ComboHistoryObj[] = countingData.combo_breaking_history;

Check failure on line 342 in src/discord/commands/guild/d.counting.ts

View workflow job for this annotation

GitHub Actions / Lint

Expected exception block, space or tab after '//' in comment

// if (comboBreakingHistory.length > 4) {
// comboBreakingHistory.shift();
// }

Check failure on line 347 in src/discord/commands/guild/d.counting.ts

View workflow job for this annotation

GitHub Actions / Lint

Trailing spaces not allowed
if (recentComboBreakers) {
// Check if the user has broken the combo recently, and if so, flag them and prevent the break.
// REMOVE THIS COMMENT AFTER READING - THIS SHOULD BE FINE.
let userCanBreakCombo = true;
recentComboBreakers.forEach((comboBreak: { user_id: string; }) => {
if (message.author.id === comboBreak.user_id) {
userCanBreakCombo = false;
}
});
if (!userCanBreakCombo) {
await message.reply('You cannot break the combo if you are one of the last 4 people to have broken it recently.');
// await message.reply(`You cannot break the combo if you are one of the last 4 people to break it: ${JSON.stringify(comboBreakingHistory)}`);
return;
}
}

const stakeholderNumber = countingData.current_stakeholders
? countingData.current_stakeholders.split(',').length
: 1;
Expand All @@ -331,11 +371,11 @@
if (countingData.current_stakeholders
&& !countingData.current_stakeholders.split(',').includes(message.author.id)
&& !warnedUsers.includes(message.author.id)) {
let messageReply = `Hey ${message.member?.displayName}, welcome to the counting game!
let messageReply = stripIndents`Hey ${message.member?.displayName}, welcome to the counting game!

You may not know, but you're breaking the combo!

The current number is ${countingData.current_number}, if you want to join the game, type the next number in the series!
The current number is ${countingData.current_number}, if you want to join the game, type the next number in the series!
`;
if (countingData.type === 'HARDCORE') {
messageReply += 'If you break the combo again, you\'ll be timed out for 24 hours!';
Expand Down Expand Up @@ -374,6 +414,7 @@
countingData.last_number_message_author = countingData.current_number_message_author;
countingData.last_number_broken_by = message.author.id;
countingData.last_number_broken_date = new Date();
// countingData.combo_breaking_history = JSON.stringify(comboBreakingHistory);

// If the number is not the next number in the sequence...
let recordMessage = '';
Expand Down Expand Up @@ -456,6 +497,21 @@
update: countingData,
});


Check failure on line 500 in src/discord/commands/guild/d.counting.ts

View workflow job for this annotation

GitHub Actions / Lint

More than 1 blank line not allowed
// THIS IS WHERE I LEFT OFF.

Check failure on line 501 in src/discord/commands/guild/d.counting.ts

View workflow job for this annotation

GitHub Actions / Lint

Trailing spaces not allowed

await db.counting_breaks.upsert({
where: {
game_id: countingData.type,
},
create: {
user_id: message.author.id,
game_id: countingData.type,
count: countingData.current_number,
},
});

Check failure on line 513 in src/discord/commands/guild/d.counting.ts

View workflow job for this annotation

GitHub Actions / Lint

Trailing spaces not allowed

Check failure on line 514 in src/discord/commands/guild/d.counting.ts

View workflow job for this annotation

GitHub Actions / Lint

More than 1 blank line not allowed
// Send a message to the channel
await message.channel.send({
embeds: [
Expand Down Expand Up @@ -550,7 +606,7 @@
// Look up the persona of every user in the currentData.current_stakeholders string
// Give each of those personas a fraction of the pot: (totalPot / currentData.current_stakeholders.length)
const stakeholderIds = countingData.current_stakeholders.split(',');
await Promise.all(stakeholderIds.map(async discordId => {
await Promise.all(stakeholderIds.map(async (discordId: any) => {
// const userData = await getUser(message.author.id, null, null);
const userData = await db.users.upsert({
where: {
Expand Down Expand Up @@ -614,40 +670,40 @@
data: new SlashCommandBuilder()
.setName('counting')
.setDescription('All things with counting!')
.addSubcommand(subcommand => subcommand
.addSubcommand((subcommand: { setName: (arg0: string) => { (): any; new(): any; setDescription: { (arg0: string): { (): any; new(): any; addStringOption: { (arg0: (option: any) => any): any; new(): any; }; }; new(): any; }; }; }) => subcommand
.setName('setup')
.setDescription('Set up a Counting channel!')
.addStringOption(option => option
.addStringOption((option: { setDescription: (arg0: string) => { (): any; new(): any; setName: { (arg0: string): { (): any; new(): any; addChoices: { (arg0: { name: string; value: string; }, arg1: { name: string; value: string; }, arg2: { name: string; value: string; }): any; new(): any; }; }; new(): any; }; }; }) => option
.setDescription('What kind of counting game?')
.setName('type')
.addChoices(
{ name: 'Hardcore', value: 'HARDCORE' },
{ name: 'Token', value: 'TOKEN' },
{ name: 'Normal', value: 'NORMAL' },
)))
.addSubcommand(subcommand => subcommand
.addSubcommand((subcommand: { setName: (arg0: string) => { (): any; new(): any; setDescription: { (arg0: string): { (): any; new(): any; addBooleanOption: { (arg0: (option: any) => any): any; new(): any; }; }; new(): any; }; }; }) => subcommand
.setName('scores')
.setDescription('Get the scores for a Counting channel!')
.addBooleanOption(option => option.setName('ephemeral')
.addBooleanOption((option: { setName: (arg0: string) => { (): any; new(): any; setDescription: { (arg0: string): any; new(): any; }; }; }) => option.setName('ephemeral')
.setDescription('Set to "True" to show the response only to you')))
.addSubcommand(subcommand => subcommand
.addSubcommand((subcommand: { setName: (arg0: string) => { (): any; new(): any; setDescription: { (arg0: string): { (): any; new(): any; addIntegerOption: { (arg0: (option: any) => any): { (): any; new(): any; addBooleanOption: { (arg0: (option: any) => any): { (): any; new(): any; addStringOption: { (arg0: (option: any) => any): any; new(): any; }; }; new(): any; }; }; new(): any; }; }; new(): any; }; }; }) => subcommand
.setName('reset')
.setDescription('Reset the counting channel!')
.addIntegerOption(option => option
.addIntegerOption((option: { setDescription: (arg0: string) => { (): any; new(): any; setName: { (arg0: string): any; new(): any; }; }; }) => option
.setDescription('The number to set the channel to')
.setName('number'))
.addBooleanOption(option => option
.addBooleanOption((option: { setName: (arg0: string) => { (): any; new(): any; setDescription: { (arg0: string): any; new(): any; }; }; }) => option
.setName('purge')
.setDescription('Set to "True" to start completely fresh'))
.addStringOption(option => option
.addStringOption((option: { setDescription: (arg0: string) => { (): any; new(): any; setName: { (arg0: string): { (): any; new(): any; addChoices: { (arg0: { name: string; value: string; }, arg1: { name: string; value: string; }, arg2: { name: string; value: string; }): any; new(): any; }; }; new(): any; }; }; }) => option
.setDescription('What kind of counting game?')
.setName('type')
.addChoices(
{ name: 'Hardcore', value: 'HARDCORE' },
{ name: 'Token', value: 'TOKEN' },
{ name: 'Normal', value: 'NORMAL' },
)))
.addSubcommand(subcommand => subcommand
.addSubcommand((subcommand: { setName: (arg0: string) => { (): any; new(): any; setDescription: { (arg0: string): any; new(): any; }; }; }) => subcommand
.setName('end')
.setDescription('End the counting game!')),
async execute(interaction) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-- CreateTable
CREATE TABLE "counting_breaks" (
"id" UUID NOT NULL DEFAULT uuid_generate_v4(),
"user_id" TEXT NOT NULL,
"game_id" "counting_type" NOT NULL,
"count" INTEGER NOT NULL,
"last_broken_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "counting_breaks_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "counting_userid_gameid_unique" ON "counting_breaks"("user_id", "game_id");

-- AddForeignKey
ALTER TABLE "counting_breaks" ADD CONSTRAINT "counting_userid_foreign" FOREIGN KEY ("user_id") REFERENCES "users"("discord_id") ON DELETE NO ACTION ON UPDATE NO ACTION;

-- AddForeignKey
ALTER TABLE "counting_breaks" ADD CONSTRAINT "counting_gameid_foreign" FOREIGN KEY ("id") REFERENCES "counting"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
13 changes: 13 additions & 0 deletions src/prisma/tripbot/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ model counting {
@@unique([guild_id, channel_id], map: "counting_guildid_channelid_unique")
}

model counting_breaks {
id String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
user_id String
game_id counting_type
count Int
last_broken_at DateTime @default(now()) @db.Timestamptz(6)

user users @relation(fields: [user_id], references: [discord_id], onDelete: NoAction, onUpdate: NoAction, map: "counting_userid_foreign")

@@unique([user_id, game_id], map: "counting_userid_gameid_unique")
}

model drugs {
id String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
summary String?
Expand Down Expand Up @@ -174,6 +186,7 @@ model users {
wordle_scores wordle_scores[]
connections_scores connections_scores[]
mini_scores mini_scores[]
counting_breaks counting_breaks[]
}

model wordle_scores {
Expand Down
Loading