Skip to content

Commit

Permalink
Feature: End message configuration (#80)
Browse files Browse the repository at this point in the history
Allows the end message to be determined by a field in the database. This allows the end message to be configurable without a restart and allows for events to be widely broadcasted. This also implements the &phrase command, which allows for these phrases to be edited by commands.
  • Loading branch information
zeroclutch committed Sep 27, 2023
1 parent a6d3c6f commit bc2c8a6
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 15 deletions.
136 changes: 136 additions & 0 deletions commands/dev/phrase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import BotCommand from '../../types/command/BotCommand.js'
import { GAMEBOT_PERMISSIONS } from '../../config/types.js'
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonStyle, Message } from 'discord.js'
import options from '../../config/options.js'
import { ButtonBuilder } from '@discordjs/builders'

export default new BotCommand({
name: 'phrase',
aliases: ['phrases'],
description: 'Sets the end message',
category: 'dev',
permissions: [GAMEBOT_PERMISSIONS.OWNER],
dmCommand: true,
args: [{
name: 'action',
type: ApplicationCommandOptionType.String,
required: true,
description: `The action to take:
- \`list\` lists the current active messages
- \`add\` lists the current active messages
- \`delete\` deletes an item from the list
- \`broadcast\` sets the global broadcast message`,
}],
/**
* @param {Message} msg
* @param {Array} args
*/
run: async function(msg, args) {
let action = args[0]
let phrase = args.slice(1).join(' ')

const collection = msg.client.database.collection('status')
let list = await collection.findOne({ type: 'phrases' })

const confirm = (message) => {
return new Promise((resolve, reject) => {
const filter = i => i.customId && i.user.id === msg.author.id
msg.reply({
content: message,
components: [
new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('confirm')
.setLabel('Confirm')
.setStyle(ButtonStyle.Success),
new ButtonBuilder()
.setCustomId('cancel')
.setLabel('Cancel')
.setStyle(ButtonStyle.Secondary),
)
],
})
.then(m => m.awaitMessageComponent({ filter, time: 60_000 }))
.then(resolve)
})
}

switch(action.toLowerCase()) {
default:
case 'list':
msg.reply({
embeds: [{
title: 'End Phrases',
fields: [{
name: 'Phrase list',
value: list.phrases.map((phrase, i) => `**[${i + 1}]** ${phrase}`).join('\n\n')
},
{
name: 'Broadcast phrase',
value: list.broadcastPhrase || '*No broadcast phrase set*'
}],
color: options.colors.info
}]
})
break
case 'add':
confirm(`Are you sure you'd like to add the following phrase?\n\n"${phrase}"`)
.then(i => {
// Confirm action
if(i.customId === 'confirm') {
collection.updateOne(
{ type: 'phrases' },
{ $push: { phrases: phrase } }
).then(() => i.reply('Added phrase!'))
} else if(i.customId === 'cancel') {
i.reply('Phrase not added.')
}
})

break
case 'delete':
let index = parseInt(args[1]) - 1

if(!isNaN(index) || list?.phrases[index]) {
confirm(`Are you sure you'd like to delete the following phrase?\n\n"${list.phrases[index]}"`)
.then(i => {
if(i.customId === 'confirm') {
// Remove and update the database
list.phrases.splice(index, 1)
collection.updateOne(
{ type: 'phrases' },
{ $set: { phrases: list.phrases } }
).then(() => i.reply('Deleted phrase!'))
} else if(i.customId === 'cancel') {
i.reply('Phrase not deleted.')
}
})
} else {
msg.channel.send(`Invalid phrase index to delete.`)
}

break
case 'broadcast':
let confirmationMessage = `Are you sure you'd like to broadcast the following phrase?\n\n"${phrase}"`
if(!phrase) {
confirmationMessage = `Are you sure you'd like to reset the broadcast message?`
}

confirm(confirmationMessage)
.then(i => {
// Confirm action
if(i.customId === 'confirm') {
collection.updateOne(
{ type: 'phrases' },
{ $set: { broadcastPhrase: phrase } }
).then(() => i.reply('Broadcast phrase set!'))
} else if(i.customId === 'cancel') {
i.reply('Phrase not broadcast.')
}
})

break
}
}
})
8 changes: 4 additions & 4 deletions games/Chess/classes/Chess.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,10 @@ export default class Chess extends Game {
}))
}

analyzeBoard(side) {
async analyzeBoard(side) {
if(this.status.isStalemate || this.status.isRepetition) {
this.importGameToLichess('draw')
this.end(undefined, `The game is a draw.\nTo play games with the community, [join our server](${options.serverInvite}?ref=gameEnd)!`)
this.end(undefined, `The game is a draw.\n${(await this.client.getEndPhrase())}`)
this.over = true
}

Expand Down Expand Up @@ -351,8 +351,8 @@ export default class Chess extends Game {
} while(!this.over)
}

finish(id) {
async finish(id) {
let winner = this.players.find(player => player.id == id)
this.end(winner, `${winner.user} has won!\nTo play games with the community, [join our server](${options.serverInvite}?ref=gameEnd)!`)
this.end(winner, `${winner.user} has won!\n${(await this.client.getEndPhrase())}`)
}
}
4 changes: 2 additions & 2 deletions games/Connect Four/classes/ConnectFour.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,9 @@ export default class ConnectFour extends Game {
this.finish(this.getWinner())
}

finish(id) {
async finish(id) {
let winner = this.players.find(player => player.id == id)
this.end(winner, `${winner.user} has won! ${this.renderBoard()}\nTo play games with the community, [join our server](${options.serverInvite}?ref=gameEnd)!`)
this.end(winner, `${winner.user} has won! ${this.renderBoard()}\n${(await this.client.getEndPhrase())}`)
}


Expand Down
5 changes: 3 additions & 2 deletions games/_Game/classes/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ export default class Game extends EventEmitter {
* @param {Object|Array<Object>} winners The game winner
* @param {String} endPhrase The message to be sent at the end of the game.
*/
end(winners, endPhrase) {
async end(winners, endPhrase) {
this.beforeEnd()
this.ending = true
this.stage = 'over'
Expand Down Expand Up @@ -925,7 +925,8 @@ export default class Game extends EventEmitter {
endPhrase = ''
}

endPhrase += `\nTo play games with the community, [join our server](${options.serverInvite}?ref=gameEnd)!`
// Add game end message
endPhrase += `\n${(await this.client.getEndPhrase())}`
}

const gameEmbed = {
Expand Down
34 changes: 27 additions & 7 deletions scripts/clientSetup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import fs from 'fs'
import path from 'path'
import logger from 'gamebot/logger'

import options from '../config/options.js'

// import GameManager from '../types/games/GameManager.js'
import CommandHandler from '../types/command/CommandHandler.js'
import TournamentManager from '../types/games/TournamentManager.js'
Expand Down Expand Up @@ -131,15 +133,33 @@ const database = async client => {
// configure downtime notifications
client.getTimeToDowntime = () => {
return new Promise((resolve, reject) => {
client.database.collection('status').findOne( { type: 'downtime' }).then((data, err) => {
if(err || !data) {
reject(logger.error(err))
return
}
resolve(data.downtimeStart - Date.now())
})
client.database.collection('status').findOne( { type: 'downtime' }).then((data, err) => {
if(err || !data) {
reject(logger.error(err))
return
}
resolve(data.downtimeStart - Date.now())
})
})
}

// configure end phrases
Object.defineProperty(client, 'getEndPhrase', {
value: async () => {
const DEFAULT_END_PHRASE = `To play games with the community, [join our server](${options.serverInvite}?ref=gameEnd)!`

const data = await client.database.collection('status').findOne({ type: 'phrases' })
let phrase = DEFAULT_END_PHRASE

if(data?.phrases) phrase = data.phrases[Math.floor(Math.random() * data.phrases.length)]
if(data?.broadcastPhrase && data.broadcastPhrase.length > 0) phrase = data.broadcastPhrase

return phrase
},
writable: false,
enumerable: true
})

}

export default {
Expand Down

0 comments on commit bc2c8a6

Please sign in to comment.