Skip to content

Commit

Permalink
Various bug fixes and enhancements.
Browse files Browse the repository at this point in the history
  • Loading branch information
roncli committed Jan 21, 2024
1 parent 64167a9 commit 3139307
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 32 deletions.
1 change: 1 addition & 0 deletions node/src/discord/commands/h.js
@@ -0,0 +1 @@
module.exports = require("./help");
4 changes: 2 additions & 2 deletions node/src/discord/commands/help.js
Expand Up @@ -39,7 +39,7 @@ class HelpCmd {
fields: [
{
name: "General Commands",
value: "`.help` - This help text.\n`.race` - Start a new race.",
value: "`.help`/`.h` - This help text.\n`.race` - Start a new race.",
inline: true
},
{
Expand All @@ -48,7 +48,7 @@ class HelpCmd {
},
{
name: "Race Room Commands - During the Race",
value: "`.done`/`.d` - Indicate that you have finished the race.\n`.forfeit`/`.f` - Forfeit the race.\n`.notdone`/`.n` - If you did `.done` or `.forfeit`, this undoes that, re-entering you into the race.\n`.time` - Get the current elapsed time of the race."
value: "`.done`/`.d` - Indicate that you have finished the race.\n`.forfeit`/`.f` - Forfeit the race.\n`.notdone`/`.n` - If you did `.done` or `.forfeit`, this undoes that, re-entering you into the race.\n`.time`/`.t` - Get the current elapsed time of the race."
},
{
name: "Race Room Commands - After the Race",
Expand Down
1 change: 1 addition & 0 deletions node/src/discord/commands/t.js
@@ -0,0 +1 @@
module.exports = require("./time");
29 changes: 24 additions & 5 deletions node/src/discord/index.js
Expand Up @@ -9,17 +9,21 @@ const DiscordJs = require("discord.js"),
discord = new DiscordJs.Client({
intents: [
DiscordJs.IntentsBitField.Flags.Guilds,
DiscordJs.IntentsBitField.Flags.GuildMessages
DiscordJs.IntentsBitField.Flags.GuildMessages,
DiscordJs.IntentsBitField.Flags.MessageContent
],
partials: [DiscordJs.Partials.Channel]
}),
messageParse = /\.(?<command>[a-z]+)\s*(?<parameters>.*)/i;
messageParse = /^\.(?<command>[a-z]+)\s*(?<parameters>.*)/i;

let readied = false;

/** @type {DiscordJs.CategoryChannel} */
let raceCategory;

/** @type {DiscordJs.TextChannel} */
let resultsChannel;

/** @type {DiscordJs.Guild} */
let sprintGuild;

Expand Down Expand Up @@ -70,6 +74,20 @@ class Discord {
return raceCategory;
}

// ## # ## # ##
// # # # # # #
// ### ## ### # # # ### ### # ### ### ### ### ## #
// # # # ## ## # # # # ## # # # # # # # # # # ## #
// # ## ## # # # # ## # # # # # ## # # # # ## #
// # ## ### ### ### ## ### ## # # # # # # # # ## ###
/**
* Returns the results channel.
* @returns {DiscordJs.TextChannel} The results channel.
*/
static get resultsChannel() {
return resultsChannel;
}

// # # # ### ##
// # # # # # # # #
// ### ### ### # # # # ## # ##
Expand Down Expand Up @@ -105,7 +123,8 @@ class Discord {
readied = true;
}

raceCategory = /** @type {DiscordJs.CategoryChannel} */ (sprintGuild.channels.cache.find((r) => r.name === "Race Rooms")); // eslint-disable-line @stylistic/no-extra-parens
raceCategory = /** @type {DiscordJs.CategoryChannel} */ (sprintGuild.channels.cache.find((c) => c.name === "Race Rooms")); // eslint-disable-line @stylistic/no-extra-parens
resultsChannel = /** @type {DiscordJs.TextChannel} */ (sprintGuild.channels.cache.find((c) => c.name === "racebot-results")); // eslint-disable-line @stylistic/no-extra-parens
staffRole = sprintGuild.roles.cache.find((r) => r.name === "SPRINT Staff");
});

Expand Down Expand Up @@ -190,7 +209,7 @@ class Discord {
* @returns {Promise<DiscordJs.TextChannel>} A promise that returns the new channel.
*/
static async createNumberedChannel(name) {
const channelSuffixes = sprintGuild.channels.cache.filter((c) => c.name.startsWith(name)).map((c) => parseInt(c.name.split("-")[1], 10)).sort((a, b) => a - b);
const channelSuffixes = sprintGuild.channels.cache.filter((c) => c.parentId && c.parentId === raceCategory.id && c.name.startsWith(name)).map((c) => parseInt(c.name.split("-")[1], 10)).sort((a, b) => a - b);

let suffix = 1;
for (let i = 0; i < channelSuffixes.length; i++) {
Expand Down Expand Up @@ -273,7 +292,7 @@ class Discord {

let msg;
try {
msg = await Discord.richQueue(Discord.embedBuilder({description: message}), channel);
msg = await channel.send(message);
} catch {}
return msg;
}
Expand Down
19 changes: 11 additions & 8 deletions node/src/models/countdown.js
Expand Up @@ -31,12 +31,15 @@ class Countdown {

this.race.start = Date.now() + 10000;

Discord.embedBuilder({
title: "Race Starts in 10 Seconds",
description: "Everyone is ready! The race will start in 10 seconds!"
});

setTimeout(async () => {
await Discord.richQueue(
Discord.embedBuilder({
title: "Race Starts in 10 Seconds",
description: "Everyone is ready! The race will start in 10 seconds!"
}),
this.race.channel
);

if (this.cancelled) {
return;
}
Expand Down Expand Up @@ -72,17 +75,17 @@ class Countdown {
// ## # # # # ## ## ###
/**
* Cancels a countdown.
* @returns {void}
* @returns {Promise} A promise that resolves when the countdown is cancelled.
*/
cancel() {
async cancel() {
if (this.race.started) {
return;
}

this.cancelled = true;
this.race.start = 0;

Discord.queue("Countdown aborted.", this.race.channel);
await Discord.queue("Countdown aborted.", this.race.channel);
}
}

Expand Down
97 changes: 80 additions & 17 deletions node/src/models/race.js
Expand Up @@ -34,6 +34,8 @@ class Race {

await race.setup();

race.channel.setTopic("Type .help or .h for help. See the pinned post for current race status.", "Creating a race room.");

Race.races.push(race);
return race;
}
Expand Down Expand Up @@ -150,6 +152,11 @@ class Race {
* @returns {Promise} A promise that resolves when the race room is closed.
*/
async close(member) {
// Record the race results, if there were any.
if (this.end > 0) {
await postResult();
}

// Remove this race from the races array.
Race.races = Race.races.filter((r) => r !== this);

Expand Down Expand Up @@ -231,7 +238,7 @@ class Race {
player.finish = Date.now();

// Get the number of finished racers.
const finishedPlayers = this.players.filter((p) => p.finish > 0),
const finishedPlayers = this.players.filter((p) => p.finish > 0).sort((a, b) => a.finish - b.finish),
finished = finishedPlayers.length;

const ordinal = finished % 100 >= 11 && finished % 100 <= 13 ? "th" : finished % 10 === 1 ? "st" : finished % 10 === 2 ? "nd" : finished % 10 === 3 ? "rd" : "th";
Expand Down Expand Up @@ -311,7 +318,7 @@ class Race {
}

if (this.countdown) {
this.countdown.cancel();
await this.countdown.cancel();
this.countdown = null;
}

Expand All @@ -321,7 +328,7 @@ class Race {

await Discord.richQueue(
Discord.embedBuilder({
title: `${member} Entered`,
title: `${member.displayName} Entered`,
description: `${member} has entered! There ${this.players.length === 1 ? "is" : "are"} now ${this.players.length} ${this.players.length === 1 ? "entry" : "entries"}, with ${this.players.filter((p) => !p.ready).length} remaining to be ready.`
}),
this.channel
Expand Down Expand Up @@ -411,7 +418,7 @@ class Race {
this.end = Date.now();

// Get the finished and forfeited racers.
const finishedPlayers = this.players.filter((p) => p.finish > 0),
const finishedPlayers = this.players.filter((p) => p.finish > 0).sort((a, b) => a.finish - b.finish),
forfeitPlayers = this.players.filter((p) => p.forfeit);

const message = Discord.embedBuilder({
Expand Down Expand Up @@ -483,6 +490,14 @@ class Race {

this.players = this.players.filter((p) => p.discordId !== kickedMember.id);

await Discord.richQueue(
Discord.embedBuilder({
title: "Player Kicked",
description: `${kickedMember} has been removed from the race.`
}),
this.channel
);

if (this.start === 0) {
// Get the number of unreadied racers.
const unreadied = this.players.filter((p) => !p.ready).length;
Expand All @@ -498,7 +513,7 @@ class Race {
this.end = Date.now();

// Get the finished and forfeited racers.
const finishedPlayers = this.players.filter((p) => p.finish > 0),
const finishedPlayers = this.players.filter((p) => p.finish > 0).sort((a, b) => a.finish - b.finish),
forfeitPlayers = this.players.filter((p) => p.forfeit);

const message = Discord.embedBuilder({
Expand Down Expand Up @@ -598,6 +613,49 @@ class Race {
return player;
}

// # ### ## #
// # # # # #
// ### ## ### ### # # ## ### # # # ###
// # # # # ## # ### # ## ## # # # #
// # # # # ## # # # ## ## # # # #
// ### ## ### ## # # ## ### ### ### ##
// #
/**
* Posts the results to the results channel.
* @returns {Promise} A promise that resolves when the results have been posted.
*/
async postResult() {
const message = Discord.embedBuilder({
title: "Completed Race",
description: `Race completed <t:${Math.floor(this.end / 1000)}:R>\nSeed: ${this.seed}`,
fields: []
});

const finishedPlayers = this.players.filter((p) => p.finish > 0).sort((a, b) => a.finish - b.finish),
forfeitPlayers = this.players.filter((p) => p.forfeit);

if (finishedPlayers.length > 0) {
message.addFields({
name: "Standings",
value: finishedPlayers.map((p, index) => `${index + 1}) **${Race.formatTime(p.finish - this.start)}** - <@${p.discordId}>`).join("\n"),
inline: true
});
}

if (forfeitPlayers.length > 0) {
message.addFields({
name: "Forfeited Players",
value: forfeitPlayers.map((p) => `<@${p.discordId}>`).join("\n"),
inline: true
});
}

await Discord.richQueue(
message,
Discord.resultsChannel
);
}

// #
// #
// ### ## ### ### # #
Expand Down Expand Up @@ -628,14 +686,14 @@ class Race {

await Discord.richQueue(
Discord.embedBuilder({
title: `${member} Ready`,
title: `${member.displayName} Ready`,
description: `${member} has is now ready! There ${this.players.length === 1 ? "is" : "are"} ${this.players.length} ${this.players.length === 1 ? "entry" : "entries"}, with ${this.players.filter((p) => !p.ready).length} remaining to be ready.`
}),
this.channel
);
} else {
if (this.countdown) {
this.countdown.cancel();
await this.countdown.cancel();
this.countdown = null;
}

Expand All @@ -646,7 +704,7 @@ class Race {

await Discord.richQueue(
Discord.embedBuilder({
title: `${member} Entered and Ready`,
title: `${member.displayName} Entered and Ready`,
description: `${member} has entered and is now ready! There ${this.players.length === 1 ? "is" : "are"} ${this.players.length} ${this.players.length === 1 ? "entry" : "entries"}, with ${this.players.filter((p) => !p.ready).length} remaining to be ready.`
}),
this.channel
Expand Down Expand Up @@ -700,11 +758,16 @@ class Race {
* @returns {Promise} A promise that resolves when the race has been setup.
*/
async setup() {
if (this.end > 0) {
await this.postResult();
}

this.seed = Math.floor(Math.random() * 100000000).toString().padStart(8, "0");
this.players = [];
this.started = false;
this.start = 0;
this.end = 0;
this.countdown = null;

this.pinnedPost = await Discord.richQueue(
Discord.embedBuilder({
Expand Down Expand Up @@ -772,7 +835,7 @@ class Race {
return;
}

Discord.queue(`The current race time is **${Race.formatTime(Date.now() - this.start)}**.`, this.channel);
await Discord.queue(`The current race time is **${Race.formatTime(Date.now() - this.start)}**.`, this.channel);
}

// #
Expand Down Expand Up @@ -812,15 +875,15 @@ class Race {
}

if (this.countdown) {
this.countdown.cancel();
await this.countdown.cancel();
this.countdown = null;
}

player.ready = false;

await Discord.richQueue(
Discord.embedBuilder({
title: `${member} Unready`,
title: `${member.displayName} Unready`,
description: `${member} is no longer ready. There ${this.players.length === 1 ? "is" : "are"} ${this.players.length} ${this.players.length === 1 ? "entry" : "entries"}, with ${this.players.filter((p) => !p.ready).length} remaining to be ready.`
}),
this.channel
Expand Down Expand Up @@ -898,7 +961,7 @@ class Race {
// Build message.
const message = Discord.embedBuilder({
title: "Race Starting",
description: `Seed: ${this.seed}\nStarting <t:${this.start}:R>`,
description: `Seed: ${this.seed}\nStarting <t:${Math.floor(this.start / 1000)}:R>`,
fields: [
{
name: "Players",
Expand Down Expand Up @@ -929,7 +992,7 @@ class Race {

const message = Discord.embedBuilder({
title: "Race Started",
description: `Seed: ${this.seed}\nStarted <t:${this.start}:R>`,
description: `Seed: ${this.seed}\nStarted <t:${Math.floor(this.start / 1000)}:R>`,
fields: []
});

Expand Down Expand Up @@ -959,7 +1022,7 @@ class Race {

message.addFields({
name: "Commands",
value: "`.done` or `.d` - Indicate you completed the race\n`.forfeit` or `.f` - Forfeit the race\n`.undone` or `.u` - Reenter the race if you accidentally completed or forfeited\n`.time` - Get the time elapsed in the race."
value: "`.done` or `.d` - Indicate you completed the race\n`.forfeit` or `.f` - Forfeit the race\n`.undone` or `.u` - Reenter the race if you accidentally completed or forfeited\n`.time` or `.t` - Get the time elapsed in the race."
});

await Discord.richEdit(this.pinnedPost, message);
Expand All @@ -978,7 +1041,7 @@ class Race {

const message = Discord.embedBuilder({
title: "Race Complete",
description: `Seed: ${this.seed}\nStarted <t:${this.start}:R>\nEnded <t:${this.end}:R>`,
description: `Seed: ${this.seed}\nStarted <t:${Math.floor(this.start / 1000)}:R>\nEnded <t:${Math.floor(this.end / 1000)}:R>`,
fields: []
});

Expand Down Expand Up @@ -1048,7 +1111,7 @@ class Race {

await Discord.richQueue(
Discord.embedBuilder({
title: `${member} Withdrawn`,
title: `${member.displayName} Withdrawn`,
description: `${member} has withdrawn. There ${this.players.length === 1 ? "is" : "are"} now ${this.players.length} ${this.players.length === 1 ? "entry" : "entries"}, with ${remainingPlayers.length} remaining to be ready.`
}),
this.channel
Expand All @@ -1059,7 +1122,7 @@ class Race {
}

if (this.countdown && this.players.length < 2) {
this.countdown.cancel();
await this.countdown.cancel();
this.countdown = null;
}

Expand Down

0 comments on commit 3139307

Please sign in to comment.