From c59b5fee9832a417d71c617ff9411e9b1dd392f2 Mon Sep 17 00:00:00 2001 From: dakedres Date: Fri, 19 May 2023 16:40:16 -0600 Subject: [PATCH] Add description ranges/outcomes --- src/constants.js | 6 ++++ src/index.js | 74 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 src/constants.js diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 0000000..7a69aa1 --- /dev/null +++ b/src/constants.js @@ -0,0 +1,6 @@ +const constants = { +rollRegex: /^(\d+)?([dhl])(\d+)(\s*([+\-*x\/])\s*(\d+))?/, +descriptionRegex: /\s*(\d+(-\d+)?)?([^;\n]+)/g +} + +export default constants \ No newline at end of file diff --git a/src/index.js b/src/index.js index aa7d983..0e6504a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,43 +1,81 @@ import { Client, GatewayIntentBits } from 'discord.js'; import * as dotenv from 'dotenv' +import constants from './constants.js'; dotenv.config() -const regex = /^(\d+)?([dhl])(\d+)(\s*([+\-*x\/])\s*(\d+))?(.*?)$/ - const replies = new Map() -const parseMatch = match => { +const parseRoll = content => { + let match = constants.rollRegex.exec(content.trim()) + + if(match == null) + return + let [ count, mode, size, modifierString, operation, - modifier, - description + modifier ] = match.slice(1) + let description = content.slice(match[0].length) + return { count: count ? parseInt(count) : 1, mode, size: parseInt(size), operation, modifier: modifier ? parseInt(modifier) : undefined, - description: description.trim() + descriptionConditions: description && parseDescription(description) } } +const parseDescription = description => { + let conditions = [], + match + + while((match = constants.descriptionRegex.exec(description)) !== null) { + // Prevent infinite loops if there's somehow a zero-length match + if(match.index == constants.descriptionRegex.lastIndex) + regex.lastIndex++ + + let [ + range, + upperRange, + content + ] = match.slice(1) + + conditions.push({ + range: range && { + lower: range[0], + upper: upperRange ? upperRange[1] : range[0] + }, + content: content.trim() + }) + } + + return conditions +} + const handleMessage = (message, respond) => { - let match = regex.exec(message.content.trim()) + let dice = parseRoll(message.content) - if(match == null) - return + if(dice == undefined) + return // No dice - let dice = parseMatch(match) - - if(dice.size > 256) { + if(dice.size > 255) { respond('That die is way too big... .-.') return + } else if(dice.size < 2) { + respond('I cannot even fathom a die with that geometry ;-;') + return + } + + if(dice.count > 100) { + respond('I don\'t have that many dice O_O') + return } let rolls = [ ...crypto.getRandomValues(new Uint8Array(dice.count) ) ] @@ -80,8 +118,12 @@ const handleMessage = (message, respond) => { break } - if(dice.description) - response += `'${dice.description}', ` + if(dice.descriptionConditions) { + for(let { range, content } of dice.descriptionConditions) { + if(!range || result >= range.lower && result <= range.upper) + response += `'${content}', ` + } + } response += `\` ${result} \` \u27F5 [${rolls.join(', ')}] ${dice.count + dice.mode + dice.size}` @@ -141,8 +183,8 @@ client.on('messageUpdate', async (oldMessage, newMessage) => { let { id } = replies.get(newMessage.id) newMessage.channel.messages.fetch(id) - .then(reply => rehandleMessage(newMessage, reply)) - .catch(err => messageCycle(newMessage, ) ) + .then(reply => rehandleMessage(newMessage, reply) ) + .catch(err => messageCycle(newMessage) ) } else { messageCycle(newMessage) }