Remove the rollDecorators command, implement roll command help library, god this was a pain to write

This commit is contained in:
Ean Milligan 2025-06-26 03:17:26 -04:00
parent 5b7ceb9f88
commit ae321885d6
24 changed files with 1212 additions and 359 deletions

View File

@ -17,6 +17,7 @@
"Dists",
"dkdk",
"EMDAS",
"Exponentials",
"funciton",
"guildid",
"hidewarn",

View File

@ -134,7 +134,8 @@ The Artificer comes with a few supplemental commands to the main rolling command
* `-o a` or `-o d` - Order Roll - Rolls the requested roll and orders the results in the requested direction
* `-ct` - Comma Totals - Adds commas to totals for readability
* `-cc` - Confirm Critical Hits - Automatically rerolls whenever a crit hits, cannot be used with `-sn`
- `-rd` - Roll Distribution - Shows a raw roll distribution of all dice in roll
* `-rd` - Roll Distribution - Shows a raw roll distribution of all dice in roll
* `-hr` - Hide Raw - Hide the raw input, showing only the results/details of the roll
* The results have some formatting applied on them to provide details on what happened during this roll.
* Critical successes will be **bolded**
* Critical fails will be <ins>underlined</ins>

View File

@ -39,6 +39,7 @@ export const config = {
sourceCode: 'https://github.com/Burn-E99/TheArtificer', // Link to the repository
supportServer: '', // Invite link to the Discord support server
roll20Formatting: 'https://help.roll20.net/hc/en-us/articles/360037773133-Dice-Reference', // Link to Roll20 Dice Reference
mathDocs: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math', // Link to the MDN docs for Math
homePage: '', // Link to the bot's home/ad page
privacyPolicy: '', // Link to the current Privacy Policy
termsOfService: '', // Link to the current Terms of Service

View File

@ -12,7 +12,6 @@ import { privacy } from 'commands/privacy.ts';
import { rip } from 'commands/rip.ts';
import { report } from 'commands/report.ts';
import { roll } from 'commands/roll.ts';
import { rollDecorators } from 'commands/rollDecorators.ts';
import { rollHelp } from 'commands/rollHelp.ts';
import { stats } from 'commands/stats.ts';
import { version } from 'commands/version.ts';
@ -32,7 +31,6 @@ export default {
rip,
report,
roll,
rollDecorators,
rollHelp,
stats,
version,

View File

@ -30,11 +30,6 @@ export const help = (message: DiscordenoMessage) => {
value: `Details on how to use the roll command, listed as \`${config.prefix}xdy...${config.postfix}\` below`,
inline: true,
},
{
name: `\`${config.prefix}rollDecorators\` or \`${config.prefix}???\``,
value: `Details on how to use decorators on the roll command`,
inline: true,
},
{
name: `\`${config.prefix}api [subcommand]\``,
value: `Administrative tools for the bots's API, run \`${config.prefix}api help\` for more details`,

View File

@ -0,0 +1,41 @@
import config from '~config';
import { HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
import { DecoratorsHelpPages } from 'commands/helpLibrary/decorators.ts';
import { DiceOptionsHelpPages } from 'commands/helpLibrary/diceOptions.ts';
import { DiceTypesHelpPages } from 'commands/helpLibrary/diceTypes.ts';
import { FormattingHelpPages } from 'commands/helpLibrary/formatting.ts';
import { LegalMathComplexFuncsHelpPages } from 'commands/helpLibrary/legalMathComplexFuncs.ts';
import { LegalMathConstsHelpPages } from 'commands/helpLibrary/legalMathConsts.ts';
import { LegalMathFuncsHelpPages } from 'commands/helpLibrary/legalMathFuncs.ts';
import { LegalMathOperators } from 'commands/helpLibrary/legalMathOperators.ts';
import { LegalMathTrigFuncsHelpPages } from 'commands/helpLibrary/legalMathTrigFuncs.ts';
import { MiscFeaturesHelpPages } from 'commands/helpLibrary/miscFeatures.ts';
const name = `${config.name}'s Roll Command Details`;
const description = `You can chain as many of these options as you want, as long as the option does not disallow it. This command also can fully solve math equations with parenthesis.
The help options in this group use the notation \`xdy\` to indicate the basic/required dice notation for die count and size as detailed in the \`Basic/Standard Dice Options\` page.
As this supports the [Roll20 formatting](${config.links.roll20Formatting}) syntax fully, more details and examples can be found [here](${config.links.roll20Formatting}).
Please use the dropdown/select menus to search through the provided documentation.`;
const dict = new Map<string, HelpPage>([
['dice-types', DiceTypesHelpPages],
['dice-options', DiceOptionsHelpPages],
['decorators', DecoratorsHelpPages],
['formatting', FormattingHelpPages],
['misc-features', MiscFeaturesHelpPages],
['legal-math-operators', LegalMathOperators],
['legal-math-consts', LegalMathConstsHelpPages],
['legal-math-funcs', LegalMathFuncsHelpPages],
['legal-math-trig-funcs', LegalMathTrigFuncsHelpPages],
['legal-math-complex-funcs', LegalMathComplexFuncsHelpPages],
]);
export const RootHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,172 @@
import config from '~config';
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Roll Command Decorators';
const description = `This command also has some useful decorators that can used. These decorators simply need to be placed after all rolls in the message.
**Examples:** \`${config.prefix}d20${config.postfix} -nd\`, \`${config.prefix}d20${config.postfix} -nd -s\`, \`${config.prefix}d20${config.postfix} ${config.prefix}d20${config.postfix} ${config.prefix}d20${config.postfix} -o a\``;
const dict = new Map<string, HelpContents>([
[
'-nd',
{
name: 'No Details',
description: `**Usage:** \`-nd\`
Hides some of the details of the requested roll, but will still show the list of roll results along with the formatted results.`,
example: ['`[[2000d20]] -nd` => Limits the details shown to just be `[[2000d20]]` = **__20935__**'],
},
],
[
'-snd',
{
name: 'Super No Details',
description: `**Usage:** \`-snd\`
Suppresses all details of the requested roll.`,
example: ['`[[2000d20]] -nd` => Removes the details section entirely'],
},
],
[
'-s',
{
name: 'Spoiler',
description: `**Usage:** \`-s\`
Spoilers all details of the requested roll`,
example: ['`[[d20]] -s`'],
},
],
[
'-max',
{
name: 'Maximize Roll',
description: `**Usage:** \`-max\` or \`-m\`
Rolls the theoretical maximum roll.
**Notice:** Cannot be used with \`-n\`, \`-min\`, or \`-sn\``,
example: ['`[[d20]] -max` => **20**'],
},
],
[
'-min',
{
name: 'Minimize Roll',
description: `**Usage:** \`-min\`
Rolls the theoretical minimum roll.
**Notice:** Cannot be used with \`-m\`, \`-max\`, \`-n\`, or \`-sn\``,
example: ['`[[d20]] -min` => __1__'],
},
],
[
'-n',
{
name: 'Nominal Roll',
description: `**Usage:** \`-n\`
Rolls the theoretical nominal roll.
**Notice:** Cannot be used with \`-m\`, \`-max\`, \`-min\`, or \`-sn\``,
example: ['`[[d20]] -n` => 10.5'],
},
],
[
'-sn',
{
name: 'Simulated Nominal Roll',
description: `**Usage:** \`-sn\`
Rolls the requests roll many times to approximately simulate the nominal of complex rolls, can specify the amount or accept default amount by not specify the amount.
**Notice:** Cannot be used with \`-m\`, \`-max\`, \`-min\`, \`-n\`, or \`-cc\``,
example: ['`[[4d6d1]] -sn` => 12.274'],
},
],
[
'-o',
{
name: 'Order Roll',
description: `**Usage:** \`-o a\` or \`-o d\`
\`a\` - Ascending (least to greatest)
\`d\` - Descending (greatest to least)
Rolls the requested roll and orders the results in the requested direction.`,
example: [
'`[[4d6d1]] [[4d6d1]] [[4d6d1]] [[4d6d1]] -o a` => 9, __9__, 12, **15**',
'`[[4d6d1]] [[4d6d1]] [[4d6d1]] [[4d6d1]] -o a` => **17**, 14, **13**, 9',
],
},
],
[
'-c',
{
name: 'Count Rolls',
description: `**Usage:** \`-c\`
Shows the Count Embed, containing the count of successful rolls, failed rolls, rerolls, drops, and explosions.`,
example: ['`[[40d20]] -c`'],
},
],
[
'-cc',
{
name: 'Confirm Critical Hits',
description: `**Usage:** \`-cc\`
Automatically rerolls whenever a crit hits.
**Notice:** Cannot be used with \`-sn\``,
example: ['`[[d20]] -cc` => **20** Auto-Confirming Crit: **20** Auto-Confirming Crit: 7'],
},
],
[
'-ct',
{
name: 'Comma Totals',
description: `**Usage:** \`-ct\`
Adds commas to totals for readability.`,
example: ['`[[100d20]] -ct` => Shows **__1,110__** instead of **__1110__**'],
},
],
[
'-gm',
{
name: 'GM Roll',
description: `**Usage:** \`-gm @user1 @user2 ... @userN\`
Rolls the requested roll in GM mode, suppressing all publicly shown results/details and instead sending the results directly to the specified GMs.`,
example: ['[[d20]] -gm @$'],
},
],
[
'-hr',
{
name: 'Hide Raw',
description: `**Usage:** \`-hr\`
Hide the raw input, showing only the results/details of the roll.`,
example: ['`[[d20]] -hr`'],
},
],
[
'-rd',
{
name: 'Roll Distribution',
description: `**Usage:** \`-rd\`
Shows a raw roll distribution of all dice in roll.`,
example: ['`[[1000d20]] -rd`'],
},
],
]);
export const DecoratorsHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,239 @@
import config from '~config';
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Roll20 Dice Options';
const description = `\`${config.prefix}xdydzracsq!${config.postfix}\` Rolls all configs requested, you may repeat the command multiple times in the same message (just ensure you close each roll with \`${config.postfix}\`).`;
const dict = new Map<string, HelpContents>([
[
'dice',
{
name: 'Basic Dice Options',
description: `**Usage:** \`xdy\`
\`x\` - Number of dice to roll, if omitted, 1 is used
\`y\` - Size of dice to roll, can be replaced with \`F\` to roll Fate dice`,
example: ['`[[4d6]]` => Rolls four 6-sided dice', '`[[5dF]]` => Rolls five Fate dice'],
},
],
[
'drop-lowest',
{
name: 'Drop (Lowest)',
description: `**Usage:** \`xdydz\` or \`xdydlz\`
\`z\` - Number of dice to drop
**Notice:** Cannot be combined with other drop or keep options`,
example: ['`[[6d8d2]]` => Rolls six 8-sided dice, dropping the two lowest rolled dice'],
},
],
[
'drop-highest',
{
name: 'Drop Highest',
description: `**Usage:** \`xdydhz\`
\`z\` - Number of dice to drop
**Notice:** Cannot be combined with other drop or keep options`,
example: ['`[[6d8dh2]]` => Rolls six 8-sided dice, dropping the two highest rolled dice'],
},
],
[
'keep-highest',
{
name: 'Keep (Highest)',
description: `**Usage:** \`xdykz\` or \`xdykhz\`
\`z\` - Number of dice to keep
**Notice:** Cannot be combined with other drop or keep options`,
example: ['`[[6d8k2]]` => Rolls six 8-sided dice, keeping the two highest rolled dice'],
},
],
[
'keep-lowest',
{
name: 'Keep Lowest',
description: `**Usage:** \`xdyklz\`
\`z\` - Number of dice to keep
**Notice:** Cannot be combined with other drop or keep options`,
example: ['`[[6d8dh2]]` => Rolls six 8-sided dice, keeping the two lowest rolled dice'],
},
],
[
'reroll',
{
name: '(Normal) Reroll',
description: `**Usage:** \`xdyrz\`, \`xdyr=z\`, \`xdyr<z\`, or \`xdyr>z\`
\`z\` - Number to compare to for rerolls, see examples for how each setup above works
The (Normal) Reroll option will reroll any dice that matches the specified pattern. Old rolls will be discarded.
**Notice:** Cannot be combined with the Reroll Once option`,
example: [
'`[[6d8r2]]` => Rolls six 8-sided dice, rerolling any dice that land on 2',
'`[[6d8r2r4]]` => Rolls six 8-sided dice, rerolling any dice that land on 2 or 4',
'`[[6d8r=2]]` => Rolls six 8-sided dice, rerolling any dice that land on 2',
'`[[6d8r<2]]` => Rolls six 8-sided dice, rerolling any dice that land on 2 or 1',
'`[[6d8r>2]]` => Rolls six 8-sided dice, rerolling any dice that land on 2 thru 8 inclusive',
],
},
],
[
'reroll-once',
{
name: 'Reroll Once',
description: `**Usage:** \`xdyroz\`, \`xdyro=z\`, \`xdyro<z\`, or \`xdyro>z\`
\`z\` - Number to compare to for rerolls, see examples for how each setup above works
The Reroll Once option will reroll any dice that matches the specified pattern for the first time. If a die that has already been rerolled lands on a side matching the pattern, it will not be rerolled again. Old rolls will be discarded.
For example, if \`4d8ro2\` is rolled with initial results of \`[1, 2, 6, 7]\`, the \`[1, 6, 7]\` will be kept and the \`2\` will be rerolled. If this die lands on a \`2\` again, it will not be rerolled and will be kept.
**Notice:** Cannot be combined with the (Normal) Reroll options`,
example: [
'`[[6d8ro2]]` => Rolls six 8-sided dice, rerolling any dice that land on 2 for the first time',
'`[[6d8ro2ro4]]` => Rolls six 8-sided dice, rerolling any dice that land on 2 or 4 for the first time',
'`[[6d8ro=2]]` => Rolls six 8-sided dice, rerolling any dice that land on 2 for the first time',
'`[[6d8ro<2]]` => Rolls six 8-sided dice, rerolling any dice that land on 2 or 1 for the first time',
'`[[6d8ro>2]]` => Rolls six 8-sided dice, rerolling any dice that land on 2 thru 8 inclusive for the first time',
],
},
],
[
'crit-score',
{
name: 'Critical (Success) Score',
description: `**Usage:** \`xdycsz\`, \`xdycs=z\`, \`xdycs<z\`, or \`xdycs>z\`
\`z\` - Number to compare to for changing the critical success score, see examples for how each setup above works
The Critical (Success) Score option will not change what is marked as a critical success, if combined with an Exploding option, it will also explode on the newly set critical success score specified.
**Notice:** This overrides the implicit critical success settings, meaning unless specified, a 8 on a \`d8\` will not be marked as a crit`,
example: [
'`[[6d8cs2]]` => Rolls six 8-sided dice, marking any die that lands on a 2 as a critical success',
'`[[6d8cs2cs4]]` => Rolls six 8-sided dice, marking any die that lands on a 2 or 4 as a critical success',
'`[[6d8cs=2]]` => Rolls six 8-sided dice, marking any die that lands on a 2 as a critical success',
'`[[6d8cs<2]]` => Rolls six 8-sided dice, marking any die that lands on a 2 or 1 as a critical success',
'`[[6d8cs>2]]` => Rolls six 8-sided dice, marking any die that lands on a 2 thru 8 inclusive as a critical success',
],
},
],
[
'crit-fail',
{
name: 'Critical Fail Score',
description: `**Usage:** \`xdycfz\`, \`xdycf=z\`, \`xdycf<z\`, or \`xdycf>z\`
\`z\` - Number to compare to for changing the critical fail score, see examples for how each setup above works
**Notice:** This overrides the implicit critical fail settings, meaning unless specified, a 1 on a \`d8\` will not be marked as a fail`,
example: [
'`[[6d8cf2]]` => Rolls six 8-sided dice, marking any die that lands on a 2 as a critical fail',
'`[[6d8cf2cf4]]` => Rolls six 8-sided dice, marking any die that lands on a 2 or 4 as a critical fail',
'`[[6d8cf=2]]` => Rolls six 8-sided dice, marking any die that lands on a 2 as a critical fail',
'`[[6d8cf<2]]` => Rolls six 8-sided dice, marking any die that lands on a 2 or 1 as a critical fail',
'`[[6d8cf>2]]` => Rolls six 8-sided dice, marking any die that lands on a 2 thru 8 inclusive as a critical fail',
],
},
],
[
'exploding',
{
name: '(Standard) Exploding',
description: `**Usage:** \`xdy!\`, \`xdy!z\`, \`xdy!=z\`, \`xdy!<z\`, or \`xdy!>z\`
\`z\` - Number to compare to for changing the score to explode on, if omitted, will explode on critical successes, see examples for how each setup above works
(Standard) Exploding is when you roll another die when one lands on a certain number, and keep both results. This theoretically could happen infinitely since if the new die also lands on a number set to explode it will also explode.
**Notice:** Cannot be combined with other types of explosion/exploding options`,
example: [
'`[[6d8!]]` => Rolls six 8-sided dice, exploding any die that lands on a 8 (the max size of the die)',
'`[[6d10!]]` => Rolls six 10-sided dice, exploding any die that lands on a 10 (the max size of the die)',
'`[[6d8cs4!]]` => Rolls six 8-sided dice, exploding any die that lands on a 4 (the critical success score specified by `cs4`)',
'`[[6d8cs>4!]]` => Rolls six 8-sided dice, exploding any die that lands on a 4 thru 8 inclusive (the critical success score specified by `cs>4`)',
'`[[6d8!2]]` => Rolls six 8-sided dice, exploding any die that lands on a 2',
'`[[6d8!2!4]]` => Rolls six 8-sided dice, exploding any die that lands on a 2 or 4',
'`[[6d8!=2]]` => Rolls six 8-sided dice, exploding any die that lands on a 2',
'`[[6d8!<2]]` => Rolls six 8-sided dice, exploding any die that lands on a 2 or 1',
'`[[6d8!>2]]` => Rolls six 8-sided dice, exploding any die that lands on a 2 thru 8 inclusive',
],
},
],
[
'explode-once',
{
name: 'Explode Once',
description: `**Usage:** \`xdy!o\`, \`xdy!oz\`, \`xdy!o=z\`, \`xdy!o<z\`, or \`xdy!o>z\`
\`z\` - Number to compare to for changing the score to explode on, if omitted, will explode on critical successes, see examples for how each setup above works
The Explode Once option is when you roll another die when one lands on a certain number, and keep both results. This will not cascade to infinity though, as once a die has exploded, it cannot explode again.
**Notice:** Cannot be combined with other types of explosion/exploding options`,
example: [
'`[[6d8!o]]` => Rolls six 8-sided dice, exploding any die that lands on a 8 (the max size of the die) for the first time',
'`[[6d10!o]]` => Rolls six 10-sided dice, exploding any die that lands on a 10 (the max size of the die) for the first time',
'`[[6d8cs4!o]]` => Rolls six 8-sided dice, exploding any die that lands on a 4 (the critical success score specified by `cs4`) for the first time',
'`[[6d8cs>4!o]]` => Rolls six 8-sided dice, exploding any die that lands on a 4 thru 8 inclusive (the critical success score specified by `cs>4`) for the first time',
'`[[6d8!o2]]` => Rolls six 8-sided dice, exploding any die that lands on a 2 for the first time',
'`[[6d8!o2!o4]]` => Rolls six 8-sided dice, exploding any die that lands on a 2 or 4 for the first time',
'`[[6d8!o=2]]` => Rolls six 8-sided dice, exploding any die that lands on a 2 for the first time',
'`[[6d8!o<2]]` => Rolls six 8-sided dice, exploding any die that lands on a 2 or 1 for the first time',
'`[[6d8!o>2]]` => Rolls six 8-sided dice, exploding any die that lands on a 2 thru 8 inclusive for the first time',
],
},
],
[
'explode-penetrating',
{
name: 'Penetrating Explosion',
description: `**Usage:** \`xdy!p\`, \`xdy!pz\`, \`xdy!p=z\`, \`xdy!p<z\`, or \`xdy!p>z\`
\`z\` - Number to compare to for changing the score to explode on, if omitted, will explode on critical successes, see examples for how each setup above works
The Penetrating Explosion option is when you roll another die when one lands on a certain number, but you subtract 1 from the new die, and keep both results. This may cascade to infinity if the exploding range is very large.
**Notice:** Cannot be combined with other types of explosion/exploding options`,
example: [
'`[[6d8!p]]` => Rolls six 8-sided dice, exploding+penetrating any die that lands on a 8 (the max size of the die)',
'`[[6d10!p]]` => Rolls six 10-sided dice, exploding+penetrating any die that lands on a 10 (the max size of the die)',
'`[[6d8cs4!p]]` => Rolls six 8-sided dice, exploding+penetrating any die that lands on a 4 (the critical success score specified by `cs4`)',
'`[[6d8cs>4!p]]` => Rolls six 8-sided dice, exploding+penetrating any die that lands on a 4 thru 8 inclusive (the critical success score specified by `cs>4`)',
'`[[6d8!p2]]` => Rolls six 8-sided dice, exploding+penetrating any die that lands on a 2',
'`[[6d8!p2!p4]]` => Rolls six 8-sided dice, exploding+penetrating any die that lands on a 2 or 4',
'`[[6d8!p=2]]` => Rolls six 8-sided dice, exploding+penetrating any die that lands on a 2',
'`[[6d8!p<2]]` => Rolls six 8-sided dice, exploding+penetrating any die that lands on a 2 or 1',
'`[[6d8!p>2]]` => Rolls six 8-sided dice, exploding+penetrating any die that lands on a 2 thru 8 inclusive',
],
},
],
[
'explode-compounding',
{
name: 'Compounding Explosion',
description: `**Usage:** \`xdy!!\`, \`xdy!!z\`, \`xdy!!=z\`, \`xdy!!<z\`, or \`xdy!!>z\`
\`z\` - Number to compare to for changing the score to explode on, if omitted, will explode on critical successes, see examples for how each setup above works
The Compounding Explosion option is when you roll another die when one lands on a certain number, and add the new result to the initial die. This theoretically could happen infinitely since if the new die also lands on a number set to explode it will also explode.
Any time a Compounding Explosion happens, the formatting on the die will still show if the underlying dice were a critical success or critical failure.
**Notice:** Cannot be combined with other types of explosion/exploding options`,
example: [
'`[[6d8!!]]` => Rolls six 8-sided dice, exploding+compounding any die that lands on a 8 (the max size of the die)',
'`[[6d10!!]]` => Rolls six 10-sided dice, exploding+compounding any die that lands on a 10 (the max size of the die)',
'`[[6d8cs4!!]]` => Rolls six 8-sided dice, exploding+compounding any die that lands on a 4 (the critical success score specified by `cs4`)',
'`[[6d8cs>4!!]]` => Rolls six 8-sided dice, exploding+compounding any die that lands on a 4 thru 8 inclusive (the critical success score specified by `cs>4`)',
'`[[6d8!!2]]` => Rolls six 8-sided dice, exploding+compounding any die that lands on a 2',
'`[[6d8!!2!!4]]` => Rolls six 8-sided dice, exploding+compounding any die that lands on a 2 or 4',
'`[[6d8!!=2]]` => Rolls six 8-sided dice, exploding+compounding any die that lands on a 2',
'`[[6d8!!<2]]` => Rolls six 8-sided dice, exploding+compounding any die that lands on a 2 or 1',
'`[[6d8!!>2]]` => Rolls six 8-sided dice, exploding+compounding any die that lands on a 2 thru 8 inclusive',
],
},
],
]);
export const DiceOptionsHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,69 @@
import config from '~config';
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Custom Dice Shapes';
const description = `${config.name} supports also a couple other types of dice such as Fate or OVA dice.`;
const dict = new Map<string, HelpContents>([
[
'd20',
{
name: 'Roll20/Normal Dice',
description: `**Usage:** \`${config.prefix}xdy${config.postfix}\`
\`x\` - Number of dice to roll, defaults to 1
\`y\` - Size of the die, required`,
example: ['`[[d20]]` => [5] = 5', '`[[6d20]]` => [**20** + 16 + 17 + 19 + 10 + 15] = **97**'],
},
],
[
'fate',
{
name: 'Fate Dice',
description: `**Usage:** \`${config.prefix}xdF${config.postfix}\`
\`x\` - Number of Fate dice to roll, defaults to 1
Rolls a Fate die, has 6 sides with values \`[-1, -1, 0, 0, 1, 1]\`.`,
example: ['`[[dF]]` => [**1**] = **1**', '`[[4dF]]` => [**1** + __-1__ + 0 + 0] = **__0__**'],
},
],
[
'cwod',
{
name: 'CWOD Dice',
description: `**Usage:** \`${config.prefix}xcwody${config.postfix}\`
\`x\` - Number of CWOD dice to roll, defaults to 1
\`y\` - Difficulty to roll at, defaults to 10
Rolls a specified number of 10 sided dice and counts successful and failed rolls.`,
example: [
'`[[cwod]]` => [3, 0 Successes, 0 Fails] = 0',
'`[[4cwod]]` => [**10** + __1__ + 9 + __1__, 1 Success, 2 Fails] = **__1__**',
'`[[5cwod8]]` => [**10** + 2 + 5 + **8** + 4, 2 Successes, 0 Fails] = **2**',
],
},
],
[
'ova',
{
name: 'OVA Dice',
description: `**Usage:** \`${config.prefix}xovady${config.postfix}\`
\`x\` - Number of OVA dice to roll, defaults to 1
\`y\` - Size of the die to roll, defaults to 6
Rolls a specified number of dice and returns the greatest sum of repeated dice. The \`[[8ovad]]\` example shows that even though there are two 5's, the sum of those is less than four 3's, and thus the result is the four 3's, summed to 12.`,
example: [
'`[[ovad]]` => [4] = 4',
'`[[4ovad]]` => [~~4~~ + 5 + ~~6~~ + 5] = 10',
'`[[8ovad]]` => [~~2~~ + 3 + 3 + ~~5~~ + ~~4~~ + 3 + 3 + ~~5~~] = 12',
'`[[5ovad20]]` => [~~18~~ + ~~17~~ + 19 + 19 + ~~10~~] = 38',
],
},
],
]);
export const DiceTypesHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,46 @@
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Results Formatting';
const description =
'The results have some formatting applied on them to provide details on what happened during this roll. These options can be stacked on each other to show complicated results.';
const dict = new Map<string, HelpContents>([
[
'bold',
{
name: 'Bold',
description: 'Individual critical successes and any results containing a critical success will be **bolded**.',
example: ['`[[2d6]]` => [2 + **6**] = **8**'],
},
],
[
'underline',
{
name: 'Underline',
description: 'Individual critical fails and any results containing a critical fail will be __underlined__.',
example: ['`[[2d6]]` => [__1__ + 4] = __5__'],
},
],
[
'strikethrough',
{
name: 'Strikethrough',
description: 'Rolls that were dropped or rerolled ~~crossed out~~.',
example: ['`[[4d6d1]]` => [~~__1__~~ + 2 + 4 + **6**] = **12**', '`4d6r2` => [__1__ + ~~2~~ + 3 + 4 + **6**] = **__14__**'],
},
],
[
'exclamation-mark',
{
name: 'Exclamation mark (`!`)',
description: 'Rolls that were caused by an explosion have an exclamation mark (`!`) after them.',
example: ['`[[4d6!]]` => [3 + 4 + **6** + 4! + 5] = **22**'],
},
],
]);
export const FormattingHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,85 @@
import { ActionRow, botId, CreateMessage, Embed, MessageComponentTypes, SelectOption } from '@discordeno';
import config from '~config';
import { RootHelpPages } from 'commands/helpLibrary/_rootHelp.ts';
import { HelpContents, HelpDict, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
import { infoColor1 } from 'embeds/colors.ts';
import { InteractionValueSeparator } from 'events/interactionCreate.ts';
export const helpCustomId = 'help';
const generateActionRowWithSelectMenu = (selected: string, helpDict: HelpDict, parent?: string): ActionRow => ({
type: MessageComponentTypes.ActionRow,
components: [
{
type: MessageComponentTypes.SelectMenu,
customId: `${helpCustomId}${InteractionValueSeparator}${selected}`,
options: helpDict
.entries()
.toArray()
.map(
(page): SelectOption => ({
label: page[1].name,
value: parent ? `${parent}${InteractionValueSeparator}${page[0]}` : page[0],
default: page[0] === selected,
})
),
},
],
});
const makeHelpEmbed = (helpDict: HelpContents | HelpPage, parentTitle?: string): Embed => ({
color: infoColor1,
author: {
name: `Roll Command Help${parentTitle ? ' - ' : ''}${parentTitle}`,
},
title: helpDict.name,
description: helpDict.description,
fields:
!helpDict.isPage && helpDict.example
? [
{
name: `Example${helpDict.example.length > 1 ? 's' : ''}:`,
value: helpDict.example.join('\n').replaceAll('@$', `<@${botId}>`).replaceAll('[[', config.prefix).replaceAll(']]', config.postfix),
},
]
: [],
});
const defaultHelpMessage = (showError = ''): CreateMessage => ({
embeds: [
{
...makeHelpEmbed(RootHelpPages),
footer: {
text: showError ? `Error${showError}: Something went wrong, please try again.` : '',
},
},
],
components: [generateActionRowWithSelectMenu('', RootHelpPages.dict)],
});
export const generateHelpMessage = (helpPath?: string): CreateMessage => {
if (helpPath) {
const [page, item] = helpPath.split(InteractionValueSeparator);
// Get the first layer dictionary
const rootHelpDict = RootHelpPages.dict.get(page);
if (!rootHelpDict || !rootHelpDict.isPage) return defaultHelpMessage('1');
// Get second layer dictionary
const helpDict = item ? rootHelpDict.dict.get(item) : rootHelpDict;
if (!helpDict) return defaultHelpMessage('2');
return {
embeds: [makeHelpEmbed(helpDict, helpDict.isPage ? '' : rootHelpDict.name)],
components: [
generateActionRowWithSelectMenu(page, RootHelpPages.dict),
helpDict.isPage ? generateActionRowWithSelectMenu('', helpDict.dict, page) : generateActionRowWithSelectMenu(item, rootHelpDict.dict, page),
],
};
} else {
return defaultHelpMessage();
}
};

View File

@ -0,0 +1,16 @@
interface HelpItem {
name: string;
description: string;
}
export type HelpDict = Map<string, HelpContents | HelpPage>;
export interface HelpContents extends HelpItem {
isPage?: false;
example?: string[];
}
export interface HelpPage extends HelpItem {
isPage: true;
dict: HelpDict;
}

View File

@ -0,0 +1,109 @@
import config from '~config';
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Complex Math Functions';
const description = `All the weird extras.
I really have no idea what these could be used for, but if you find a cool use, please use \`${config.prefix}report\` to let me know what cool things you are doing!
Have fun!
Documentation from the [MDN Web Docs](${config.links.mathDocs}).`;
const dict = new Map<string, HelpContents>([
[
'cbrt',
{
name: 'Cube Root',
description: 'Returns the cube root of a number.',
example: ['`[[cbrt(27)]]` => 3', '`[[cbrt(d20 * 4)]]` => cbrt([10] * 6.4) = 4'],
},
],
[
'exp',
{
name: 'e^x',
description: 'Returns `e` raised to the power of a number.',
example: ['`[[exp(2)]]` => 7.38905609893065', '`[[exp(d8)]]` => exp([6]) = 403.4287934927351'],
},
],
[
'expm1',
{
name: 'e^x - 1',
description: 'Returns `e` raised to the power of a number, subtracted by `1`.',
example: ['`[[expm1(2)]]` => 6.38905609893065', '`[[expm1(d8)]]` => expm1([6]) = 402.4287934927351'],
},
],
[
'sign',
{
name: 'Sign',
description: 'Returns `1` or `-1`, indicating the sign of the number passed as argument.',
example: ['`[[sign(-456)]]` => -1', '`[[sign(d20)]]` => sign([14]) = 1'],
},
],
[
'f16round',
{
name: '16bit Float Round',
description: 'Returns the nearest 16-bit half precision float representation of a number.',
example: ['`[[f16round(4.1)]]` => 4.1015625', '`[[f16round(d4 / 3)]]` => f16round([2] / 3) = 0.66650390625'],
},
],
[
'fround',
{
name: '32bit Float Round',
description: 'Returns the nearest 32-bit single precision float representation of a number.',
example: ['`[[fround(4.1)]]` => 4.099999904632568', '`[[fround(d4 / 3)]]` => fround([2] / 3) = 0.6666666865348816'],
},
],
[
'log',
{
name: 'Natural Log (ln(x))',
description: 'Returns the natural logarithm (base e) of a number.',
example: ['`[[log(2)]]` => 0.6931471805599453', '`[[log(d8)]]` => log([4]) = 1.3862943611198906'],
},
],
[
'log1p',
{
name: 'Natural Log (ln(x + 1))',
description: 'Returns the natural logarithm (base e) of `1 + x`, where `x` is the argument.',
example: ['`[[log1p(2)]]` => 1.0986122886681096', '`[[log1p(d8)]]` => log1p([4]) = 1.6094379124341003'],
},
],
[
'log2',
{
name: 'Log Base 2',
description: 'Returns the base 2 logarithm of a number.',
example: ['`[[log2(2)]]` => 1', '`[[log2(d8)]]` => log2([4]) = 2'],
},
],
[
'log10',
{
name: 'Log Base 10',
description: 'Returns the base 10 logarithm of a number.',
example: ['`[[log10(2)]]` => 0.3010299956639812', '`[[log10(d8)]]` => log10([4]) = 0.6020599913279624'],
},
],
[
'clz32',
{
name: 'Count Leading Zeros 32',
description: 'Returns the number of leading zero bits in the 32-bit binary representation of a number.',
example: ['`[[clz32(1)]]` => 31', '`[[clz32(d20)]]` => clz32([19] * 4) = 25'],
},
],
]);
export const LegalMathComplexFuncsHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,37 @@
import config from '~config';
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Math Constants';
const description = `Available math constants.
Documentation from [MDN Web Docs](${config.links.mathDocs}).`;
const dict = new Map<string, HelpContents>([
[
'e',
{
name: "Euler's number",
description: `**Usage:** \`e\`
Represents Euler's number, the base of natural logarithms, \`e\`, which is approximately \`2.718\`.`,
example: ['`[[e]]` => 2.718281828459045', '`[[e*2]]` => 5.43656365691809'],
},
],
[
'pi',
{
name: 'Pi/𝜋',
description: `**Usage:** \`pi\` or \`𝜋\`
Represents the ratio of the circumference of a circle to its diameter, approximately \`3.14159\`.`,
example: ['`[[pi]]` => 3.141592653589793', '`[[𝜋*2]]` => 6.283185307179586'],
},
],
]);
export const LegalMathConstsHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,65 @@
import config from '~config';
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Basic Math Functions';
const description = `Basic math functions akin to what Roll20 provides, such as Round or Ceil.
Documentation from the [MDN Web Docs](${config.links.mathDocs}).`;
const dict = new Map<string, HelpContents>([
[
'abs',
{
name: 'Absolute Value',
description: 'Returns the absolute value of a number.',
example: ['`[[abs(-4)]]` => 4', '`[[abs(-56 * d20)]]` => abs(-56 * [12]) = 672'],
},
],
[
'ceil',
{
name: 'Ceiling',
description: 'Always rounds up to nearest whole number.',
example: ['`[[ceil(4.3)]]` => 5', '`[[ceil(d20 / 3)]]` => ceil([13] / 3) = 5'],
},
],
[
'floor',
{
name: 'Floor',
description: 'Always rounds down to the nearest whole number.',
example: ['`[[floor(4.8)]]` => 4', '`[[floor(d20 / 3)]]` => floor([14] / 3) = 4'],
},
],
[
'round',
{
name: 'Round',
description: 'Returns the value of a number rounded to the nearest whole number.',
example: ['`[[round(4.3)]]` => 4', '`[[round(4.8)]]` => 5', '`[[round(d20 / 3)]]` => round([13] / 3) = 4', '`[[round(d20 / 3)]]` => round([14] / 3) = 5'],
},
],
[
'trunc',
{
name: 'Truncate',
description: 'Returns the integer part of a number by removing any fractional digits.',
example: ['`[[trunc(4.3)]]` => 4', '`[[trunc(4.8)]]` => 4', '`[[trunc(d20 / 3)]]` => trunc([13] / 3) = 4', '`[[trunc(d20 / 3)]]` => trunc([14] / 3) = 5'],
},
],
[
'sqrt',
{
name: 'Square Root',
description: 'Returns the square root of a number.',
example: ['`[[sqrt(4)]]` => 2', '`[[sqrt(d20 + 2)]]` => sqrt([14] + 2) = 4'],
},
],
]);
export const LegalMathFuncsHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,70 @@
import config from '~config';
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Math Operators';
const description = `Basic math operators. In the following examples, spaces are included for readability and are not required as they are stripped from the command when ${config.name} parses it.
When multiple are included in one command, they are executed in PEMDAS (Parenthesis, Exponentials, Multiplication, Division, Addition, Subtraction) order.`;
const dict = new Map<string, HelpContents>([
[
'parenthesis',
{
name: 'Parenthesis',
description: 'Used to group parts of an equation, can be nested as much as needed. Supports implicit multiplication.',
example: [
'`[[4(12 + 3)]]` => 60',
'`[[(12 + 3)4]]` => 60',
'`[[d20(4 + d4)]]` => [14] * (4 + 3) = 98',
'`[[d20(4 + (d4 * (4 + d20) ^ 3))]]` => [19] * (4 + ([__1__] * (4 + 8) ^ 3)) = __32908__',
],
},
],
[
'exponentials',
{
name: 'Exponentials',
description: 'A base number multiplied by itself a specified number of times.',
example: ['`[[10 ^ 2]]` => 100', '`[[d20 ^ 2]]` => [13] ^ 2 = 169'],
},
],
[
'multiplication',
{
name: 'Multiplication',
description: 'Also known as repeated addition.',
example: ['`[[4 * 5]]` => 20', '`[[d20 * 6]]` => [11] * 6 = 66'],
},
],
[
'division',
{
name: 'Division',
description: 'The inverse of multiplication',
example: ['`[[20 / 4]]` => 5', '`[[d20 / 4]]` => [12] / 4 = 3'],
},
],
[
'addition',
{
name: 'Addition',
description: 'The process of adding things together.',
example: ['`[[3 + 4]]` => 7', '`[[d20 + 4]]` => [13] + 4 = 17'],
},
],
[
'subtraction',
{
name: 'Subtraction',
description: 'Gives the difference between two numbers.',
example: ['`[[5 - 2]]` => 3', '`[[d20 - 3]]` => [17] - 3 = 14'],
},
],
]);
export const LegalMathOperators: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,115 @@
import config from '~config';
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Trigonometric Math Funcs';
const description = `Math functions such as sine and cosine.
I have no idea why you may need this in a dice rolling bot, but have fun!
Documentation from the [MDN Web Docs](${config.links.mathDocs}).`;
const dict = new Map<string, HelpContents>([
[
'sin',
{
name: 'Sine',
description: 'Returns the sine of a number in radians.',
example: ['`[[sin(2)]]` => 0.9092974268256817', '`[[sin(d4)]]` => sin([3]) = 0.1411200080598672'],
},
],
[
'sinh',
{
name: 'Hyperbolic Sine',
description: 'Returns the hyperbolic sine of a number.',
example: ['`[[sinh(2)]]` => 3.626860407847019', '`[[sinh(d4)]]` => sinh([3]) = 10.017874927409903'],
},
],
[
'asin',
{
name: 'Arc Sine',
description: 'Returns the inverse/arc sine (in radians) of a number.',
example: ['`[[asin(1)]]` => 1.5707963267948966', '`[[asin(d4 / 4)]]` => asin([3] / 4) = 0.848062078981481'],
},
],
[
'asinh',
{
name: 'Arc Hyperbolic Sine',
description: 'Returns the inverse/arc hyperbolic sine of a number.',
example: ['`[[asinh(2)]]` => 1.4436354751788103', '`[[asinh(d4)]]` => asinh([3]) = 1.8184464592320668'],
},
],
[
'cos',
{
name: 'Cosine',
description: 'Returns the cosine of a number in radians.',
example: ['`[[cos(2)]]` => -0.4161468365471424', '`[[cos(d4)]]` => cos([3]) = -0.9899924966004454'],
},
],
[
'cosh',
{
name: 'Hyperbolic Cosine',
description: 'Returns the hyperbolic cosine of a number.',
example: ['`[[cosh(2)]]` => 3.7621956910836314', '`[[cosh(d4)]]` => cosh([3]) = 10.067661995777765'],
},
],
[
'acos',
{
name: 'Arc Cosine',
description: 'Returns the inverse/arc cosine (in radians) of a number.',
example: ['`[[acos(0.5)]]` => 1.0471975511965979', '`[[acos(d4 / 4)]]` => acos([3] / 4) = 0.7227342478134157'],
},
],
[
'acosh',
{
name: 'Arc Hyperbolic Cosine',
description: 'Returns the inverse/arc hyperbolic cosine of a number.',
example: ['`[[acosh(2)]]` => 1.3169578969248166', '`[[acosh(d4)]]` => acosh([3]) = 1.7627471740390859'],
},
],
[
'tan',
{
name: 'Tangent',
description: 'Returns the tangent of a number in radians.',
example: ['`[[tan(2)]]` => -2.185039863261519', '`[[tan(d4)]]` => tan([3]) = -0.1425465430742778'],
},
],
[
'tanh',
{
name: 'Hyperbolic Tangent',
description: 'Returns the hyperbolic tangent of a number.',
example: ['`[[tanh(2)]]` => 0.9640275800758169', '`[[tanh(d4)]]` => tanh([3]) = 0.9950547536867305'],
},
],
[
'atan',
{
name: 'Arc Tangent',
description: 'Returns the inverse/arc tangent (in radians) of a number.',
example: ['`[[atan(2)]]` => 1.1071487177940904', '`[[atan(d4)]]` => atan([3]) = 1.2490457723982544'],
},
],
[
'atanh',
{
name: 'Arc Hyperbolic Tangent',
description: 'Returns the inverse/arc hyperbolic tangent of a number.',
example: ['`[[atanh(0.5)]]` => 0.5493061443340548', '`[[atanh(d4 / 4)]]` => atanh([3] / 4) = 0.9729550745276566'],
},
],
]);
export const LegalMathTrigFuncsHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -0,0 +1,87 @@
import config from '~config';
import { HelpContents, HelpPage } from 'commands/helpLibrary/helpLibrary.d.ts';
const name = 'Miscellaneous Features';
const description = `This section includes any other features I can't group elsewhere.`;
const dict = new Map<string, HelpContents>([
[
'user-formatting',
{
name: 'User Formatting',
description: `Any formatting/characters outside of roll commands will be preserved in the output.
The first characters in a message must be a valid roll command, you can pad your message with something like \`[[0]]\` as shown in the example. The example uses the "Super No Details" flag (\`-snd\`) in combination with the "Hide Raw" flag (\`-hr\`) to only show the formatted results.`,
example: [
`\`\`\`[[0]] ${config.name} attacks the dragon with their Sword!
To Hit: [[d20 + 4 - 1 + 8]]
Damage: [[d8 + 10]] -snd -hr\`\`\`
**Results:**
0 ${config.name} attacks the dragon with their Sword!
To Hit: 18
Damage: 14`,
],
},
],
[
'nested',
{
name: 'Nested Rolls',
description: `${config.name} supports nesting dice rolls inside of each other. This means you can roll a random number of die, dice of random sizes, etc.`,
example: [
'Roll a `d10`, then roll that number of `d20`s.\n`[[ [[d10]]d20 ]]` => `[[d10 = 3]]d20` = [2 + 12 + 11] = 25',
'',
'Roll a `d4` and add 4 to it, then use that number as the die size.\nResults in rolling `4d5d1` thru `4d8d1`.\n`[[ 4d[[ d4 + 4 ]]d1 ]]` => `4d[[d4+4 = 6]]d1` = [~~__1__~~ + 3 + 3 + 3] = 9',
'',
'Roll 5 `d10`s, but reroll a random side of the die determine by a different `d10`.\n`[[5d10r[[d10]] ]]` => `5d10r[[d10 = 10]]` = [3 + 9 + 5 + 5 + ~~**10**~~ + 6] = 28',
],
},
],
[
'variable',
{
name: 'Variables',
description: `${config.name}'s variable system allows reusing results as a value inside one message. This is useful when you want to use a result as a part of the final message, but also want to use that result in a follow-up roll.
This message must contain multiple roll commands in it (such as \`[[d4]] [[d8]]\`). Nested dice rolls are not able to be used as a variable, but can use variables inside them.
Variables are numbered from \`x0\` to \`xN\`, where \`N\` equals two less than the total number of roll commands in the message.
**Notes about this example:**
- The example below starts with \`[[0]]\` so that it is a valid roll command. See the \`Miscellaneous Features>User Formatting\` help page for more details.
- It is recommended to use the "Super No Details" flag (\`-snd\`) in combination with the "Hide Raw" flag (\`-hr\`) to only show the formatted results. This example does not use it to show exactly what is happening.
- The example makes use of Nested Roll Commands to use the "To Hit" as the number of dice to roll for the "Explosion".`,
example: [
`\`\`\`[[0]]<=(this is x0) ${config.name} attacks the dragon with their Magical Sword of Extra Strength and Explosions!
Strength Check: [[d20 + 8 + 2 - 1]]<=(this is x1)
To Hit: [[d20 + 4 - 1 + 8]]<=(this is x2)
Damage: [[(d8 + 10) * x1]]<=(this is x3)
Explosion: [[ [[x2]]d10! * x3 ]]\`\`\`
The above results in the following:
@$ rolled:
\`[[0]] ${config.name} attacks the dragon with their Magical Sword of Extra Strength and Explosions! Strength Check: [[d20 + 8 + 2 - 1]] To Hit: [[d20 + 4 - 1 + 8]] Damage: [[(d8 + 10) * x1]] Explosion: [[ [[x2]]d10! * x3 ]]\`
**Results:**
0 ${config.name} attacks the dragon with their Magical Sword of Extra Strength and Explosions!
Strength Check: 27
To Hit: __12__
Damage: 324
Explosion: __19764__
**Details:**
\`0\` = 0 = 0
\`d20+8+2-1\` = [18]+8+2-1 = 27
\`d20+4-1+8\` = [1]+4-1+8 = 12
\`(d8+10)*x1\` = ([2]+10)\\*27 = 324
\`[[x2=12]]d10!*x3\` = [6 + 5 + 9 + 5 + 4 + __1__ + 3 + **10** + 4! + 6 + 2 + 5 + 6]\\*324 = __21384__`,
],
},
],
]);
export const MiscFeaturesHelpPages: HelpPage = {
name,
description,
isPage: true,
dict,
};

View File

@ -1,85 +0,0 @@
import { DiscordenoMessage } from '@discordeno';
import config from '~config';
import dbClient from 'db/client.ts';
import { queries } from 'db/common.ts';
import { infoColor2 } from 'embeds/colors.ts';
import utils from 'utils/utils.ts';
export const rollDecorators = (message: DiscordenoMessage) => {
// Light telemetry to see how many times a command is being run
dbClient.execute(queries.callIncCnt('rolldecorators')).catch((e) => utils.commonLoggers.dbError('rollHelp.ts:15', 'call sproc INC_CNT on', e));
message
.send({
embeds: [
{
color: infoColor2,
title: 'Roll Command Decorators:',
description: `This command also has some useful decorators that can used. These decorators simply need to be placed after all rolls in the message.
Examples: \`${config.prefix}d20${config.postfix} -nd\`, \`${config.prefix}d20${config.postfix} -nd -s\`, \`${config.prefix}d20${config.postfix} ${config.prefix}d20${config.postfix} ${config.prefix}d20${config.postfix} -o a\``,
fields: [
{
name: '`-nd` - No Details',
value: 'Suppresses all details of the requested roll',
inline: true,
},
{
name: '`-snd` - Super No Details',
value: 'Suppresses all details of the requested roll and hides no details message',
inline: true,
},
{
name: '`-s` - Spoiler',
value: 'Spoilers all details of the requested roll',
inline: true,
},
{
name: '`-m` or `-max` - Maximize Roll',
value: 'Rolls the theoretical maximum roll, cannot be used with `-n` or `-min`',
inline: true,
},
{
name: '`-min` - Minimize Roll',
value: 'Rolls the theoretical minimum roll, cannot be used with `-m`, `-max`, or `-n`',
inline: true,
},
{
name: '`-n` - Nominal Roll',
value: 'Rolls the theoretical nominal roll, cannot be used with `-m`, `-max`, or `-min`',
inline: true,
},
{
name: '`-gm @user1 @user2 @userN` - GM Roll',
value: 'Rolls the requested roll in GM mode, suppressing all publicly shown results and details and sending the results directly to the specified GMs',
inline: true,
},
{
name: '`-c` - Count Rolls',
value: 'Shows the Count Embed, containing the count of successful rolls, failed rolls, rerolls, drops, and explosions',
inline: true,
},
{
name: '`-o [direction]` - Order Roll',
value: `Rolls the requested roll and orders the results in the requested direction
Available directions:
\`a\` - Ascending (least to greatest)
\`d\` - Descending (greatest to least)`,
inline: true,
},
{
name: '`-ct` - Comma Totals',
value: 'Adds commas to totals for readability',
inline: true,
},
],
},
],
})
.catch((e: Error) => utils.commonLoggers.messageSendError('rollHelp.ts:247', message, e));
};

View File

@ -1,266 +1,15 @@
import { DiscordenoMessage } from '@discordeno';
import config from '~config';
import { generateHelpMessage } from 'commands/helpLibrary/generateHelpMessage.ts';
import dbClient from 'db/client.ts';
import { queries } from 'db/common.ts';
import { infoColor1, infoColor2, successColor } from 'embeds/colors.ts';
import utils from 'utils/utils.ts';
export const rollHelp = (message: DiscordenoMessage) => {
// Light telemetry to see how many times a command is being run
dbClient.execute(queries.callIncCnt('rollhelp')).catch((e) => utils.commonLoggers.dbError('rollHelp.ts:15', 'call sproc INC_CNT on', e));
message
.send({
embeds: [
{
color: infoColor1,
title: `${config.name}'s Roll Command Details:`,
description: `You can chain as many of these options as you want, as long as the option does not disallow it.
This command also can fully solve math equations with parenthesis.
${config.name} supports most of the [Roll20 formatting](${config.links.roll20Formatting}). More details and examples can be found [here](${config.links.roll20Formatting}).
Run \`[[???\` or \`[[rollDecorators\` for details on the roll decorators.`,
},
{
color: infoColor2,
title: 'Roll20 Dice Options:',
fields: [
{
name: `\`${config.prefix}xdydzracsq!${config.postfix}\` ...`,
value: `Rolls all configs requested, you may repeat the command multiple times in the same message (just ensure you close each roll with \`${config.postfix}\`)`,
},
{
name: '`x` [Optional]',
value: `Number of dice to roll, if omitted, 1 is used
Additionally, replace \`x\` with \`F\` to roll Fate dice`,
inline: true,
},
{
name: '`dy` [Required]',
value: 'Size of dice to roll, `d20` = 20 sided die',
inline: true,
},
{
name: '`dz` or `dlz` [Optional]',
value: 'Drops the lowest `z` dice, cannot be used with `kz`',
inline: true,
},
{
name: '`kz` or `khz` [Optional]',
value: 'Keeps the highest `z` dice, cannot be used with `dz`',
inline: true,
},
{
name: '`dhz` [Optional]',
value: 'Drops the highest `z` dice, cannot be used with `kz`',
inline: true,
},
{
name: '`klz` [Optional]',
value: 'Keeps the lowest `z` dice, cannot be used with `dz`',
inline: true,
},
{
name: '`rq` or `r=q` [Optional]',
value: 'Rerolls any rolls that match `q`, `r3` will reroll every die that land on 3, throwing out old rolls, cannot be used with `ro`',
inline: true,
},
{
name: '`r<q` [Optional]',
value: 'Rerolls any rolls that are less than or equal to `q`, `r3` will reroll every die that land on 3, 2, or 1, throwing out old rolls, cannot be used with `ro`',
inline: true,
},
{
name: '`r>q` [Optional]',
value: 'Rerolls any rolls that are greater than or equal to `q`, `r3` will reroll every die that land on 3 or greater, throwing out old rolls, cannot be used with `ro`',
inline: true,
},
{
name: '`roq` or `ro=q` [Optional]',
value: 'Rerolls any rolls that match `q`, `ro3` will reroll each die that lands on 3 ONLY ONE TIME, throwing out old rolls, cannot be used with `r`',
inline: true,
},
{
name: '`ro<q` [Optional]',
value: 'Rerolls any rolls that are less than or equal to `q`, `ro3` will reroll each die that lands on 3, 2, or 1 ONLY ONE TIME, throwing out old rolls, cannot be used with `r`',
inline: true,
},
{
name: '`ro>q` [Optional]',
value: 'Rerolls any rolls that are greater than or equal to `q`, `ro3` will reroll each die that lands on 3 or greater ONLY ONE TIME, throwing out old rolls, cannot be used with `r`',
inline: true,
},
{
name: '`csq` or `cs=q` [Optional]',
value: 'Changes crit score to `q`',
inline: true,
},
{
name: '`cs<q` [Optional]',
value: 'Changes crit score to be less than or equal to `q`',
inline: true,
},
{
name: '`cs>q` [Optional]',
value: 'Changes crit score to be greater than or equal to `q`',
inline: true,
},
{
name: '`cfq` or `cf=q` [Optional]',
value: 'Changes crit fail to `q`',
inline: true,
},
{
name: '`cf<q` [Optional]',
value: 'Changes crit fail to be less than or equal to `q`',
inline: true,
},
{
name: '`cf>q` [Optional]',
value: 'Changes crit fail to be greater than or equal to `q`',
inline: true,
},
{
name: '`!` [Optional]',
value: 'Exploding, rolls another `dy` for every crit success',
inline: true,
},
{
name: '`!o` [Optional]',
value: 'Exploding Once, rolls one `dy` for each original crit success',
inline: true,
},
{
name: '`!p` [Optional]',
value: 'Penetrating Explosion, rolls one `dy` for each crit success, but subtracts one from each resulting explosion',
inline: true,
},
{
name: '`!!` [Optional]',
value: 'Compounding Explosion, rolls one `dy` for each crit success, but adds the resulting explosion to the die that caused this explosion',
inline: true,
},
{
name: '`!=u` [Optional]',
value: 'Explode on `u`, rolls another `dy` for every die that lands on `u`',
inline: true,
},
{
name: '`!>u` [Optional]',
value: 'Explode on `u` and greater, rolls another `dy` for every die that lands on `u` or greater',
inline: true,
},
],
},
{
color: infoColor2,
fields: [
{
name: '`!<u` [Optional]',
value: 'Explode on `u` and under, rolls another `dy` for every die that lands on `u` or less',
inline: true,
},
{
name: '`!o=u` [Optional]',
value: 'Explodes Once on `u`, rolls another `dy` for each original die that landed on `u`',
inline: true,
},
{
name: '`!o>u` [Optional]',
value: 'Explode Once on `u` and greater, rolls another `dy` for each original die that landed on `u` or greater',
inline: true,
},
{
name: '`!o<u` [Optional]',
value: 'Explode Once on `u` and under, rolls another `dy` for each original die that landed on `u` or less',
inline: true,
},
{
name: '`!p=u` [Optional]',
value: 'Penetrating Explosion on `u`, rolls one `dy` for each die that lands on `u`, but subtracts one from each resulting explosion',
inline: true,
},
{
name: '`!p>u` [Optional]',
value: 'Penetrating Explosion on `u` and greater, rolls one `dy` for each die that lands on `u` or greater, but subtracts one from each resulting explosion',
inline: true,
},
{
name: '`!p<u` [Optional]',
value: 'Penetrating Explosion on `u` and under, rolls one `dy` for each die that lands on `u` or under, but subtracts one from each resulting explosion',
inline: true,
},
{
name: '`!!=u` [Optional]',
value: 'Compounding Explosion on `u`, rolls one `dy` for each die that lands on `u`, but adds the resulting explosion to the die that caused this explosion',
inline: true,
},
{
name: '`!!>u` [Optional]',
value: 'Compounding Explosion on `u` and greater, rolls one `dy` for each die that lands on `u` or greater, but adds the resulting explosion to the die that caused this explosion',
inline: true,
},
{
name: '`!!<u` [Optional]',
value: 'Compounding Explosion on `u` and under, rolls one `dy` for each die that lands on `u` or under, but adds the resulting explosion to the die that caused this explosion',
inline: true,
},
],
},
{
color: infoColor1,
title: 'Custom Dice Options',
fields: [
{
name: 'CWOD Rolling',
value: `\`${config.prefix}xcwody${config.postfix}\`
\`x\` - Number of CWOD dice to roll
\`y\` - Difficulty to roll at`,
inline: true,
},
{
name: 'OVA Rolling',
value: `\`${config.prefix}xovady${config.postfix}\`
\`x\` - Number of OVA dice to roll
\`y\` - Size of the die to roll (defaults to 6 if omitted)`,
inline: true,
},
],
},
{
color: successColor,
title: 'Results Formatting:',
description: 'The results have some formatting applied on them to provide details on what happened during this roll.',
fields: [
{
name: 'Bold',
value: 'Critical successes will be **bolded**.',
inline: true,
},
{
name: 'Underline',
value: 'Critical fails will be __underlined__.',
inline: true,
},
{
name: 'Strikethrough',
value: 'Rolls that were dropped or rerolled ~~crossed out~~.',
inline: true,
},
{
name: 'Exclamation mark (`!`)',
value: 'Rolls that were caused by an explosion have an exclamation mark (`!`) after them.',
inline: true,
},
],
},
],
})
.catch((e: Error) => utils.commonLoggers.messageSendError('rollHelp.ts:247', message, e));
message.send(generateHelpMessage()).catch((e: Error) => utils.commonLoggers.messageSendError('rollHelp.ts:247', message, e));
};

View File

@ -5,6 +5,7 @@ import { DEVMODE } from '~flags';
import { debugHandler } from 'events/debug.ts';
import { guildCreateHandler } from 'events/guildCreate.ts';
import { guildDeleteHandler } from 'events/guildDelete.ts';
import { interactionCreateHandler } from 'events/interactionCreate.ts';
import { messageCreateHandler } from 'events/messageCreate.ts';
import { readyHandler } from 'events/ready.ts';
import { rawHandler } from 'events/raw.ts';
@ -13,6 +14,7 @@ const eventHandlers: Partial<EventHandlers> = {};
eventHandlers.guildCreate = guildCreateHandler;
eventHandlers.guildDelete = guildDeleteHandler;
eventHandlers.interactionCreate = interactionCreateHandler;
eventHandlers.messageCreate = messageCreateHandler;
eventHandlers.ready = readyHandler;

View File

@ -0,0 +1,43 @@
import {
ButtonData,
DiscordMessageComponentTypes,
editMessage,
Interaction,
InteractionResponseTypes,
SelectMenuData,
sendInteractionResponse,
} from '@discordeno';
import { log, LogTypes as LT } from '@Log4Deno';
import { generateHelpMessage, helpCustomId } from 'commands/helpLibrary/generateHelpMessage.ts';
import utils from 'utils/utils.ts';
export const InteractionValueSeparator = '\u205a';
export const interactionCreateHandler = (interaction: Interaction) => {
try {
if (interaction.data) {
const parsedData = JSON.parse(JSON.stringify(interaction.data)) as SelectMenuData | ButtonData;
if (parsedData.customId.startsWith(helpCustomId) && parsedData.componentType === DiscordMessageComponentTypes.SelectMenu) {
// Acknowledge the request since we're editing the original message
sendInteractionResponse(interaction.id, interaction.token, {
type: InteractionResponseTypes.DeferredUpdateMessage,
}).catch((e: Error) => utils.commonLoggers.messageEditError('interactionCreate.ts:26', interaction, e));
// Edit original message
editMessage(BigInt(interaction.channelId ?? '0'), BigInt(interaction.message?.id ?? '0'), generateHelpMessage(parsedData.values[0])).catch((e: Error) =>
utils.commonLoggers.messageEditError('interactionCreate.ts:30', interaction, e)
);
return;
}
log(LT.WARN, `UNHANDLED INTERACTION!!! data: ${JSON.stringify(interaction.data)}`);
} else {
log(LT.WARN, `UNHANDLED INTERACTION!!! Missing data! ${JSON.stringify(interaction)}`);
}
} catch (e) {
log(LT.ERROR, `UNHANDLED INTERACTION!!! ERR! interaction: ${JSON.stringify(interaction)} error: ${JSON.stringify(e)}`);
}
};

View File

@ -59,21 +59,18 @@ export const messageCreateHandler = (message: DiscordenoMessage) => {
// Displays a short message I wanted to include
commands.rip(message);
break;
case 'rollhelp':
case 'rh':
case 'hr':
case '??':
// [[rollhelp or [[rh or [[hr or [[??
// Help command specifically for the roll command
commands.rollHelp(message);
break;
case 'rolldecorators':
case 'rd':
case 'dr':
case '???':
// [[rollDecorators or [[rd or [[dr or [[???
// Help command specifically for the roll command decorators
commands.rollDecorators(message);
case 'rollhelp':
case 'rh':
case 'hr':
case '??':
// Legacy: [[rollDecorators or [[rd or [[dr or [[???
// [[rollhelp or [[rh or [[hr or [[??
// Help command specifically for the roll command
commands.rollHelp(message);
break;
case 'help':
case 'h':

View File

@ -4,7 +4,7 @@
* December 21, 2020
*/
import { log, LogTypes as LT } from '@Log4Deno';
import { DiscordenoMessage, sendMessage } from '@discordeno';
import { DiscordenoMessage, Interaction, sendMessage } from '@discordeno';
// ask(prompt) returns string
// ask prompts the user at command line for message
@ -87,7 +87,7 @@ Available Commands:
};
const genericLogger = (level: LT, message: string) => log(level, message);
const messageEditError = (location: string, message: DiscordenoMessage | string, err: Error) =>
const messageEditError = (location: string, message: DiscordenoMessage | Interaction | string, err: Error) =>
genericLogger(LT.ERROR, `${location} | Failed to edit message: ${JSON.stringify(message)} | Error: ${err.name} - ${err.message}`);
const messageSendError = (location: string, message: DiscordenoMessage | string, err: Error) =>
genericLogger(LT.ERROR, `${location} | Failed to send message: ${JSON.stringify(message)} | Error: ${err.name} - ${err.message}`);