Change tab size
This commit is contained in:
parent
7912b455e9
commit
ece60db183
116
src/constants.js
116
src/constants.js
@ -1,65 +1,65 @@
|
|||||||
export default {
|
export default {
|
||||||
rollRegex: /^(\d+)?([dhlfb])(\d+)(\s*([+\-*x\/])\s*(\d+))?/,
|
rollRegex: /^(\d+)?([dhlfb])(\d+)(\s*([+\-*x\/])\s*(\d+))?/,
|
||||||
optionRollRegex: /^(\d+)?(([dhlfb])(\d+))?(\s*([+\-*x\/])\s*(\d+))?/,
|
optionRollRegex: /^(\d+)?(([dhlfb])(\d+))?(\s*([+\-*x\/])\s*(\d+))?/,
|
||||||
descriptionRegex: /\s*((\d*-\d*)|(\d+))?([^;\n]+)/g,
|
descriptionRegex: /\s*((\d*-\d*)|(\d+))?([^;\n]+)/g,
|
||||||
macroNameRegex: /^[a-z0-9]+$/,
|
macroNameRegex: /^[a-z0-9]+$/,
|
||||||
|
|
||||||
commands: {
|
commands: {
|
||||||
about: {
|
about: {
|
||||||
name: 'about',
|
name: 'about',
|
||||||
description: "Get information about dicedicedice"
|
description: "Get information about dicedicedice"
|
||||||
},
|
},
|
||||||
|
|
||||||
macro: {
|
macro: {
|
||||||
name: 'macro',
|
name: 'macro',
|
||||||
description: "Manage macros",
|
description: "Manage macros",
|
||||||
'dm_permission': false,
|
'dm_permission': false,
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: 'add',
|
name: 'add',
|
||||||
description: "Define a dice macro",
|
description: "Define a dice macro",
|
||||||
type: 1, // Sub command
|
type: 1, // Sub command
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: "name",
|
name: "name",
|
||||||
description: "Name of the macro",
|
description: "Name of the macro",
|
||||||
type: 3, // String
|
type: 3, // String
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "dice",
|
name: "dice",
|
||||||
description: "The dice expression to save as a macro",
|
description: "The dice expression to save as a macro",
|
||||||
type: 3, // String
|
type: 3, // String
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'remove',
|
name: 'remove',
|
||||||
description: "Remove a macro",
|
description: "Remove a macro",
|
||||||
type: 1, // Sub command
|
type: 1, // Sub command
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: "name",
|
name: "name",
|
||||||
description: "Name of the macro",
|
description: "Name of the macro",
|
||||||
type: 3, // String
|
type: 3, // String
|
||||||
required: true,
|
required: true,
|
||||||
autocomplete: true,
|
autocomplete: true,
|
||||||
getAutocomplete: interaction => {
|
getAutocomplete: interaction => {
|
||||||
let macros = globalThis.macroCache.get(interaction.guild.id)
|
let macros = globalThis.macroCache.get(interaction.guild.id)
|
||||||
|
|
||||||
return macros ? Object.keys(macros) : []
|
return macros ? Object.keys(macros) : []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
iconUrl: 'https://github.com/Dakedres/dicedicedice/raw/main/assets/eater-transparent.png',
|
iconUrl: 'https://github.com/Dakedres/dicedicedice/raw/main/assets/eater-transparent.png',
|
||||||
|
|
||||||
errorMessage: error => `\
|
errorMessage: error => `\
|
||||||
Something went wrong trying to execute that command.
|
Something went wrong trying to execute that command.
|
||||||
\`\`\`fix
|
\`\`\`fix
|
||||||
${error.toString()}
|
${error.toString()}
|
||||||
@ -67,7 +67,7 @@ ${error.toString()}
|
|||||||
If this issue persists please report it here: <https://github.com/Dakedres/dicedicedice/issues>\
|
If this issue persists please report it here: <https://github.com/Dakedres/dicedicedice/issues>\
|
||||||
`,
|
`,
|
||||||
|
|
||||||
aboutMessage: (guildCount) => `\
|
aboutMessage: (guildCount) => `\
|
||||||
A discord bot for metaphorically "rolling dice"/generating random values. Made for use with Weaverdice systems.
|
A discord bot for metaphorically "rolling dice"/generating random values. Made for use with Weaverdice systems.
|
||||||
|
|
||||||
Present in ~${guildCount} guilds!
|
Present in ~${guildCount} guilds!
|
||||||
|
698
src/index.js
698
src/index.js
@ -11,508 +11,508 @@ globalThis.macroCache = new Map()
|
|||||||
const db = new ClassicLevel('./db')
|
const db = new ClassicLevel('./db')
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
intents: [
|
intents: [
|
||||||
GatewayIntentBits.Guilds,
|
GatewayIntentBits.Guilds,
|
||||||
GatewayIntentBits.GuildMessages,
|
GatewayIntentBits.GuildMessages,
|
||||||
GatewayIntentBits.MessageContent,
|
GatewayIntentBits.MessageContent,
|
||||||
GatewayIntentBits.DirectMessages
|
GatewayIntentBits.DirectMessages
|
||||||
],
|
],
|
||||||
partials: [
|
partials: [
|
||||||
Partials.Channel
|
Partials.Channel
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
const rest = new REST().setToken(process.env.DISCORD_TOKEN)
|
const rest = new REST().setToken(process.env.DISCORD_TOKEN)
|
||||||
|
|
||||||
const ParseRollInt = (value, defaultValue) =>
|
const ParseRollInt = (value, defaultValue) =>
|
||||||
value ? parseInt(value) : defaultValue
|
value ? parseInt(value) : defaultValue
|
||||||
|
|
||||||
const ParseOptionRoll = expression => {
|
const ParseOptionRoll = expression => {
|
||||||
let match = constants.optionRollRegex.exec(expression.trim())
|
let match = constants.optionRollRegex.exec(expression.trim())
|
||||||
|
|
||||||
let [
|
let [
|
||||||
count,
|
count,
|
||||||
modeSize,
|
modeSize,
|
||||||
mode,
|
mode,
|
||||||
size,
|
size,
|
||||||
operationModifier,
|
operationModifier,
|
||||||
operation,
|
operation,
|
||||||
modifier
|
modifier
|
||||||
] = match
|
] = match
|
||||||
.slice(1)
|
.slice(1)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
count: ParseRollInt(count),
|
count: ParseRollInt(count),
|
||||||
mode,
|
mode,
|
||||||
size: ParseRollInt(size),
|
size: ParseRollInt(size),
|
||||||
operation,
|
operation,
|
||||||
modifier: ParseRollInt(modifier),
|
modifier: ParseRollInt(modifier),
|
||||||
descriptionConditions: PullDescription(expression, match)
|
descriptionConditions: PullDescription(expression, match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ParseRoll = expression => {
|
const ParseRoll = expression => {
|
||||||
let match = constants.rollRegex.exec(expression.trim())
|
let match = constants.rollRegex.exec(expression.trim())
|
||||||
|
|
||||||
if(match == null)
|
if(match == null)
|
||||||
return
|
return
|
||||||
|
|
||||||
let [
|
let [
|
||||||
count,
|
count,
|
||||||
mode,
|
mode,
|
||||||
size,
|
size,
|
||||||
modifierString,
|
modifierString,
|
||||||
operation,
|
operation,
|
||||||
modifier
|
modifier
|
||||||
] = match.slice(1)
|
] = match.slice(1)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
count: ParseRollInt(count, 1),
|
count: ParseRollInt(count, 1),
|
||||||
mode,
|
mode,
|
||||||
size: ParseRollInt(size),
|
size: ParseRollInt(size),
|
||||||
operation,
|
operation,
|
||||||
modifier: ParseRollInt(modifier),
|
modifier: ParseRollInt(modifier),
|
||||||
descriptionConditions: PullDescription(expression, match)
|
descriptionConditions: PullDescription(expression, match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PullDescription = (expression, match) => {
|
const PullDescription = (expression, match) => {
|
||||||
if(match[0].length == expression.length)
|
if(match[0].length == expression.length)
|
||||||
return
|
return
|
||||||
|
|
||||||
return ParseDescription(expression.slice(match[0].length))
|
return ParseDescription(expression.slice(match[0].length))
|
||||||
}
|
}
|
||||||
|
|
||||||
const ParseDescription = description => {
|
const ParseDescription = description => {
|
||||||
let conditions = []
|
let conditions = []
|
||||||
let match
|
let match
|
||||||
|
|
||||||
while((match = constants.descriptionRegex.exec(description)) !== null) {
|
while((match = constants.descriptionRegex.exec(description)) !== null) {
|
||||||
let range
|
let range
|
||||||
let [
|
let [
|
||||||
rangeExp,
|
rangeExp,
|
||||||
valueExp,
|
valueExp,
|
||||||
content
|
content
|
||||||
] = match.slice(2)
|
] = match.slice(2)
|
||||||
|
|
||||||
if(rangeExp) {
|
if(rangeExp) {
|
||||||
let split = rangeExp.split('-')
|
let split = rangeExp.split('-')
|
||||||
|
|
||||||
range = {
|
range = {
|
||||||
lower: ParseRollInt(split[0], -Infinity),
|
lower: ParseRollInt(split[0], -Infinity),
|
||||||
upper: ParseRollInt(split[1], Infinity)
|
upper: ParseRollInt(split[1], Infinity)
|
||||||
}
|
}
|
||||||
} else if(valueExp) {
|
} else if(valueExp) {
|
||||||
range = {
|
range = {
|
||||||
upper: valueExp,
|
upper: valueExp,
|
||||||
lower: valueExp
|
lower: valueExp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conditions.push({
|
conditions.push({
|
||||||
range,
|
range,
|
||||||
content: content.trim()
|
content: content.trim()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
}
|
}
|
||||||
|
|
||||||
const OnMessage = (message, respond) => {
|
const OnMessage = (message, respond) => {
|
||||||
let dice = ParseRoll(message.content)
|
let dice = ParseRoll(message.content)
|
||||||
|
|
||||||
if(dice == undefined)
|
if(dice == undefined)
|
||||||
return // No dice
|
return // No dice
|
||||||
|
|
||||||
RollDice(dice, respond)
|
RollDice(dice, respond)
|
||||||
}
|
}
|
||||||
|
|
||||||
const RollDice = (dice, respond) => {
|
const RollDice = (dice, respond) => {
|
||||||
if(dice.size > 255) {
|
if(dice.size > 255) {
|
||||||
respond('That die is way too big... .-.')
|
respond('That die is way too big... .-.')
|
||||||
return
|
return
|
||||||
} else if(dice.size < 2) {
|
} else if(dice.size < 2) {
|
||||||
respond('I cannot even fathom a die with that geometry ;-;')
|
respond('I cannot even fathom a die with that geometry ;-;')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dice.count > 100) {
|
if(dice.count > 100) {
|
||||||
respond('I don\'t have that many dice O_O')
|
respond('I don\'t have that many dice O_O')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let rolls = [ ...crypto.getRandomValues(new Uint8Array(dice.count) ) ]
|
let rolls = [ ...crypto.getRandomValues(new Uint8Array(dice.count) ) ]
|
||||||
.map(n => Math.ceil((n / 256) * dice.size))
|
.map(n => Math.ceil((n / 256) * dice.size))
|
||||||
let result = 0
|
let result = 0
|
||||||
let operationSymbol = dice.operation
|
let operationSymbol = dice.operation
|
||||||
let response = ''
|
let response = ''
|
||||||
|
|
||||||
switch(dice.mode.toLowerCase()) {
|
switch(dice.mode.toLowerCase()) {
|
||||||
case 'd':
|
case 'd':
|
||||||
result = rolls.reduce((a, v) => a + v, 0)
|
result = rolls.reduce((a, v) => a + v, 0)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
result = rolls.reduce((a, v) => v > a ? v : a, 0)
|
result = rolls.reduce((a, v) => v > a ? v : a, 0)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
result = rolls.reduce((a, v) => v < a ? v : a, Infinity)
|
result = rolls.reduce((a, v) => v < a ? v : a, Infinity)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
let pseudoMedian = Math.floor(dice.size / 2)
|
let pseudoMedian = Math.floor(dice.size / 2)
|
||||||
let resultDistance = -1
|
let resultDistance = -1
|
||||||
|
|
||||||
for(let roll of rolls) {
|
for(let roll of rolls) {
|
||||||
let distance = Math.abs(roll - pseudoMedian)
|
let distance = Math.abs(roll - pseudoMedian)
|
||||||
|
|
||||||
if(distance > resultDistance) {
|
if(distance > resultDistance) {
|
||||||
result = roll
|
result = roll
|
||||||
resultDistance = distance
|
resultDistance = distance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(dice.operation) {
|
switch(dice.operation) {
|
||||||
case '+':
|
case '+':
|
||||||
result += dice.modifier
|
result += dice.modifier
|
||||||
break
|
break
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
result -= dice.modifier
|
result -= dice.modifier
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'x':
|
case 'x':
|
||||||
operationSymbol = '*'
|
operationSymbol = '*'
|
||||||
case '*':
|
case '*':
|
||||||
result = result * dice.modifier
|
result = result * dice.modifier
|
||||||
break
|
break
|
||||||
|
|
||||||
case '/':
|
case '/':
|
||||||
result = result / dice.modifier
|
result = result / dice.modifier
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dice.descriptionConditions) {
|
if(dice.descriptionConditions) {
|
||||||
for(let { range, content } of dice.descriptionConditions) {
|
for(let { range, content } of dice.descriptionConditions) {
|
||||||
if(!range || result >= range.lower && result <= range.upper)
|
if(!range || result >= range.lower && result <= range.upper)
|
||||||
response += `'${content}', `
|
response += `'${content}', `
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response += `\` ${result} \` \u27F5 [${rolls.join(', ')}] ${dice.count + dice.mode + dice.size}`
|
response += `\` ${result} \` \u27F5 [${rolls.join(', ')}] ${dice.count + dice.mode + dice.size}`
|
||||||
|
|
||||||
if(dice.operation) {
|
if(dice.operation) {
|
||||||
response += ' ' + operationSymbol + ' ' + dice.modifier
|
response += ' ' + operationSymbol + ' ' + dice.modifier
|
||||||
}
|
}
|
||||||
|
|
||||||
respond(response)
|
respond(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
const SaveReply = (message, reply) => {
|
const SaveReply = (message, reply) => {
|
||||||
globalThis.replies.set(message.id, {
|
globalThis.replies.set(message.id, {
|
||||||
id: reply.id,
|
id: reply.id,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const MessageCycle = async message => {
|
const MessageCycle = async message => {
|
||||||
OnMessage(message, async content => {
|
OnMessage(message, async content => {
|
||||||
SaveReply(message, await message.reply(content) )
|
SaveReply(message, await message.reply(content) )
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const RehandleMessage = async (message, reply) => {
|
const RehandleMessage = async (message, reply) => {
|
||||||
OnMessage(message, async content => {
|
OnMessage(message, async content => {
|
||||||
SaveReply(message, await reply.edit(content) )
|
SaveReply(message, await reply.edit(content) )
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const PruneReplies = () => {
|
const PruneReplies = () => {
|
||||||
for(let [ id, entry ] of globalThis.replies.entries()) {
|
for(let [ id, entry ] of globalThis.replies.entries()) {
|
||||||
let age = Date.now() - entry.timestamp
|
let age = Date.now() - entry.timestamp
|
||||||
|
|
||||||
if(age > 1000 * 60 * 3) {
|
if(age > 1000 * 60 * 3) {
|
||||||
globalThis.replies.delete(id)
|
globalThis.replies.delete(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InteractionRespond = (interaction, content) => {
|
const InteractionRespond = (interaction, content) => {
|
||||||
let reply = { content, ephemeral: true }
|
let reply = { content, ephemeral: true }
|
||||||
|
|
||||||
if(interaction.replied || interaction.deferred) {
|
if(interaction.replied || interaction.deferred) {
|
||||||
return interaction.followUp(reply)
|
return interaction.followUp(reply)
|
||||||
} else {
|
} else {
|
||||||
return interaction.reply(reply)
|
return interaction.reply(reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrorHandler = (interaction) => (error) =>
|
const ErrorHandler = (interaction) => (error) =>
|
||||||
InteractionRespond(interaction, constants.errorMessage(error) )
|
InteractionRespond(interaction, constants.errorMessage(error) )
|
||||||
.catch(reportingError => console.error('Could not display error message:\n ', reportingError) )
|
.catch(reportingError => console.error('Could not display error message:\n ', reportingError) )
|
||||||
|
|
||||||
const Command = (data, callback) => {
|
const Command = (data, callback) => {
|
||||||
globalThis.commands.set(data.name, {
|
globalThis.commands.set(data.name, {
|
||||||
data,
|
data,
|
||||||
execute: callback
|
execute: callback
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const Subcommands = (data, subcommandCallbacks) =>
|
const Subcommands = (data, subcommandCallbacks) =>
|
||||||
Command(data, interaction => {
|
Command(data, interaction => {
|
||||||
return subcommandCallbacks[interaction.options.getSubcommand()](interaction)
|
return subcommandCallbacks[interaction.options.getSubcommand()](interaction)
|
||||||
})
|
})
|
||||||
|
|
||||||
const OpenMacros = guildId =>
|
const OpenMacros = guildId =>
|
||||||
db.sublevel(guildId).sublevel('macros')
|
db.sublevel(guildId).sublevel('macros')
|
||||||
|
|
||||||
const ReloadMacros = async guildId => {
|
const ReloadMacros = async guildId => {
|
||||||
let commands = []
|
let commands = []
|
||||||
let macros = OpenMacros(guildId)
|
let macros = OpenMacros(guildId)
|
||||||
let cacheEntry = {}
|
let cacheEntry = {}
|
||||||
|
|
||||||
for await (let [ name, dice ] of macros.iterator() ) {
|
for await (let [ name, dice ] of macros.iterator() ) {
|
||||||
cacheEntry[name] = dice
|
cacheEntry[name] = dice
|
||||||
|
|
||||||
commands.push({
|
commands.push({
|
||||||
name,
|
name,
|
||||||
description: Elipsify("Roll " + dice.replaceAll('\n', ';'), 100),
|
description: Elipsify("Roll " + dice.replaceAll('\n', ';'), 100),
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: "options",
|
name: "options",
|
||||||
description: "Dice, modifiers, or descriptions to apply over the macro",
|
description: "Dice, modifiers, or descriptions to apply over the macro",
|
||||||
type: 3
|
type: 3
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
globalThis.macroCache.set(guildId, cacheEntry)
|
globalThis.macroCache.set(guildId, cacheEntry)
|
||||||
|
|
||||||
await rest.put(
|
await rest.put(
|
||||||
Routes.applicationGuildCommands(process.env.DISCORD_ID, guildId),
|
Routes.applicationGuildCommands(process.env.DISCORD_ID, guildId),
|
||||||
{ body: globalThis.commands }
|
{ body: globalThis.commands }
|
||||||
)
|
)
|
||||||
.catch(err => console.error('Failed to reload macros:', err) )
|
.catch(err => console.error('Failed to reload macros:', err) )
|
||||||
}
|
}
|
||||||
|
|
||||||
const Elipsify = (string, maxLength) =>
|
const Elipsify = (string, maxLength) =>
|
||||||
string.length > maxLength ? string.slice(0, maxLength - 3) + '...' : string
|
string.length > maxLength ? string.slice(0, maxLength - 3) + '...' : string
|
||||||
|
|
||||||
const PruneDB = async () => {
|
const PruneDB = async () => {
|
||||||
let validIds = []
|
let validIds = []
|
||||||
|
|
||||||
for await(let key of db.keys()) {
|
for await(let key of db.keys()) {
|
||||||
let [ guildId ] = key.split('!').slice(1)
|
let [ guildId ] = key.split('!').slice(1)
|
||||||
|
|
||||||
if(validIds.includes(guildId))
|
if(validIds.includes(guildId))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if(client.guilds.cache.has(guildId)) {
|
if(client.guilds.cache.has(guildId)) {
|
||||||
validIds.push(guildId)
|
validIds.push(guildId)
|
||||||
} else {
|
} else {
|
||||||
await db.del(key)
|
await db.del(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return validIds
|
return validIds
|
||||||
}
|
}
|
||||||
|
|
||||||
const Responses = (interaction, ephemeral) => async content =>
|
const Responses = (interaction, ephemeral) => async content =>
|
||||||
interaction.reply({ content, ephemeral })
|
interaction.reply({ content, ephemeral })
|
||||||
|
|
||||||
const Subscribe = (event, callback) => {
|
const Subscribe = (event, callback) => {
|
||||||
client.on(event, (...args) => {
|
client.on(event, (...args) => {
|
||||||
return callback(...args)
|
return callback(...args)
|
||||||
.catch(err => console.error(err))
|
.catch(err => console.error(err))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const HandleCommand = async interaction => {
|
const HandleCommand = async interaction => {
|
||||||
if(globalThis.commands.has(interaction.commandName) ) {
|
if(globalThis.commands.has(interaction.commandName) ) {
|
||||||
globalThis.commands.get(interaction.commandName).execute(interaction)
|
globalThis.commands.get(interaction.commandName).execute(interaction)
|
||||||
.catch(ErrorHandler(interaction))
|
.catch(ErrorHandler(interaction))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await interaction.deferReply()
|
await interaction.deferReply()
|
||||||
let roll = globalThis.macroCache.get(interaction.guild.id)[interaction.commandName]
|
let roll = globalThis.macroCache.get(interaction.guild.id)[interaction.commandName]
|
||||||
|
|
||||||
if(roll) {
|
if(roll) {
|
||||||
let dice = ParseRoll(roll)
|
let dice = ParseRoll(roll)
|
||||||
let options = interaction.options.get('options')
|
let options = interaction.options.get('options')
|
||||||
|
|
||||||
if(options) {
|
if(options) {
|
||||||
let optionDice = ParseOptionRoll(options.value)
|
let optionDice = ParseOptionRoll(options.value)
|
||||||
|
|
||||||
for(let [ key, value ] of Object.entries(optionDice)) {
|
for(let [ key, value ] of Object.entries(optionDice)) {
|
||||||
if(value)
|
if(value)
|
||||||
dice[key] = Array.isArray(value) ? value.concat(dice[key]) : value
|
dice[key] = Array.isArray(value) ? value.concat(dice[key]) : value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RollDice(dice, content => interaction.followUp(content) )
|
RollDice(dice, content => interaction.followUp(content) )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FindOption = (options, name) =>
|
const FindOption = (options, name) =>
|
||||||
options.find(option => option.name == name)
|
options.find(option => option.name == name)
|
||||||
|
|
||||||
const HandleAutocomplete = async interaction => {
|
const HandleAutocomplete = async interaction => {
|
||||||
if(globalThis.commands.has(interaction.commandName) ) {
|
if(globalThis.commands.has(interaction.commandName) ) {
|
||||||
let { data } = globalThis.commands.get(interaction.commandName)
|
let { data } = globalThis.commands.get(interaction.commandName)
|
||||||
let subcommand = interaction.options.getSubcommand()
|
let subcommand = interaction.options.getSubcommand()
|
||||||
let focusedOption = interaction.options.getFocused(true)
|
let focusedOption = interaction.options.getFocused(true)
|
||||||
|
|
||||||
if(subcommand !== undefined) {
|
if(subcommand !== undefined) {
|
||||||
data = FindOption(data.options, subcommand)
|
data = FindOption(data.options, subcommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
let option = FindOption(data.options, focusedOption.name)
|
let option = FindOption(data.options, focusedOption.name)
|
||||||
|
|
||||||
if(!option) {
|
if(!option) {
|
||||||
console.error('Could not find option: ' + focusedOption)
|
console.error('Could not find option: ' + focusedOption)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let filtered = option
|
let filtered = option
|
||||||
.getAutocomplete(interaction)
|
.getAutocomplete(interaction)
|
||||||
.filter(choice => choice.startsWith(focusedOption.value) )
|
.filter(choice => choice.startsWith(focusedOption.value) )
|
||||||
.map(choice => ({ name: choice, value: choice }) )
|
.map(choice => ({ name: choice, value: choice }) )
|
||||||
|
|
||||||
await interaction.respond(filtered)
|
await interaction.respond(filtered)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Interaction = interaction => {
|
const Interaction = interaction => {
|
||||||
if(interaction.isChatInputCommand()) {
|
if(interaction.isChatInputCommand()) {
|
||||||
return HandleCommand(interaction)
|
return HandleCommand(interaction)
|
||||||
} else if(interaction.isAutocomplete()) {
|
} else if(interaction.isAutocomplete()) {
|
||||||
return HandleAutocomplete(interaction)
|
return HandleAutocomplete(interaction)
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MessageUpdate = async (oldMessage, newMessage) => {
|
const MessageUpdate = async (oldMessage, newMessage) => {
|
||||||
if(globalThis.replies.has(newMessage.id) ) {
|
if(globalThis.replies.has(newMessage.id) ) {
|
||||||
let { id } = globalThis.replies.get(newMessage.id)
|
let { id } = globalThis.replies.get(newMessage.id)
|
||||||
|
|
||||||
newMessage.channel.messages.fetch(id)
|
newMessage.channel.messages.fetch(id)
|
||||||
.then(reply => RehandleMessage(newMessage, reply) )
|
.then(reply => RehandleMessage(newMessage, reply) )
|
||||||
.catch(err => MessageCycle(newMessage) )
|
.catch(err => MessageCycle(newMessage) )
|
||||||
} else {
|
} else {
|
||||||
MessageCycle(newMessage)
|
MessageCycle(newMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const About = async (interaction) => {
|
const About = async (interaction) => {
|
||||||
let embed = {
|
let embed = {
|
||||||
title: 'dicedicedice',
|
title: 'dicedicedice',
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
url: constants.iconUrl
|
url: constants.iconUrl
|
||||||
},
|
},
|
||||||
description: constants.aboutMessage(client.guilds.cache.size)
|
description: constants.aboutMessage(client.guilds.cache.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
embeds: [ embed ],
|
embeds: [ embed ],
|
||||||
ephemeral: true
|
ephemeral: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddMacro = async (interaction) => {
|
const AddMacro = async (interaction) => {
|
||||||
let respond = Responses(interaction, true)
|
let respond = Responses(interaction, true)
|
||||||
let name = interaction.options.get('name').value.toLowerCase()
|
let name = interaction.options.get('name').value.toLowerCase()
|
||||||
|
|
||||||
if(!constants.macroNameRegex.test(name))
|
if(!constants.macroNameRegex.test(name))
|
||||||
return respond("Please provide a macro name that consists of only alphanumeric characters.")
|
return respond("Please provide a macro name that consists of only alphanumeric characters.")
|
||||||
|
|
||||||
if(commands.has(name))
|
if(commands.has(name))
|
||||||
return respond("Uhh,, I think that macro name is already taken by my own commands, sorry.")
|
return respond("Uhh,, I think that macro name is already taken by my own commands, sorry.")
|
||||||
|
|
||||||
let macros = globalThis.macroCache.get(interaction.guild.id)
|
let macros = globalThis.macroCache.get(interaction.guild.id)
|
||||||
|
|
||||||
if(macros && !macros[name] && Object.keys(macros).length >= 100)
|
if(macros && !macros[name] && Object.keys(macros).length >= 100)
|
||||||
return respond("I can't keep track of that many macros,, ;-;")
|
return respond("I can't keep track of that many macros,, ;-;")
|
||||||
|
|
||||||
let dice = interaction.options.get('dice').value
|
let dice = interaction.options.get('dice').value
|
||||||
|
|
||||||
if(!constants.rollRegex.test(dice) )
|
if(!constants.rollRegex.test(dice) )
|
||||||
return respond("Please provide a valid roll expression.")
|
return respond("Please provide a valid roll expression.")
|
||||||
|
|
||||||
await interaction.deferReply({ ephemeral: true })
|
await interaction.deferReply({ ephemeral: true })
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
OpenMacros(interaction.guild.id).put(name, dice),
|
OpenMacros(interaction.guild.id).put(name, dice),
|
||||||
ReloadMacros(interaction.guild.id)
|
ReloadMacros(interaction.guild.id)
|
||||||
])
|
])
|
||||||
interaction.followUp(`Macro added! Try \`/${name}\`! You might need to switch to a different server and back or reopen Discord in order for it to recognize the new command.`)
|
interaction.followUp(`Macro added! Try \`/${name}\`! You might need to switch to a different server and back or reopen Discord in order for it to recognize the new command.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const RemoveMacro = async (interaction) => {
|
const RemoveMacro = async (interaction) => {
|
||||||
let name = interaction.options.get('name').value.toLowerCase()
|
let name = interaction.options.get('name').value.toLowerCase()
|
||||||
let macros = macroCache.get(interaction.guild.id)
|
let macros = macroCache.get(interaction.guild.id)
|
||||||
let respond = openResponses(interaction, true)
|
let respond = openResponses(interaction, true)
|
||||||
|
|
||||||
if(!macros)
|
if(!macros)
|
||||||
return respond('There aren\'t even any macros in this guild!')
|
return respond('There aren\'t even any macros in this guild!')
|
||||||
|
|
||||||
let dice = macros && macroCache.get(interaction.guild.id)[name]
|
let dice = macros && macroCache.get(interaction.guild.id)[name]
|
||||||
|
|
||||||
if(!dice)
|
if(!dice)
|
||||||
return respond("There isn't a macro with that name .-.")
|
return respond("There isn't a macro with that name .-.")
|
||||||
|
|
||||||
await interaction.deferReply({ ephemeral: true })
|
await interaction.deferReply({ ephemeral: true })
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
openMacros(interaction.guild.id).del(name),
|
openMacros(interaction.guild.id).del(name),
|
||||||
reloadMacros(interaction.guild.id)
|
reloadMacros(interaction.guild.id)
|
||||||
])
|
])
|
||||||
|
|
||||||
await interaction.followUp(`Removed \`${name}\`, its dice expression was: \`\`\`${dice}\`\`\``)
|
await interaction.followUp(`Removed \`${name}\`, its dice expression was: \`\`\`${dice}\`\`\``)
|
||||||
}
|
}
|
||||||
|
|
||||||
const Start = async () => {
|
const Start = async () => {
|
||||||
Command(
|
Command(
|
||||||
constants.commands.about,
|
constants.commands.about,
|
||||||
About
|
About
|
||||||
)
|
)
|
||||||
|
|
||||||
Subcommands(constants.commands.macro, {
|
Subcommands(constants.commands.macro, {
|
||||||
add: AddMacro,
|
add: AddMacro,
|
||||||
remove: RemoveMacro
|
remove: RemoveMacro
|
||||||
})
|
})
|
||||||
|
|
||||||
Subscribe('interactionCreate', Interaction)
|
Subscribe('interactionCreate', Interaction)
|
||||||
Subscribe('messageCreate', MessageCycle)
|
Subscribe('messageCreate', MessageCycle)
|
||||||
Subscribe('messageUpdate', MessageUpdate)
|
Subscribe('messageUpdate', MessageUpdate)
|
||||||
Subscribe('ready', async () => {
|
Subscribe('ready', async () => {
|
||||||
console.log("Logged in!")
|
console.log("Logged in!")
|
||||||
|
|
||||||
let guildIds = await PruneDB()
|
let guildIds = await PruneDB()
|
||||||
|
|
||||||
for(let guildId of guildIds)
|
for(let guildId of guildIds)
|
||||||
await ReloadMacros(guildId)
|
await ReloadMacros(guildId)
|
||||||
|
|
||||||
console.log("Ready")
|
console.log("Ready")
|
||||||
})
|
})
|
||||||
|
|
||||||
await rest.put(
|
await rest.put(
|
||||||
Routes.applicationCommands(process.env.DISCORD_ID),
|
Routes.applicationCommands(process.env.DISCORD_ID),
|
||||||
{
|
{
|
||||||
body: [ ...globalThis.commands.values() ]
|
body: [ ...globalThis.commands.values() ]
|
||||||
.map(command => command.data )
|
.map(command => command.data )
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.catch(err => console.error('Command registration failed: ', err) )
|
.catch(err => console.error('Command registration failed: ', err) )
|
||||||
|
|
||||||
console.log(process.env)
|
console.log(process.env)
|
||||||
|
|
||||||
await client.login(process.env.DISCORD_TOKEN)
|
await client.login(process.env.DISCORD_TOKEN)
|
||||||
.catch(err => console.error('Login failed: ', err) )
|
.catch(err => console.error('Login failed: ', err) )
|
||||||
|
|
||||||
setInterval(PruneReplies, 1000 * 60)
|
setInterval(PruneReplies, 1000 * 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
Start()
|
Start()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user