From d6c5dfee77d240e2cb6ba6ae07046dddb94d525a Mon Sep 17 00:00:00 2001 From: Ean Milligan Date: Tue, 22 Jul 2025 23:31:47 -0400 Subject: [PATCH] Add -yvariables decorator to allow repeat roll button to work consistently --- .vscode/settings.json | 3 ++- README.md | 1 + src/artigen/artigen.ts | 24 ++++++++++++++++--- src/artigen/dice/getModifiers.ts | 10 ++++++++ src/artigen/utils/escape.ts | 3 +++ src/artigen/utils/sortFuncs.ts | 9 +++++++ src/commands/aliasCmd/aliasAddUpdate.ts | 9 +------ .../helpLibrary/rollHelp/decorators.ts | 14 +++++++++++ src/events/interactionCreate.ts | 19 +++++++++++++-- 9 files changed, 78 insertions(+), 14 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a8e3c2e..d1f77b6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -58,6 +58,7 @@ "xdydz", "xdydzracsq", "xovady", - "yvar" + "yvar", + "yvariables" ] } \ No newline at end of file diff --git a/README.md b/README.md index ea98890..92dfb23 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,7 @@ The Artificer comes with a few supplemental commands to the main rolling command * `-nv` or `-vn` - Number Variables - Adds `xN` before each roll command in the details section for debug reasons * `-cd` - Custom Dice shapes - Allows a list of `name:[side1,side2,...,sideN]` separated by `;` to be passed to create special shaped dice * `-ns` - No Spaces - Removes the default padding added space between rolls (`[[d4]][[d4]]` will output `22` instead of `2 2`) + * `-yvariables y0,y1,...,yN` - Y Variables - Intended for internal use only, but is mentioned here since it is available externally. Takes a comma separated list of numbers. Unlike other decorators, this one will not be shown in the raw output. * 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 underlined diff --git a/src/artigen/artigen.ts b/src/artigen/artigen.ts index e4dbab6..d68c1e8 100644 --- a/src/artigen/artigen.ts +++ b/src/artigen/artigen.ts @@ -3,15 +3,17 @@ import { log, LogTypes as LT } from '@Log4Deno'; import { SolvedRoll } from 'artigen/artigen.d.ts'; import { tokenizeCmd } from 'artigen/cmdTokenizer.ts'; +import { Modifiers } from 'artigen/dice/getModifiers.ts'; + import { loopCountCheck } from 'artigen/managers/loopManager.ts'; import { QueuedRoll } from 'artigen/managers/manager.d.ts'; import { reduceCountDetails } from 'artigen/utils/counter.ts'; -import { cmdSplitRegex, escapeCharacters } from 'artigen/utils/escape.ts'; +import { cmdSplitRegex, escapeCharacters, withYVarsDash } from 'artigen/utils/escape.ts'; import { loggingEnabled } from 'artigen/utils/logFlag.ts'; import { assertPrePostBalance } from 'artigen/utils/parenBalance.ts'; import { reduceRollDistMaps } from 'artigen/utils/rollDist.ts'; -import { compareTotalRolls, compareTotalRollsReverse } from 'artigen/utils/sortFuncs.ts'; +import { compareTotalRolls, compareTotalRollsReverse, sortYVars } from 'artigen/utils/sortFuncs.ts'; import { translateError } from 'artigen/utils/translateError.ts'; // runCmd(rollRequest) @@ -51,7 +53,12 @@ export const runCmd = (rollRequest: QueuedRoll): SolvedRoll => { // Remove any floating spaces from originalCommand // Escape any | and ` chars in originalCommand to prevent spoilers and code blocks from acting up - const rawCmd = escapeCharacters(rollRequest.originalCommand.trim(), '|').replace(/`/g, ''); + let rawCmd = escapeCharacters(rollRequest.originalCommand.trim(), '|').replace(/`/g, ''); + + // Remove yvariables from the rawCmd since this is intended for internal use only + if (rawCmd.includes(Modifiers.YVars)) { + rawCmd = rawCmd.replaceAll(new RegExp(`( ${Modifiers.YVars} (\\d+,)+\\d+)`, 'g'), ''); + } let line1 = ''; let line2 = ''; @@ -84,6 +91,17 @@ export const runCmd = (rollRequest: QueuedRoll): SolvedRoll => { line1 = ` rolled:\n\`${rawCmd}\``; } + if (rollRequest.modifiers.yVars.size) { + line1 += `\n${withYVarsDash} With yVars: ${ + rollRequest.modifiers.yVars + .entries() + .toArray() + .sort((a, b) => sortYVars(a[0], b[0])) + .map((yVar) => `\`${yVar[0]}=${yVar[1]}\``) + .join(' ') + }`; + } + // List number of iterations on simulated nominals if (rollRequest.modifiers.simulatedNominal) line2 += `Iterations performed per roll: \`${rollRequest.modifiers.simulatedNominal}\`\n`; diff --git a/src/artigen/dice/getModifiers.ts b/src/artigen/dice/getModifiers.ts index 3499948..e94f527 100644 --- a/src/artigen/dice/getModifiers.ts +++ b/src/artigen/dice/getModifiers.ts @@ -25,6 +25,7 @@ export const Modifiers = Object.freeze({ VariablesNumber: '-vn', CustomDiceShapes: '-cd', NoSpaces: '-ns', + YVars: '-yvariables', }); // args will look like this: ['-sn', ' ', '10'] as spaces/newlines are split on their own @@ -204,6 +205,15 @@ export const getModifiers = (args: string[]): [RollModifiers, string[]] => { case Modifiers.NoSpaces: modifiers.noSpaces = true; break; + case Modifiers.YVars: { + // Shift the -yvariables out of the array so the next item is the first yVar + args.splice(i, 2); + const yVars = args[i].split(','); + yVars.forEach((yVar, idx) => { + modifiers.yVars.set(`y${idx}`, parseFloat(yVar)); + }); + break; + } default: // Default case should not mess with the array defaultCase = true; diff --git a/src/artigen/utils/escape.ts b/src/artigen/utils/escape.ts index 90d2434..cc15968 100644 --- a/src/artigen/utils/escape.ts +++ b/src/artigen/utils/escape.ts @@ -41,3 +41,6 @@ export const internalWrapRegex = new RegExp(`([${openInternal}${closeInternal}]) export const openInternalGrp = '\u2e20'; export const closeInternalGrp = '\u2e21'; export const internalGrpWrapRegex = new RegExp(`([${openInternalGrp}${closeInternalGrp}])`, 'g'); + +// Marker to look for when repeating a roll AND it was from a SLASH COMMAND alias run command +export const withYVarsDash = '\u2043'; diff --git a/src/artigen/utils/sortFuncs.ts b/src/artigen/utils/sortFuncs.ts index 0e10516..96a20cb 100644 --- a/src/artigen/utils/sortFuncs.ts +++ b/src/artigen/utils/sortFuncs.ts @@ -49,3 +49,12 @@ export const compareOrigIdx = (a: RollSet | ReturnData, b: RollSet | ReturnData) } return 0; }; + +// Sort yVars by their name +export const sortYVars = (a: string, b: string) => { + if (a.length < b.length) return -1; + if (a.length > b.length) return 1; + if (a < b) return -1; + if (a > b) return 1; + return 0; +}; diff --git a/src/commands/aliasCmd/aliasAddUpdate.ts b/src/commands/aliasCmd/aliasAddUpdate.ts index bec8784..8916c64 100644 --- a/src/commands/aliasCmd/aliasAddUpdate.ts +++ b/src/commands/aliasCmd/aliasAddUpdate.ts @@ -10,6 +10,7 @@ import { sendRollRequest } from 'artigen/managers/queueManager.ts'; import { cmdSplitRegex } from 'artigen/utils/escape.ts'; import { assertPrePostBalance, getMatchingPostfixIdx } from 'artigen/utils/parenBalance.ts'; +import { sortYVars } from 'artigen/utils/sortFuncs.ts'; import { ReservedWords } from 'commands/aliasCmd/reservedWords.ts'; @@ -26,14 +27,6 @@ interface QueryShape { aliasName: string; } -const sortYVars = (a: string, b: string) => { - if (a.length < b.length) return -1; - if (a.length > b.length) return 1; - if (a < b) return -1; - if (a > b) return 1; - return 0; -}; - const handleAddUpdate = async ( msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, diff --git a/src/commands/helpLibrary/rollHelp/decorators.ts b/src/commands/helpLibrary/rollHelp/decorators.ts index 199e691..cef0204 100644 --- a/src/commands/helpLibrary/rollHelp/decorators.ts +++ b/src/commands/helpLibrary/rollHelp/decorators.ts @@ -207,6 +207,20 @@ Removes the default padding added space between rolls.`, ], }, ], + [ + '-yvariables', + { + name: 'Y Variables', + description: `**Usage:** \`-yvariables y0,y1,...,yN\` + +Intended for internal use only, but it's implementation makes it accessible publicly, so this documentation explains what its for and why it exists. + +Allows a comma separated list of number to be passed in for y variables, see \`Miscellaneous Features>Variables\` and \`Roll Alias System>Add New Alias\` for what y variables are. + +This decorator exists to allow for the Repeat Roll button to work consistently.`, + example: ['`[[d20+y0+y1]] -yvariables 10,37` => `[[d20+10+37]]` => [15]+10+37 = 62'], + }, + ], ]); export const DecoratorsHelpPages: HelpPage = { diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index b5dda18..4b9208b 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -15,10 +15,12 @@ import { } from '@discordeno'; import { log, LogTypes as LT } from '@Log4Deno'; +import { Modifiers } from 'artigen/dice/getModifiers.ts'; + import { repeatRollCustomId } from 'artigen/managers/handler/workerComplete.ts'; import { toggleWebView, webViewCustomId } from 'artigen/utils/embeds.ts'; -import { argSpacesSplitRegex } from 'artigen/utils/escape.ts'; +import { argSpacesSplitRegex, withYVarsDash } from 'artigen/utils/escape.ts'; import { commands, slashCommandDetails } from 'commands/_index.ts'; @@ -104,7 +106,20 @@ export const interactionCreateHandler = async (interaction: Interaction) => { if (botMsg && botMsg.embeds.length) { const rollEmbed = botMsg.embeds[0].description ?? ''; const rollStrStartIdx = rollEmbed.indexOf('`') + 1; - const rollStr = rollEmbed.substring(rollStrStartIdx, rollEmbed.indexOf('`', rollStrStartIdx)); + let rollStr = rollEmbed.substring(rollStrStartIdx, rollEmbed.indexOf('`', rollStrStartIdx)); + + // Since we're dealing with a slash command, we can't get the original command (as far as I know), so rebuild the yVars for an alias using what is in the response message + if (rollEmbed.includes(withYVarsDash)) { + const yVarStartIdx = rollEmbed.indexOf(withYVarsDash) + 1; + const yVarStr = rollEmbed.substring(rollEmbed.indexOf(':', yVarStartIdx) + 1, rollEmbed.indexOf('\n', yVarStartIdx)).trim(); + const yVars = yVarStr.split(' ').filter((x) => x); + const yVarVals: string[] = []; + for (const yVar of yVars) { + const [_yVarName, yVarVal] = yVar.split('='); + yVarVals.push(yVarVal); + } + rollStr += ` ${Modifiers.YVars} ${yVarVals.join(',')}`; + } commands.roll(interaction, rollStr.split(argSpacesSplitRegex), ''); return; }