Add simulated nominal flag
This commit is contained in:
parent
8793011350
commit
9d6b389d71
|
@ -5,7 +5,7 @@ meta {
|
||||||
}
|
}
|
||||||
|
|
||||||
get {
|
get {
|
||||||
url: http://localhost:8166/api/roll?user=[discord-user-id]&channel=[discord-channel-id]&rollstr=[artificer-roll-cmd]&documentation=All items below are optional. Flags do not need values.&nd=[no-details-flag]&snd=[super-no-details-flag]&hr=[hide-raw-roll-details-flag]&s=[spoiler-results-flag]&m-or-max=[max-roll-flag, cannot be used with n flag]&min=[min-roll-flag, cannot be used with n or max]&n=[nominal-roll-flag, cannot be used with max or min flag]&gms=[csv-of-discord-user-ids-to-be-dmed-results]&o=[order-rolls, must be a or d]&c=[count-flag]&cc=[confirm-crit-flag]&rd=[roll-dist-flag]
|
url: http://localhost:8166/api/roll?user=[discord-user-id]&channel=[discord-channel-id]&rollstr=[artificer-roll-cmd]&documentation=All items below are optional. Flags do not need values.&nd=[no-details-flag]&snd=[super-no-details-flag]&hr=[hide-raw-roll-details-flag]&s=[spoiler-results-flag]&m-or-max=[max-roll-flag, cannot be used with n flag]&min=[min-roll-flag, cannot be used with n, sn, or max]&n=[nominal-roll-flag, cannot be used with sn, max or min flag]&sn=[simulated-nominal-flag, cannot be used with max, min, n. or cc]&gms=[csv-of-discord-user-ids-to-be-dmed-results]&o=[order-rolls, must be a or d]&c=[count-flag]&cc=[confirm-crit-flag, cannot be used with sn]&rd=[roll-dist-flag]
|
||||||
body: none
|
body: none
|
||||||
auth: inherit
|
auth: inherit
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,12 @@ params:query {
|
||||||
hr: [hide-raw-roll-details-flag]
|
hr: [hide-raw-roll-details-flag]
|
||||||
s: [spoiler-results-flag]
|
s: [spoiler-results-flag]
|
||||||
m-or-max: [max-roll-flag, cannot be used with n flag]
|
m-or-max: [max-roll-flag, cannot be used with n flag]
|
||||||
min: [min-roll-flag, cannot be used with n or max]
|
min: [min-roll-flag, cannot be used with n, sn, or max]
|
||||||
n: [nominal-roll-flag, cannot be used with max or min flag]
|
n: [nominal-roll-flag, cannot be used with sn, max or min flag]
|
||||||
|
sn: [simulated-nominal-flag, can pass number with it, cannot be used with max, min, n. or cc]
|
||||||
gms: [csv-of-discord-user-ids-to-be-dmed-results]
|
gms: [csv-of-discord-user-ids-to-be-dmed-results]
|
||||||
o: [order-rolls, must be a or d]
|
o: [order-rolls, must be a or d]
|
||||||
c: [count-flag]
|
c: [count-flag]
|
||||||
cc: [confirm-crit-flag]
|
cc: [confirm-crit-flag, cannot be used with sn]
|
||||||
rd: [roll-dist-flag]
|
rd: [roll-dist-flag]
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,13 +126,14 @@ The Artificer comes with a few supplemental commands to the main rolling command
|
||||||
* `-nd` - No Details - Suppresses all details of the requested roll
|
* `-nd` - No Details - Suppresses all details of the requested roll
|
||||||
* `-snd` - Super No Details - Suppresses all details of the requested roll and hides no details message
|
* `-snd` - Super No Details - Suppresses all details of the requested roll and hides no details message
|
||||||
* `-s` - Spoiler - Spoilers all details of the requested roll
|
* `-s` - Spoiler - Spoilers all details of the requested roll
|
||||||
* `-m` or `-max` - Maximize Roll - Rolls the theoretical maximum roll, cannot be used with `-n` or `-min`
|
* `-m` or `-max` - Maximize Roll - Rolls the theoretical maximum roll, cannot be used with `-n`, `-min`, or `-sn`
|
||||||
* `-min` - Minimize Roll - Rolls the theoretical minimum roll, cannot be used with `-m`, `-max`, or `-n`
|
* `-min` - Minimize Roll - Rolls the theoretical minimum roll, cannot be used with `-m`, `-max`, `-n`, or `-sn`
|
||||||
* `-n` - Nominal Roll - Rolls the theoretical nominal roll, cannot be used with `-m`, `-max`, or `-min`
|
* `-n` - Nominal Roll - Rolls the theoretical nominal roll, cannot be used with `-m`, `-max`, `-min`, or `-sn`
|
||||||
|
* `-sn` or `-sn [number]` - Simulated Nominal - 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, cannot be used with `-m`, `-max`, `-min`, `-n`, or `-cc`
|
||||||
* `-gm @user1 @user2 ... @userN` - GM Roll - Rolls the requested roll in GM mode, suppressing all publicly shown results and details and sending the results directly to the specified GMs
|
* `-gm @user1 @user2 ... @userN` - GM Roll - Rolls the requested roll in GM mode, suppressing all publicly shown results and details and sending the results directly to the specified GMs
|
||||||
* `-o a` or `-o d` - Order Roll - Rolls the requested roll and orders the results in the requested direction
|
* `-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
|
* `-ct` - Comma Totals - Adds commas to totals for readability
|
||||||
* `-cc` - Confirm Critical Hits - Automatically rerolls whenever a crit hits
|
* `-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
|
||||||
* The results have some formatting applied on them to provide details on what happened during this roll.
|
* The results have some formatting applied on them to provide details on what happened during this roll.
|
||||||
* Critical successes will be **bolded**
|
* Critical successes will be **bolded**
|
||||||
|
|
|
@ -11,6 +11,7 @@ export const config = {
|
||||||
maxLoops: 1000000, // Determines how long the bot will attempt a roll, number of loops before it kills a roll. Increase this at your own risk.
|
maxLoops: 1000000, // Determines how long the bot will attempt a roll, number of loops before it kills a roll. Increase this at your own risk.
|
||||||
maxWorkers: 16, // Maximum number of worker threads to spawn at once (Set this to less than the number of threads your CPU has, Artificer will eat it all if too many rolls happen at once)
|
maxWorkers: 16, // Maximum number of worker threads to spawn at once (Set this to less than the number of threads your CPU has, Artificer will eat it all if too many rolls happen at once)
|
||||||
workerTimeout: 300000, // Maximum time before the bot kills a worker thread in ms
|
workerTimeout: 300000, // Maximum time before the bot kills a worker thread in ms
|
||||||
|
simulatedNominal: 100000, // Number of loops to run for simulating a nominal
|
||||||
},
|
},
|
||||||
api: {
|
api: {
|
||||||
// Setting for the built-in API
|
// Setting for the built-in API
|
||||||
|
|
|
@ -61,13 +61,18 @@ export const runCmd = (rollRequest: QueuedRoll): SolvedRoll => {
|
||||||
line2 = resultStr;
|
line2 = resultStr;
|
||||||
|
|
||||||
// If a theoretical roll is requested, mark the output as such, else use default formatting
|
// If a theoretical roll is requested, mark the output as such, else use default formatting
|
||||||
if (rollRequest.modifiers.maxRoll || rollRequest.modifiers.minRoll || rollRequest.modifiers.nominalRoll) {
|
const theoreticalBools = [
|
||||||
const theoreticalTexts = ['Maximum', 'Minimum', 'Nominal'];
|
rollRequest.modifiers.maxRoll,
|
||||||
const theoreticalBools = [rollRequest.modifiers.maxRoll, rollRequest.modifiers.minRoll, rollRequest.modifiers.nominalRoll];
|
rollRequest.modifiers.minRoll,
|
||||||
|
rollRequest.modifiers.nominalRoll,
|
||||||
|
rollRequest.modifiers.simulatedNominal > 0,
|
||||||
|
];
|
||||||
|
if (theoreticalBools.includes(true)) {
|
||||||
|
const theoreticalTexts = ['Theoretical Maximum', 'Theoretical Minimum', 'Theoretical Nominal', 'Simulated Nominal'];
|
||||||
const theoreticalText = theoreticalTexts[theoreticalBools.indexOf(true)];
|
const theoreticalText = theoreticalTexts[theoreticalBools.indexOf(true)];
|
||||||
|
|
||||||
line1 = ` requested the Theoretical ${theoreticalText} of:\n\`${rawCmd}\``;
|
line1 = ` requested the ${theoreticalText.toLowerCase()} of:\n\`${rawCmd}\``;
|
||||||
line2 = `Theoretical ${theoreticalText} ${resultStr}`;
|
line2 = `${theoreticalText} ${resultStr}`;
|
||||||
} else if (rollRequest.modifiers.order === 'a') {
|
} else if (rollRequest.modifiers.order === 'a') {
|
||||||
line1 = ` requested the following rolls to be ordered from least to greatest:\n\`${rawCmd}\``;
|
line1 = ` requested the following rolls to be ordered from least to greatest:\n\`${rawCmd}\``;
|
||||||
tempReturnData.sort(compareTotalRolls);
|
tempReturnData.sort(compareTotalRolls);
|
||||||
|
@ -78,6 +83,8 @@ export const runCmd = (rollRequest: QueuedRoll): SolvedRoll => {
|
||||||
line1 = ` rolled:\n\`${rawCmd}\``;
|
line1 = ` rolled:\n\`${rawCmd}\``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rollRequest.modifiers.simulatedNominal) line2 += `Iterations performed per roll: \`${rollRequest.modifiers.simulatedNominal}\`\n`;
|
||||||
|
|
||||||
// Fill out all of the details and results now
|
// Fill out all of the details and results now
|
||||||
tempReturnData.forEach((e) => {
|
tempReturnData.forEach((e) => {
|
||||||
loopCountCheck();
|
loopCountCheck();
|
||||||
|
@ -86,14 +93,16 @@ export const runCmd = (rollRequest: QueuedRoll): SolvedRoll => {
|
||||||
let preFormat = '';
|
let preFormat = '';
|
||||||
let postFormat = '';
|
let postFormat = '';
|
||||||
|
|
||||||
// If the roll contained a crit success or fail, set the formatting around it
|
if (!rollRequest.modifiers.simulatedNominal) {
|
||||||
if (e.containsCrit) {
|
// If the roll contained a crit success or fail, set the formatting around it
|
||||||
preFormat = `**${preFormat}`;
|
if (e.containsCrit) {
|
||||||
postFormat = `${postFormat}**`;
|
preFormat = `**${preFormat}`;
|
||||||
}
|
postFormat = `${postFormat}**`;
|
||||||
if (e.containsFail) {
|
}
|
||||||
preFormat = `__${preFormat}`;
|
if (e.containsFail) {
|
||||||
postFormat = `${postFormat}__`;
|
preFormat = `__${preFormat}`;
|
||||||
|
postFormat = `${postFormat}__`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate line2 (the results) and line3 (the details) with their data
|
// Populate line2 (the results) and line3 (the details) with their data
|
||||||
|
@ -106,7 +115,7 @@ export const runCmd = (rollRequest: QueuedRoll): SolvedRoll => {
|
||||||
line2 += `${preFormat}${rollRequest.modifiers.commaTotals ? e.rollTotal.toLocaleString() : e.rollTotal}${postFormat}, `;
|
line2 += `${preFormat}${rollRequest.modifiers.commaTotals ? e.rollTotal.toLocaleString() : e.rollTotal}${postFormat}, `;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rollDetails = rollRequest.modifiers.noDetails ? ' = ' : ` = ${e.rollDetails} = `;
|
const rollDetails = rollRequest.modifiers.noDetails || rollRequest.modifiers.simulatedNominal > 0 ? ' = ' : ` = ${e.rollDetails} = `;
|
||||||
line3 += `\`${e.initConfig}\`${rollDetails}${preFormat}${rollRequest.modifiers.commaTotals ? e.rollTotal.toLocaleString() : e.rollTotal}${postFormat}\n`;
|
line3 += `\`${e.initConfig}\`${rollDetails}${preFormat}${rollRequest.modifiers.commaTotals ? e.rollTotal.toLocaleString() : e.rollTotal}${postFormat}\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,14 @@ import { reduceCountDetails } from 'artigen/utils/counter.ts';
|
||||||
import { closeInternal, internalWrapRegex, openInternal } from 'artigen/utils/escape.ts';
|
import { closeInternal, internalWrapRegex, openInternal } from 'artigen/utils/escape.ts';
|
||||||
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
||||||
import { getMatchingInternalIdx, getMatchingPostfixIdx } from 'artigen/utils/parenBalance.ts';
|
import { getMatchingInternalIdx, getMatchingPostfixIdx } from 'artigen/utils/parenBalance.ts';
|
||||||
|
import { basicReducer } from 'artigen/utils/reducers.ts';
|
||||||
|
|
||||||
// tokenizeCmd expects a string[] of items that are either config.prefix/config.postfix or some text that contains math and/or dice rolls
|
// tokenizeCmd expects a string[] of items that are either config.prefix/config.postfix or some text that contains math and/or dice rolls
|
||||||
export const tokenizeCmd = (
|
export const tokenizeCmd = (
|
||||||
cmd: string[],
|
cmd: string[],
|
||||||
modifiers: RollModifiers,
|
modifiers: RollModifiers,
|
||||||
topLevel: boolean,
|
topLevel: boolean,
|
||||||
previousResults: number[] = [],
|
previousResults: number[] = []
|
||||||
): [ReturnData[], CountDetails[], RollDistributionMap[]] => {
|
): [ReturnData[], CountDetails[], RollDistributionMap[]] => {
|
||||||
loggingEnabled && log(LT.LOG, `Tokenizing command ${JSON.stringify(cmd)}`);
|
loggingEnabled && log(LT.LOG, `Tokenizing command ${JSON.stringify(cmd)}`);
|
||||||
|
|
||||||
|
@ -37,56 +38,90 @@ export const tokenizeCmd = (
|
||||||
|
|
||||||
const currentCmd = cmd.slice(openIdx + 1, closeIdx);
|
const currentCmd = cmd.slice(openIdx + 1, closeIdx);
|
||||||
|
|
||||||
loggingEnabled && log(LT.LOG, `Setting previous results: topLevel:${topLevel} ${topLevel ? returnData.map((rd) => rd.rollTotal) : previousResults}`);
|
const simulatedLoopCount = modifiers.simulatedNominal || 1;
|
||||||
|
|
||||||
// Handle any nested commands
|
loggingEnabled &&
|
||||||
const [tempData, tempCounts, tempDists] = tokenizeCmd(currentCmd, modifiers, false, topLevel ? returnData.map((rd) => rd.rollTotal) : previousResults);
|
log(
|
||||||
const data = tempData[0];
|
LT.LOG,
|
||||||
|
`Setting previous results: topLevel:${topLevel} ${
|
||||||
|
topLevel ? returnData.map((rd) => rd.rollTotal) : previousResults
|
||||||
|
} simulatedLoopCount:${simulatedLoopCount}`
|
||||||
|
);
|
||||||
|
|
||||||
if (topLevel) {
|
const simulatedData: ReturnData[] = [];
|
||||||
// Handle saving any formatting between dice
|
for (let i = 0; i < simulatedLoopCount; i++) {
|
||||||
if (openIdx !== 0) {
|
loopCountCheck();
|
||||||
data.rollPreFormat = cmd.slice(0, openIdx).join('');
|
|
||||||
|
loggingEnabled && log(LT.LOG, `In simLoop:${i} "${currentCmd}" of ${JSON.stringify(cmd)}`);
|
||||||
|
|
||||||
|
// Handle any nested commands
|
||||||
|
const [tempData, tempCounts, tempDists] = tokenizeCmd(currentCmd, modifiers, false, topLevel ? returnData.map((rd) => rd.rollTotal) : previousResults);
|
||||||
|
const data = tempData[0];
|
||||||
|
loggingEnabled && log(LT.LOG, `Data back from tokenizeCmd, "${currentCmd}" of "${JSON.stringify(cmd)}" ${JSON.stringify(data)}`);
|
||||||
|
|
||||||
|
// Only run this on first loop
|
||||||
|
if (topLevel && i === 0) {
|
||||||
|
// Handle saving any formatting between dice
|
||||||
|
if (openIdx !== 0) {
|
||||||
|
data.rollPreFormat = cmd.slice(0, openIdx).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chop off all formatting between cmds along with the processed cmd
|
||||||
|
cmd.splice(0, closeIdx + 1);
|
||||||
}
|
}
|
||||||
|
// Store results
|
||||||
|
modifiers.simulatedNominal ? simulatedData.push(data) : returnData.push(data);
|
||||||
|
countDetails.push(...tempCounts);
|
||||||
|
rollDists.push(...tempDists);
|
||||||
|
|
||||||
// Chop off all formatting between cmds along with the processed cmd
|
// Handle ConfirmCrit if its on
|
||||||
cmd.splice(0, closeIdx + 1);
|
if (topLevel && modifiers.confirmCrit && reduceCountDetails(tempCounts).successful) {
|
||||||
} else {
|
loggingEnabled && log(LT.LOG, `ConfirmCrit on ${JSON.stringify(currentCmd)}`);
|
||||||
// We're handling something nested, replace [[cmd]] with the cmd's result
|
let done = false;
|
||||||
cmd.splice(openIdx, closeIdx - openIdx + 1, `${openInternal}${data.rollTotal}${closeInternal}`);
|
while (!done) {
|
||||||
|
loopCountCheck();
|
||||||
|
|
||||||
|
// Keep running the same roll again until its not successful
|
||||||
|
const [ccTempData, ccTempCounts, ccTempDists] = tokenizeCmd(
|
||||||
|
currentCmd,
|
||||||
|
modifiers,
|
||||||
|
false,
|
||||||
|
topLevel ? returnData.map((rd) => rd.rollTotal) : previousResults
|
||||||
|
);
|
||||||
|
const ccData = ccTempData[0];
|
||||||
|
ccData.rollPreFormat = '\nAuto-Confirming Crit: ';
|
||||||
|
|
||||||
|
loggingEnabled &&
|
||||||
|
log(LT.LOG, `ConfirmCrit on ${JSON.stringify(currentCmd)} | Rolled again ${JSON.stringify(ccData)} ${JSON.stringify(ccTempCounts)}`);
|
||||||
|
|
||||||
|
// Store CC results
|
||||||
|
returnData.push(ccData);
|
||||||
|
countDetails.push(...ccTempCounts);
|
||||||
|
rollDists.push(...ccTempDists);
|
||||||
|
|
||||||
|
done = reduceCountDetails(ccTempCounts).successful === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store results
|
// Turn the simulated return data into a single usable payload
|
||||||
returnData.push(data);
|
if (modifiers.simulatedNominal) {
|
||||||
countDetails.push(...tempCounts);
|
loggingEnabled && log(LT.LOG, `SN on, condensing array into single item ${JSON.stringify(simulatedData)}`);
|
||||||
rollDists.push(...tempDists);
|
returnData.push({
|
||||||
|
rollTotal: simulatedData.map((data) => data.rollTotal).reduce(basicReducer) / simulatedData.length,
|
||||||
|
rollPreFormat: simulatedData[0].rollPreFormat,
|
||||||
|
rollPostFormat: simulatedData[0].rollPostFormat,
|
||||||
|
rollDetails: simulatedData[0].rollDetails,
|
||||||
|
containsCrit: simulatedData.some((data) => data.containsCrit),
|
||||||
|
containsFail: simulatedData.some((data) => data.containsFail),
|
||||||
|
initConfig: simulatedData[0].initConfig,
|
||||||
|
});
|
||||||
|
loggingEnabled && log(LT.LOG, `SN on, returnData updated ${JSON.stringify(returnData)}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle ConfirmCrit if its on
|
// Finally, if we are handling a nested [[cmd]], fill in the rollTotal correctly
|
||||||
if (topLevel && modifiers.confirmCrit && reduceCountDetails(tempCounts).successful) {
|
if (!topLevel) {
|
||||||
loggingEnabled && log(LT.LOG, `ConfirmCrit on ${JSON.stringify(currentCmd)}`);
|
cmd.splice(openIdx, closeIdx - openIdx + 1, `${openInternal}${Math.round(returnData[returnData.length - 1].rollTotal)}${closeInternal}`);
|
||||||
let done = false;
|
|
||||||
while (!done) {
|
|
||||||
loopCountCheck();
|
|
||||||
|
|
||||||
// Keep running the same roll again until its not successful
|
|
||||||
const [ccTempData, ccTempCounts, ccTempDists] = tokenizeCmd(
|
|
||||||
currentCmd,
|
|
||||||
modifiers,
|
|
||||||
false,
|
|
||||||
topLevel ? returnData.map((rd) => rd.rollTotal) : previousResults,
|
|
||||||
);
|
|
||||||
const ccData = ccTempData[0];
|
|
||||||
ccData.rollPreFormat = '\nAuto-Confirming Crit: ';
|
|
||||||
|
|
||||||
loggingEnabled && log(LT.LOG, `ConfirmCrit on ${JSON.stringify(currentCmd)} | Rolled again ${JSON.stringify(ccData)} ${JSON.stringify(ccTempCounts)}`);
|
|
||||||
|
|
||||||
// Store CC results
|
|
||||||
returnData.push(ccData);
|
|
||||||
countDetails.push(...ccTempCounts);
|
|
||||||
rollDists.push(...ccTempDists);
|
|
||||||
|
|
||||||
done = reduceCountDetails(ccTempCounts).successful === 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ export interface RollModifiers {
|
||||||
maxRoll: boolean;
|
maxRoll: boolean;
|
||||||
minRoll: boolean;
|
minRoll: boolean;
|
||||||
nominalRoll: boolean;
|
nominalRoll: boolean;
|
||||||
|
simulatedNominal: number;
|
||||||
gmRoll: boolean;
|
gmRoll: boolean;
|
||||||
gms: string[];
|
gms: string[];
|
||||||
order: string;
|
order: string;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { log, LogTypes as LT } from '@Log4Deno';
|
import { log, LogTypes as LT } from '@Log4Deno';
|
||||||
|
|
||||||
import { RollModifiers } from 'artigen/dice/dice.d.ts';
|
import { RollModifiers } from 'artigen/dice/dice.d.ts';
|
||||||
|
import config from '~config';
|
||||||
|
|
||||||
export const Modifiers = Object.freeze({
|
export const Modifiers = Object.freeze({
|
||||||
Count: '-c',
|
Count: '-c',
|
||||||
|
@ -12,6 +13,7 @@ export const Modifiers = Object.freeze({
|
||||||
MaxShorthand: '-m',
|
MaxShorthand: '-m',
|
||||||
Min: '-min',
|
Min: '-min',
|
||||||
Nominal: '-n',
|
Nominal: '-n',
|
||||||
|
SimulatedNominal: '-sn',
|
||||||
GM: '-gm',
|
GM: '-gm',
|
||||||
Order: '-o',
|
Order: '-o',
|
||||||
CommaTotals: '-ct',
|
CommaTotals: '-ct',
|
||||||
|
@ -28,6 +30,7 @@ export const getModifiers = (args: string[]): [RollModifiers, string[]] => {
|
||||||
maxRoll: false,
|
maxRoll: false,
|
||||||
minRoll: false,
|
minRoll: false,
|
||||||
nominalRoll: false,
|
nominalRoll: false,
|
||||||
|
simulatedNominal: 0,
|
||||||
gmRoll: false,
|
gmRoll: false,
|
||||||
gms: [],
|
gms: [],
|
||||||
order: '',
|
order: '',
|
||||||
|
@ -36,7 +39,7 @@ export const getModifiers = (args: string[]): [RollModifiers, string[]] => {
|
||||||
confirmCrit: false,
|
confirmCrit: false,
|
||||||
rollDist: false,
|
rollDist: false,
|
||||||
apiWarn: '',
|
apiWarn: '',
|
||||||
valid: false,
|
valid: true,
|
||||||
error: new Error(),
|
error: new Error(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,6 +73,16 @@ export const getModifiers = (args: string[]): [RollModifiers, string[]] => {
|
||||||
case Modifiers.Nominal:
|
case Modifiers.Nominal:
|
||||||
modifiers.nominalRoll = true;
|
modifiers.nominalRoll = true;
|
||||||
break;
|
break;
|
||||||
|
case Modifiers.SimulatedNominal:
|
||||||
|
if (args[i + 1] && parseInt(args[i + 1]).toString() === args[i + 1]) {
|
||||||
|
// Shift the -sn out so the next item is the amount
|
||||||
|
args.splice(i, 1);
|
||||||
|
|
||||||
|
modifiers.simulatedNominal = parseInt(args[i]);
|
||||||
|
} else {
|
||||||
|
modifiers.simulatedNominal = 10000;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Modifiers.ConfirmCrit:
|
case Modifiers.ConfirmCrit:
|
||||||
modifiers.confirmCrit = true;
|
modifiers.confirmCrit = true;
|
||||||
break;
|
break;
|
||||||
|
@ -121,13 +134,26 @@ export const getModifiers = (args: string[]): [RollModifiers, string[]] => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// maxRoll, minRoll, and nominalRoll cannot be on at same time, throw an error
|
// maxRoll, minRoll, nominalRoll, simulatedNominal cannot be on at same time, throw an error
|
||||||
if ([modifiers.maxRoll, modifiers.minRoll, modifiers.nominalRoll].filter((b) => b).length > 1) {
|
if ([modifiers.maxRoll, modifiers.minRoll, modifiers.nominalRoll, modifiers.simulatedNominal].filter((b) => b).length > 1) {
|
||||||
modifiers.error.name = 'MaxAndNominal';
|
modifiers.error.name = 'MaxAndNominal';
|
||||||
modifiers.error.message = 'Can only use one of the following at a time:\n`maximize`, `minimize`, `nominal`';
|
modifiers.error.message = 'Can only use one of the following at a time:\n`maximize`, `minimize`, `nominal`, `simulatedNominal`';
|
||||||
return [modifiers, args];
|
modifiers.valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulatedNominal and confirmCrit cannot be used at same time, throw an error
|
||||||
|
if ([modifiers.confirmCrit, modifiers.simulatedNominal].filter((b) => b).length > 1) {
|
||||||
|
modifiers.error.name = 'SimNominalAndCC';
|
||||||
|
modifiers.error.message = 'Cannot use the following at the same time:\n`confirmCrit`, `simulatedNominal`';
|
||||||
|
modifiers.valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulatedNominal cannot be greater than config.limits.simulatedNominal
|
||||||
|
if (modifiers.simulatedNominal > config.limits.simulatedNominal) {
|
||||||
|
modifiers.error.name = 'SimNominalTooBig';
|
||||||
|
modifiers.error.message = `Number of iterations for \`simulatedNominal\` cannot be greater than \`${config.limits.simulatedNominal}\``;
|
||||||
|
modifiers.valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiers.valid = true;
|
|
||||||
return [modifiers, args];
|
return [modifiers, args];
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,6 +81,8 @@ export const apiRoll = async (query: Map<string, string>, apiUserid: bigint): Pr
|
||||||
// Clip off the leading prefix. API calls must be formatted with a prefix at the start to match how commands are sent in Discord
|
// Clip off the leading prefix. API calls must be formatted with a prefix at the start to match how commands are sent in Discord
|
||||||
rollCmd = rollCmd.replace(/%20/g, ' ').trim();
|
rollCmd = rollCmd.replace(/%20/g, ' ').trim();
|
||||||
|
|
||||||
|
const rawSimNom = parseInt(query.get('sn') ?? '0');
|
||||||
|
const simNom = rawSimNom || 10000;
|
||||||
const modifiers: RollModifiers = {
|
const modifiers: RollModifiers = {
|
||||||
noDetails: query.has('nd'),
|
noDetails: query.has('nd'),
|
||||||
superNoDetails: query.has('snd'),
|
superNoDetails: query.has('snd'),
|
||||||
|
@ -89,6 +91,7 @@ export const apiRoll = async (query: Map<string, string>, apiUserid: bigint): Pr
|
||||||
maxRoll: query.has('m') || query.has('max'),
|
maxRoll: query.has('m') || query.has('max'),
|
||||||
minRoll: query.has('min'),
|
minRoll: query.has('min'),
|
||||||
nominalRoll: query.has('n'),
|
nominalRoll: query.has('n'),
|
||||||
|
simulatedNominal: query.has('sn') ? simNom : 0,
|
||||||
gmRoll: query.has('gms'),
|
gmRoll: query.has('gms'),
|
||||||
gms: query.has('gms') ? (query.get('gms') || '').split(',') : [],
|
gms: query.has('gms') ? (query.get('gms') || '').split(',') : [],
|
||||||
order: query.has('o') ? query.get('o')?.toLowerCase() || '' : '',
|
order: query.has('o') ? query.get('o')?.toLowerCase() || '' : '',
|
||||||
|
@ -101,6 +104,21 @@ export const apiRoll = async (query: Map<string, string>, apiUserid: bigint): Pr
|
||||||
error: new Error(),
|
error: new Error(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// maxRoll, minRoll, and nominalRoll cannot be on at same time, throw an error
|
||||||
|
if ([modifiers.maxRoll, modifiers.minRoll, modifiers.nominalRoll, modifiers.simulatedNominal].filter((b) => b).length > 1) {
|
||||||
|
return stdResp.BadRequest('Can only use one of the following at a time:\n`maximize`, `minimize`, `nominal`, `simulatedNominal`');
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulatedNominal and confirmCrit cannot be used at same time, throw an error
|
||||||
|
if ([modifiers.confirmCrit, modifiers.simulatedNominal].filter((b) => b).length > 1) {
|
||||||
|
return stdResp.BadRequest('Cannot use the following at the same time:\n`confirmCrit`, `simulatedNominal`');
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulatedNominal cannot be greater than config.limits.simulatedNominal
|
||||||
|
if (modifiers.simulatedNominal > config.limits.simulatedNominal) {
|
||||||
|
return stdResp.BadRequest(`Number of iterations for \`simulatedNominal\` cannot be greater than \`${config.limits.simulatedNominal}\``);
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise<Response>((resolve) => {
|
return new Promise<Response>((resolve) => {
|
||||||
sendRollRequest({
|
sendRollRequest({
|
||||||
apiRoll: true,
|
apiRoll: true,
|
||||||
|
@ -120,7 +138,7 @@ export const apiRoll = async (query: Map<string, string>, apiUserid: bigint): Pr
|
||||||
} else {
|
} else {
|
||||||
// Alert API user that they messed up
|
// Alert API user that they messed up
|
||||||
return stdResp.Forbidden(
|
return stdResp.Forbidden(
|
||||||
`Verify you are a member of the guild you are sending this roll to. If you are, the ${config.name} may not have that registered, please send a message in the guild so ${config.name} can register this. This registration is temporary, so if you see this error again, just poke your server again.`,
|
`Verify you are a member of the guild you are sending this roll to. If you are, the ${config.name} may not have that registered, please send a message in the guild so ${config.name} can register this. This registration is temporary, so if you see this error again, just poke your server again.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue