Begin adding support for penetrating and compounding explosions

Added rollDecorators help command to make [[?? small enough to fit in discord
Added documentation on penetrating and compounding
This commit is contained in:
Ean Milligan (Bastion) 2022-07-05 21:47:37 -04:00
parent 0e69231f20
commit 5366206951
9 changed files with 186 additions and 74 deletions

View File

@ -22,8 +22,10 @@ The Artificer comes with a few supplemental commands to the main rolling command
* `[[help` or `[[h` or `[[?` * `[[help` or `[[h` or `[[?`
* Provides a message similar to this available commands block. * Provides a message similar to this available commands block.
* `[[rollhelp` or `[[??` * `[[rollhelp` or `[[??` or `[[rh` or `[[hr`
* Details on how to use the roll command, listed as `[[xdy...]]` below. * Details on how to use the roll command, listed as `[[xdy...]]` below.
* `[[rolldecorators` or `[[???` or `[[rd` or `[[dr`
* Details on how to use decorators on the roll command.
* `[[api [subcommand]` * `[[api [subcommand]`
* Administrative tools for the bots's API. These commands may only be used by the Owner or Admins of your guild. * Administrative tools for the bots's API. These commands may only be used by the Owner or Admins of your guild.
* Available Subcommands: * Available Subcommands:
@ -66,7 +68,7 @@ The Artificer comes with a few supplemental commands to the main rolling command
| Paramater | Required? | Repeatable? | Description | | Paramater | Required? | Repeatable? | Description |
|---------------|-------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |---------------|-------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| x | Optional | No | number of dice to roll, if omitted, 1 is used, additionally, replace x with `F` to roll the dice as Fate dice | | x | Optional | No | number of dice to roll, if omitted, 1 is used, additionally, replace x with `F` to roll the dice as Fate dice |
| dy | Required | No | size of dice to roll, d20 = 20 sided die | | dy | Required | No | size of dice to roll, d20 = 20 sided die |
| dz or dlz | Optional | No | drops the lowest z dice, cannot be used with any other drop or keep options | | dz or dlz | Optional | No | drops the lowest z dice, cannot be used with any other drop or keep options |
| kz or khz | Optional | No | keeps the highest z dice, cannot be used with any other drop or keep options | | kz or khz | Optional | No | keeps the highest z dice, cannot be used with any other drop or keep options |
@ -86,12 +88,20 @@ The Artificer comes with a few supplemental commands to the main rolling command
| cf>q | Optional | Yes | changes crit fail to be greater than or equal to q | | cf>q | Optional | Yes | changes crit fail to be greater than or equal to q |
| ! | Optional | No | exploding, rolls another dy for every crit success | | ! | Optional | No | exploding, rolls another dy for every crit success |
| !o | Optional | No | exploding once, rolls another dy for each original crit success | | !o | Optional | No | exploding once, rolls another dy for each original crit success |
| !p | Optional | No | penetrating explosion, rolls one dy for each crit success, but subtracts one from each resulting explosion |
| !! | Optional | No | compounding explosion, rolls one dy for each crit success, but adds the resulting explosion to the die that caused this explosion |
| !=u | Optional | Yes | exploding, rolls another dy for every die that lands on u | | !=u | Optional | Yes | exploding, rolls another dy for every die that lands on u |
| !>u | Optional | Yes | exploding, rolls another dy for every die that lands on u or greater | | !>u | Optional | Yes | exploding, rolls another dy for every die that lands on u or greater |
| !<u> | Optional | Yes | exploding, rolls another dy for every die that lands on u or less | | !<u> | Optional | Yes | exploding, rolls another dy for every die that lands on u or less |
| !o=u | Optional | Yes | exploding once, rolls another dy for each original die that landed on u | | !o=u | Optional | Yes | exploding once, rolls another dy for each original die that landed on u |
| !o>u | Optional | Yes | exploding once, rolls another dy for each original die that landed on u or greater | | !o>u | Optional | Yes | exploding once, rolls another dy for each original die that landed on u or greater |
| !o<u | Optional | Yes | exploding once, rolls another dy for each original die that landed on u or less | | !o<u | Optional | Yes | exploding once, rolls another dy for each original die that landed on u or less |
| !p=u | Optional | Yes | penetrating explosion, rolls one dy for each die that lands on u, but subtracts one from each resulting explosion |
| !p>u | Optional | Yes | penetrating explosion, rolls one dy for each die that lands on u or greater, but subtracts one from each resulting explosion |
| !p<u | Optional | Yes | penetrating explosion, rolls one dy for each die that lands on u or under, but subtracts one from each resulting explosion |
| !!=u | Optional | Yes | compounding explosion, rolls one dy for each die that lands on u, but adds the resulting explosion to the die that caused this explosion |
| !!>u | Optional | Yes | compounding explosion, rolls one dy for each die that lands on u or greater, but adds the resulting explosion to the die that caused this explosion |
| !!<u | Optional | Yes | compounding explosion, rolls one dy for each die that lands on u or under, but adds the resulting explosion to the die that caused this explosion |
* If the parameter is Required, it must be provided at all times. * If the parameter is Required, it must be provided at all times.
* If the parameter is Repeatable, it may occur multiple times in the roll configuration. * If the parameter is Repeatable, it may occur multiple times in the roll configuration.

View File

@ -10,7 +10,7 @@ await dbClient.execute('INSERT INTO all_keys(userid,apiKey) values(?,?)', [confi
console.log('Inesrtion done'); console.log('Inesrtion done');
console.log('Attempting to insert default commands into command_cnt'); console.log('Attempting to insert default commands into command_cnt');
const commands = ['ping', 'rip', 'rollhelp', 'help', 'info', 'version', 'report', 'stats', 'roll', 'emojis', 'api', 'privacy', 'mention', 'audit', 'heatmap']; const commands = ['ping', 'rip', 'rollhelp', 'help', 'info', 'version', 'report', 'stats', 'roll', 'emojis', 'api', 'privacy', 'mention', 'audit', 'heatmap', 'rollDecorators'];
for (const command of commands) { for (const command of commands) {
await dbClient.execute('INSERT INTO command_cnt(command) values(?)', [command]).catch((e) => { await dbClient.execute('INSERT INTO command_cnt(command) values(?)', [command]).catch((e) => {
console.log(`Failed to insert ${command} into database`, e); console.log(`Failed to insert ${command} into database`, e);

8
mod.ts
View File

@ -157,6 +157,14 @@ startBot({
// Help command specifically for the roll command // Help command specifically for the roll command
commands.rollHelp(message); commands.rollHelp(message);
break; 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);
break;
case 'help': case 'help':
case 'h': case 'h':
case '?': case '?':

View File

@ -1,6 +1,7 @@
import { ping } from './ping.ts'; import { ping } from './ping.ts';
import { rip } from './rip.ts'; import { rip } from './rip.ts';
import { rollHelp } from './rollHelp.ts'; import { rollHelp } from './rollHelp.ts';
import { rollDecorators } from './rollDecorators.ts';
import { help } from './help.ts'; import { help } from './help.ts';
import { info } from './info.ts'; import { info } from './info.ts';
import { privacy } from './privacy.ts'; import { privacy } from './privacy.ts';
@ -18,6 +19,7 @@ export default {
ping, ping,
rip, rip,
rollHelp, rollHelp,
rollDecorators,
help, help,
info, info,
privacy, privacy,

View File

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

View File

@ -0,0 +1,71 @@
import config from '../../config.ts';
import { dbClient, queries } from '../db.ts';
import {
// Discordeno deps
DiscordenoMessage,
} from '../../deps.ts';
import { infoColor2 } from '../commandUtils.ts';
import utils from '../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` - Maximize Roll',
value: 'Rolls the theoretical maximum roll, cannot be used with -n',
inline: true,
},
{
name: '`-n` - Nominal Roll',
value: 'Rolls the theoretical nominal roll, cannot be used with -m',
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,
},
],
},
],
}).catch((e: Error) => utils.commonLoggers.messageSendError('rollHelp.ts:247', message, e));
};

View File

@ -20,7 +20,9 @@ export const rollHelp = (message: DiscordenoMessage) => {
This command also can fully solve math equations with parenthesis. This command also can fully solve math equations with parenthesis.
The Artificer supports most of the [Roll20 formatting](https://artificer.eanm.dev/roll20). More details and examples can be found [here](https://artificer.eanm.dev/roll20).`, The Artificer supports most of the [Roll20 formatting](https://artificer.eanm.dev/roll20). More details and examples can be found [here](https://artificer.eanm.dev/roll20).
Run \`[[???\` or \`[[rollDecorators\` for details on the roll decorators.`,
}, },
{ {
color: infoColor2, color: infoColor2,
@ -131,6 +133,16 @@ Additionally, replace \`x\` with \`F\` to roll Fate dice`,
value: 'Exploding Once, rolls one `dy` for each original crit success', value: 'Exploding Once, rolls one `dy` for each original crit success',
inline: true, 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]', name: '`!=u` [Optional]',
value: 'Explode on `u`, rolls another `dy` for every die that lands on `u`', value: 'Explode on `u`, rolls another `dy` for every die that lands on `u`',
@ -141,6 +153,11 @@ Additionally, replace \`x\` with \`F\` to roll Fate dice`,
value: 'Explode on `u` and greater, rolls another `dy` for every die that lands on `u` or greater', value: 'Explode on `u` and greater, rolls another `dy` for every die that lands on `u` or greater',
inline: true, inline: true,
}, },
],
},
{
color: infoColor2,
fields: [
{ {
name: '`!<u` [Optional]', name: '`!<u` [Optional]',
value: 'Explode on `u` and under, rolls another `dy` for every die that lands on `u` or less', value: 'Explode on `u` and under, rolls another `dy` for every die that lands on `u` or less',
@ -151,11 +168,6 @@ Additionally, replace \`x\` with \`F\` to roll Fate dice`,
value: 'Explodes Once on `u`, rolls another `dy` for each original die that landed on `u`', value: 'Explodes Once on `u`, rolls another `dy` for each original die that landed on `u`',
inline: true, inline: true,
}, },
],
},
{
color: infoColor2,
fields: [
{ {
name: '`!o>u` [Optional]', name: '`!o>u` [Optional]',
value: 'Explode Once on `u` and greater, rolls another `dy` for each original die that landed on `u` or greater', value: 'Explode Once on `u` and greater, rolls another `dy` for each original die that landed on `u` or greater',
@ -166,6 +178,36 @@ Additionally, replace \`x\` with \`F\` to roll Fate dice`,
value: 'Explode Once on `u` and under, rolls another `dy` for each original die that landed on `u` or less', value: 'Explode Once on `u` and under, rolls another `dy` for each original die that landed on `u` or less',
inline: true, 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,
},
], ],
}, },
{ {
@ -188,59 +230,6 @@ Additionally, replace \`x\` with \`F\` to roll Fate dice`,
}, },
], ],
}, },
{
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` - Maximize Roll',
value: 'Rolls the theoretical maximum roll, cannot be used with -n',
inline: true,
},
{
name: '`-n` - Nominal Roll',
value: 'Rolls the theoretical nominal roll, cannot be used with -m',
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,
},
],
},
{ {
color: successColor, color: successColor,
title: 'Results Formatting:', title: 'Results Formatting:',

View File

@ -60,6 +60,8 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
exploding: { exploding: {
on: false, on: false,
once: false, once: false,
compounding: false,
penetrating: false,
nums: <number[]> [], nums: <number[]> [],
}, },
}; };
@ -261,10 +263,10 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
rollConf.critFail.range.push(i); rollConf.critFail.range.push(i);
} }
break; break;
case '!o':
rollConf.exploding.once = true;
// falls through as !o functions the same as ! in this context
case '!': case '!':
case '!o':
case '!p':
case '!!':
// Configure Exploding // Configure Exploding
rollConf.exploding.on = true; rollConf.exploding.on = true;
if (afterNumIdx > 0) { if (afterNumIdx > 0) {
@ -275,18 +277,18 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
afterNumIdx = 1; afterNumIdx = 1;
} }
break; break;
case '!o=':
rollConf.exploding.once = true;
// falls through as !o= functions the same as != in this context
case '!=': case '!=':
case '!o=':
case '!p=':
case '!!=':
// Configure Exploding (this can happen multiple times) // Configure Exploding (this can happen multiple times)
rollConf.exploding.on = true; rollConf.exploding.on = true;
rollConf.exploding.nums.push(tNum); rollConf.exploding.nums.push(tNum);
break; break;
case '!o>':
rollConf.exploding.once = true;
// falls through as !o> functions the same as !> in this context
case '!>': case '!>':
case '!o>':
case '!p>':
case '!!>':
// Configure Exploding for all numbers greater than or equal to tNum (this could happen multiple times, but why) // Configure Exploding for all numbers greater than or equal to tNum (this could happen multiple times, but why)
rollConf.exploding.on = true; rollConf.exploding.on = true;
for (let i = tNum; i <= rollConf.dieSize; i++) { for (let i = tNum; i <= rollConf.dieSize; i++) {
@ -294,10 +296,10 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
rollConf.exploding.nums.push(i); rollConf.exploding.nums.push(i);
} }
break; break;
case '!o<':
rollConf.exploding.once = true;
// falls through as !o< functions the same as !< in this context
case '!<': case '!<':
case '!o<':
case '!p<':
case '!!<':
// Configure Exploding for all numbers less than or equal to tNum (this could happen multiple times, but why) // Configure Exploding for all numbers less than or equal to tNum (this could happen multiple times, but why)
rollConf.exploding.on = true; rollConf.exploding.on = true;
for (let i = 1; i <= tNum; i++) { for (let i = 1; i <= tNum; i++) {
@ -309,6 +311,29 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
// Throw error immediately if unknown op is encountered // Throw error immediately if unknown op is encountered
throw new Error(`UnknownOperation_${tSep}`); throw new Error(`UnknownOperation_${tSep}`);
} }
// Exploding flags get set in their own switch statement to avoid weird duplicated code
switch (tSep) {
case '!o':
case '!o=':
case '!o>':
case '!o<':
rollConf.exploding.once = true;
break;
case '!p':
case '!p=':
case '!p>':
case '!p<':
rollConf.exploding.penetrating = true;
break;
case '!!':
case '!!=':
case '!!>':
case '!!<':
rollConf.exploding.compounding = true;
break;
}
// Finally slice off everything else parsed this loop // Finally slice off everything else parsed this loop
remains = remains.slice(afterNumIdx); remains = remains.slice(afterNumIdx);
} }

View File

@ -95,6 +95,8 @@ export type RollConf = {
exploding: { exploding: {
on: boolean; on: boolean;
once: boolean; once: boolean;
compounding: boolean;
penetrating: boolean;
nums: number[]; nums: number[];
}; };
}; };