falgames
Version:
Falgames is a helpful package to enhance your discord bot with fun and interactive minigames
155 lines (136 loc) • 7.23 kB
JavaScript
import { EmbedBuilder } from "discord.js"
import events from "node:events"
/**
* This class allows you to create and manage a Fast Type game in Discord, including handling user interactions and game logic.
*
* @class FastType
* @param {FastTypeOptions} options - The options for the Fast Type game.
*
* @extends {approve}
* @fires FastType#gameOver
* @typedef {Object} FastTypeOptions
*/
export class FastType extends events {
/**
* Represents a FastType game.
* @constructor
* @param {Object} options - The options the FastType game.
* @param {boolean} [options.isSlashGame=false] - Whether the game is played using slash commands.
* @param {Object} options.message - The message object associated with the game.
* @param {Object} [options.embed={}] - The embed options for the game.
* @param {string} [options.embed.title='Fast Type'] - The title of the embed.
* @param {string} [options.embed.color='#551476'] - The color of the embed.
* @param {string} [options.embed.description='You have {time} seconds to type the sentence below.'] - The description of the embed.
* @param {string} [options.embed.sentenceTitle='Sentence'] - The title of the sentence in the embed.
* @param {string} [options.sentence='Some really cool sentence to fast type.'] - The sentence to be typed.
* @param {string} [options.winMessage='You won! You finished the type race in {time} seconds with word per minute of {wpm}.'] - The win message.
* @param {string} [options.loseMessage='You lost! You didn\'t type the correct sentence in time.'] - The lose message.
* @param {string} [options.timeMessage='You lost! You didn\'t type fast enough.';] - The lose message by time.
* @param {number} [options.timeoutTime=60000] - The timeout time for the game.
*/
constructor(options = {}) {
if (!options.isSlashGame) options.isSlashGame = false
if (!options.message) throw new TypeError("NO_MESSAGE: No message option was provided.")
if (typeof options.message !== "object") throw new TypeError("INVALID_MESSAGE: message option must be an object.")
if (typeof options.isSlashGame !== "boolean")
throw new TypeError("INVALID_COMMAND_TYPE: isSlashGame option must be a boolean.")
if (!options.embed) options.embed = {}
if (!options.embed.title) options.embed.title = "Fast Type"
if (!options.embed.color) options.embed.color = "#551476"
if (!options.embed.description) options.embed.description = "You have {time} seconds to type the sentence below."
if (!options.embed.sentenceTitle) options.embed.sentenceTitle = "Sentence"
if (!options.sentence) options.sentence = "Some really cool sentence to fast type."
if (!options.winMessage)
options.winMessage = "You won! You finished the type race in {time} seconds with word per minute of {wpm}."
if (!options.loseMessage) options.loseMessage = "You lost! You didn't type the correct sentence in time."
if (!options.timeMessage) options.timeMessage = "You lost! You didn't type fast enough."
if (!options.timeoutTime) options.timeoutTime = 60000
if (typeof options.embed !== "object") throw new TypeError("INVALID_EMBED: embed option must be an object.")
if (typeof options.embed.title !== "string") throw new TypeError("INVALID_EMBED: embed title must be a string.")
if (typeof options.embed.description !== "string")
throw new TypeError("INVALID_DESCRIPTION: embed description must be a string.")
if (typeof options.embed.sentenceTitle !== "string")
throw new TypeError("INVALID_TEXT: embed sentenceTitle must be a string.")
if (typeof options.sentence !== "string") throw new TypeError("INVALID_SENTENCE: sentence must be a string.")
if (typeof options.winMessage !== "string")
throw new TypeError("INVALID_MESSAGE: Win message option must be a string.")
if (typeof options.loseMessage !== "string")
throw new TypeError("INVALID_MESSAGE: Lose message option must be a string.")
if (typeof options.timeMessage !== "string")
throw new TypeError("INVALID_MESSAGE: Time message option must be a string.")
if (typeof options.timeoutTime !== "number")
throw new TypeError("INVALID_TIME: Timeout time option must be a number.")
super()
this.options = options
this.message = options.message
this.timeTaken = null
this.wpm = 0
}
async sendMessage(content) {
if (this.options.isSlashGame) return await this.message.editReply(content)
else return await this.message.channel.send(content)
}
async startGame() {
if (this.options.isSlashGame || !this.message.author) {
if (!this.message.deferred) await this.message.deferReply().catch((e) => {})
this.message.author = this.message.user
this.options.isSlashGame = true
}
const embed = new EmbedBuilder()
.setColor(this.options.embed.color)
.setTitle(this.options.embed.title)
.setDescription(this.options.embed.description.replace("{time}", this.options.timeoutTime / 1000))
.addFields({ name: this.options.embed.sentenceTitle, value: this.options.sentence })
.setAuthor({ name: this.message.author.tag, iconURL: this.message.author.displayAvatarURL({ dynamic: true }) })
const msg = await this.sendMessage({ embeds: [embed] })
const startTime = Date.now()
const filter = (m) => m.author.id === this.message.author.id
const collector = this.message.channel.createMessageCollector({ time: this.options.timeoutTime, filter: filter })
collector.on("collect", (message) => {
this.timeTaken = Date.now() - startTime
this.wpm = Math.floor(message.content.trim().length / (this.timeTaken / 60000) / 5)
const userInput = message.content.toLowerCase().trim()
const correctSentence = this.options.sentence.toLowerCase()
if (userInput === correctSentence) {
collector.stop("win")
} else {
if (this.timeTaken >= this.options.timeoutTime) {
collector.stop("time")
} else {
collector.stop("lose")
}
}
})
/*
I spent 12 hours messing with this part of the code (losing my sanity) to discover that there was a simple function that fixed this in minutes :D
*/
collector.on("end", (collected, reason) => {
if (reason === "win") {
this.gameOver(msg, true, false)
} else if (reason === "time") {
this.gameOver(msg, false, true)
} else {
this.gameOver(msg, false, false)
}
})
}
gameOver(msg, result, timeRanOut) {
let GameOverMessage = result
? this.options.winMessage
: timeRanOut
? this.options.timeMessage
: this.options.loseMessage
GameOverMessage = GameOverMessage.replace("{time}", Math.floor(this.timeTaken / 1000)).replace("{wpm}", this.wpm)
this.emit("gameOver", {
result: result ? "win" : "lose",
FasttypeGame: { player: this.message.author, timeTaken: Math.floor(this.timeTaken / 1000), wpm: this.wpm },
})
const embed = new EmbedBuilder()
.setColor(this.options.embed.color)
.setTitle(this.options.embed.title)
.setDescription(GameOverMessage)
.setAuthor({ name: this.message.author.tag, iconURL: this.message.author.displayAvatarURL({ dynamic: true }) })
.setTimestamp()
return msg.edit({ embeds: [embed] })
}
}