Properly handle mt! or !m (or other future no number mashups)
This commit is contained in:
parent
0e009441ca
commit
5f58f9cae8
|
@ -0,0 +1,52 @@
|
||||||
|
export const DiceOptions = Object.freeze({
|
||||||
|
Drop: 'd',
|
||||||
|
DropLow: 'dl',
|
||||||
|
DropHigh: 'dh',
|
||||||
|
Keep: 'k',
|
||||||
|
KeepLow: 'kl',
|
||||||
|
KeepHigh: 'kh',
|
||||||
|
Reroll: 'r',
|
||||||
|
RerollLt: 'r<',
|
||||||
|
RerollGtr: 'r>',
|
||||||
|
RerollEqu: 'r=',
|
||||||
|
RerollOnce: 'ro',
|
||||||
|
RerollOnceLt: 'ro<',
|
||||||
|
RerollOnceGtr: 'ro>',
|
||||||
|
RerollOnceEqu: 'ro=',
|
||||||
|
CritSuccess: 'cs',
|
||||||
|
CritSuccessLt: 'cs<',
|
||||||
|
CritSuccessGtr: 'cs>',
|
||||||
|
CritSuccessEqu: 'cs=',
|
||||||
|
CritFail: 'cf',
|
||||||
|
CritFailLt: 'cf<',
|
||||||
|
CritFailGtr: 'cf>',
|
||||||
|
CritFailEqu: 'cf=',
|
||||||
|
Exploding: '!',
|
||||||
|
ExplodingLt: '!<',
|
||||||
|
ExplodingGtr: '!>',
|
||||||
|
ExplodingEqu: '!=',
|
||||||
|
ExplodeOnce: '!o',
|
||||||
|
ExplodeOnceLt: '!o<',
|
||||||
|
ExplodeOnceGtr: '!o>',
|
||||||
|
ExplodeOnceEqu: '!o=',
|
||||||
|
PenetratingExplosion: '!p',
|
||||||
|
PenetratingExplosionLt: '!p<',
|
||||||
|
PenetratingExplosionGtr: '!p>',
|
||||||
|
PenetratingExplosionEqu: '!p=',
|
||||||
|
CompoundingExplosion: '!!',
|
||||||
|
CompoundingExplosionLt: '!!<',
|
||||||
|
CompoundingExplosionGtr: '!!>',
|
||||||
|
CompoundingExplosionEqu: '!!=',
|
||||||
|
Matching: 'm',
|
||||||
|
MatchingTotal: 'mt',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Should be ordered such that 'mt' will be encountered before 'm'
|
||||||
|
export const NumberlessDiceOptions = [
|
||||||
|
DiceOptions.MatchingTotal,
|
||||||
|
DiceOptions.Matching,
|
||||||
|
DiceOptions.CompoundingExplosion,
|
||||||
|
DiceOptions.PenetratingExplosion,
|
||||||
|
DiceOptions.ExplodeOnce,
|
||||||
|
DiceOptions.Exploding,
|
||||||
|
];
|
|
@ -5,6 +5,7 @@ import { RollConf } from 'artigen/dice/dice.d.ts';
|
||||||
import { getLoopCount, loopCountCheck } from 'artigen/managers/loopManager.ts';
|
import { getLoopCount, loopCountCheck } from 'artigen/managers/loopManager.ts';
|
||||||
|
|
||||||
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
||||||
|
import { DiceOptions, NumberlessDiceOptions } from 'artigen/dice/diceOptions.ts';
|
||||||
|
|
||||||
const throwDoubleSepError = (sep: string): void => {
|
const throwDoubleSepError = (sep: string): void => {
|
||||||
throw new Error(`DoubleSeparator_${sep}`);
|
throw new Error(`DoubleSeparator_${sep}`);
|
||||||
|
@ -198,11 +199,24 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
if (afterSepIdx < 0) {
|
if (afterSepIdx < 0) {
|
||||||
afterSepIdx = remains.length;
|
afterSepIdx = remains.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine if afterSepIdx needs to be moved up (cases like mt! or !mt)
|
||||||
|
const tempSep = remains.slice(0, afterSepIdx);
|
||||||
|
let noNumberAfter = false;
|
||||||
|
NumberlessDiceOptions.some((opt) => {
|
||||||
|
if (tempSep.startsWith(opt) && tempSep !== opt) {
|
||||||
|
afterSepIdx = opt.length;
|
||||||
|
noNumberAfter = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return tempSep === opt;
|
||||||
|
});
|
||||||
|
|
||||||
// Save the rule name to tSep and remove it from remains
|
// Save the rule name to tSep and remove it from remains
|
||||||
const tSep = remains.slice(0, afterSepIdx);
|
const tSep = remains.slice(0, afterSepIdx);
|
||||||
remains = remains.slice(afterSepIdx);
|
remains = remains.slice(afterSepIdx);
|
||||||
// Find the next non-number in the remains to be able to cut out the count/num
|
// Find the next non-number in the remains to be able to cut out the count/num
|
||||||
let afterNumIdx = remains.search(/\D/);
|
let afterNumIdx = noNumberAfter ? 0 : remains.search(/\D/);
|
||||||
if (afterNumIdx < 0) {
|
if (afterNumIdx < 0) {
|
||||||
afterNumIdx = remains.length;
|
afterNumIdx = remains.length;
|
||||||
}
|
}
|
||||||
|
@ -211,8 +225,8 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
|
|
||||||
// Switch on rule name
|
// Switch on rule name
|
||||||
switch (tSep) {
|
switch (tSep) {
|
||||||
case 'dl':
|
case DiceOptions.Drop:
|
||||||
case 'd':
|
case DiceOptions.DropLow:
|
||||||
if (rollConf.drop.on) {
|
if (rollConf.drop.on) {
|
||||||
// Ensure we do not override existing settings
|
// Ensure we do not override existing settings
|
||||||
throwDoubleSepError(tSep);
|
throwDoubleSepError(tSep);
|
||||||
|
@ -221,8 +235,8 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
rollConf.drop.on = true;
|
rollConf.drop.on = true;
|
||||||
rollConf.drop.count = tNum;
|
rollConf.drop.count = tNum;
|
||||||
break;
|
break;
|
||||||
case 'kh':
|
case DiceOptions.Keep:
|
||||||
case 'k':
|
case DiceOptions.KeepHigh:
|
||||||
if (rollConf.keep.on) {
|
if (rollConf.keep.on) {
|
||||||
// Ensure we do not override existing settings
|
// Ensure we do not override existing settings
|
||||||
throwDoubleSepError(tSep);
|
throwDoubleSepError(tSep);
|
||||||
|
@ -231,7 +245,7 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
rollConf.keep.on = true;
|
rollConf.keep.on = true;
|
||||||
rollConf.keep.count = tNum;
|
rollConf.keep.count = tNum;
|
||||||
break;
|
break;
|
||||||
case 'dh':
|
case DiceOptions.DropHigh:
|
||||||
if (rollConf.dropHigh.on) {
|
if (rollConf.dropHigh.on) {
|
||||||
// Ensure we do not override existing settings
|
// Ensure we do not override existing settings
|
||||||
throwDoubleSepError(tSep);
|
throwDoubleSepError(tSep);
|
||||||
|
@ -240,7 +254,7 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
rollConf.dropHigh.on = true;
|
rollConf.dropHigh.on = true;
|
||||||
rollConf.dropHigh.count = tNum;
|
rollConf.dropHigh.count = tNum;
|
||||||
break;
|
break;
|
||||||
case 'kl':
|
case DiceOptions.KeepLow:
|
||||||
if (rollConf.keepLow.on) {
|
if (rollConf.keepLow.on) {
|
||||||
// Ensure we do not override existing settings
|
// Ensure we do not override existing settings
|
||||||
throwDoubleSepError(tSep);
|
throwDoubleSepError(tSep);
|
||||||
|
@ -249,20 +263,20 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
rollConf.keepLow.on = true;
|
rollConf.keepLow.on = true;
|
||||||
rollConf.keepLow.count = tNum;
|
rollConf.keepLow.count = tNum;
|
||||||
break;
|
break;
|
||||||
case 'ro':
|
case DiceOptions.RerollOnce:
|
||||||
case 'ro=':
|
case DiceOptions.RerollOnceEqu:
|
||||||
rollConf.reroll.once = true;
|
rollConf.reroll.once = true;
|
||||||
// falls through as ro/ro= functions the same as r/r= in this context
|
// falls through as ro/ro= functions the same as r/r= in this context
|
||||||
case 'r':
|
case DiceOptions.Reroll:
|
||||||
case 'r=':
|
case DiceOptions.RerollEqu:
|
||||||
// Configure Reroll (this can happen multiple times)
|
// Configure Reroll (this can happen multiple times)
|
||||||
rollConf.reroll.on = true;
|
rollConf.reroll.on = true;
|
||||||
!rollConf.reroll.nums.includes(tNum) && rollConf.reroll.nums.push(tNum);
|
!rollConf.reroll.nums.includes(tNum) && rollConf.reroll.nums.push(tNum);
|
||||||
break;
|
break;
|
||||||
case 'ro>':
|
case DiceOptions.RerollOnceGtr:
|
||||||
rollConf.reroll.once = true;
|
rollConf.reroll.once = true;
|
||||||
// falls through as ro> functions the same as r> in this context
|
// falls through as ro> functions the same as r> in this context
|
||||||
case 'r>':
|
case DiceOptions.RerollGtr:
|
||||||
// Configure reroll for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure reroll for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.reroll.on = true;
|
rollConf.reroll.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
|
@ -272,10 +286,10 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
!rollConf.reroll.nums.includes(i) && rollConf.reroll.nums.push(i);
|
!rollConf.reroll.nums.includes(i) && rollConf.reroll.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'ro<':
|
case DiceOptions.RerollOnceLt:
|
||||||
rollConf.reroll.once = true;
|
rollConf.reroll.once = true;
|
||||||
// falls through as ro< functions the same as r< in this context
|
// falls through as ro< functions the same as r< in this context
|
||||||
case 'r<':
|
case DiceOptions.RerollLt:
|
||||||
// Configure reroll for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure reroll for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.reroll.on = true;
|
rollConf.reroll.on = true;
|
||||||
for (let i = 1; i <= tNum; i++) {
|
for (let i = 1; i <= tNum; i++) {
|
||||||
|
@ -285,13 +299,13 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
!rollConf.reroll.nums.includes(i) && rollConf.reroll.nums.push(i);
|
!rollConf.reroll.nums.includes(i) && rollConf.reroll.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'cs':
|
case DiceOptions.CritSuccess:
|
||||||
case 'cs=':
|
case DiceOptions.CritSuccessEqu:
|
||||||
// Configure CritScore for one number (this can happen multiple times)
|
// Configure CritScore for one number (this can happen multiple times)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
!rollConf.critScore.range.includes(tNum) && rollConf.critScore.range.push(tNum);
|
!rollConf.critScore.range.includes(tNum) && rollConf.critScore.range.push(tNum);
|
||||||
break;
|
break;
|
||||||
case 'cs>':
|
case DiceOptions.CritSuccessGtr:
|
||||||
// Configure CritScore for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritScore for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
|
@ -301,7 +315,7 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
!rollConf.critScore.range.includes(i) && rollConf.critScore.range.push(i);
|
!rollConf.critScore.range.includes(i) && rollConf.critScore.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'cs<':
|
case DiceOptions.CritSuccessLt:
|
||||||
// Configure CritScore for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritScore for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
for (let i = 0; i <= tNum; i++) {
|
for (let i = 0; i <= tNum; i++) {
|
||||||
|
@ -311,13 +325,13 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
!rollConf.critScore.range.includes(i) && rollConf.critScore.range.push(i);
|
!rollConf.critScore.range.includes(i) && rollConf.critScore.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'cf':
|
case DiceOptions.CritFail:
|
||||||
case 'cf=':
|
case DiceOptions.CritFailEqu:
|
||||||
// Configure CritFail for one number (this can happen multiple times)
|
// Configure CritFail for one number (this can happen multiple times)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
!rollConf.critFail.range.includes(tNum) && rollConf.critFail.range.push(tNum);
|
!rollConf.critFail.range.includes(tNum) && rollConf.critFail.range.push(tNum);
|
||||||
break;
|
break;
|
||||||
case 'cf>':
|
case DiceOptions.CritFailGtr:
|
||||||
// Configure CritFail for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritFail for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
|
@ -327,7 +341,7 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
!rollConf.critFail.range.includes(i) && rollConf.critFail.range.push(i);
|
!rollConf.critFail.range.includes(i) && rollConf.critFail.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'cf<':
|
case DiceOptions.CritFailLt:
|
||||||
// Configure CritFail for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritFail for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
for (let i = 0; i <= tNum; i++) {
|
for (let i = 0; i <= tNum; i++) {
|
||||||
|
@ -337,32 +351,29 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
!rollConf.critFail.range.includes(i) && rollConf.critFail.range.push(i);
|
!rollConf.critFail.range.includes(i) && rollConf.critFail.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '!':
|
case DiceOptions.Exploding:
|
||||||
case '!o':
|
case DiceOptions.ExplodeOnce:
|
||||||
case '!p':
|
case DiceOptions.PenetratingExplosion:
|
||||||
case '!!':
|
case DiceOptions.CompoundingExplosion:
|
||||||
// Configure Exploding
|
// Configure Exploding
|
||||||
rollConf.exploding.on = true;
|
rollConf.exploding.on = true;
|
||||||
if (afterNumIdx > 0) {
|
if (afterNumIdx > 0) {
|
||||||
// User gave a number to explode on, save it
|
// User gave a number to explode on, save it
|
||||||
!rollConf.exploding.nums.includes(tNum) && rollConf.exploding.nums.push(tNum);
|
!rollConf.exploding.nums.includes(tNum) && rollConf.exploding.nums.push(tNum);
|
||||||
} else {
|
|
||||||
// User did not give number, use cs
|
|
||||||
afterNumIdx = 1;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '!=':
|
case DiceOptions.ExplodingEqu:
|
||||||
case '!o=':
|
case DiceOptions.ExplodeOnceEqu:
|
||||||
case '!p=':
|
case DiceOptions.PenetratingExplosionEqu:
|
||||||
case '!!=':
|
case DiceOptions.CompoundingExplosionEqu:
|
||||||
// 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.includes(tNum) && rollConf.exploding.nums.push(tNum);
|
!rollConf.exploding.nums.includes(tNum) && rollConf.exploding.nums.push(tNum);
|
||||||
break;
|
break;
|
||||||
case '!>':
|
case DiceOptions.ExplodingGtr:
|
||||||
case '!o>':
|
case DiceOptions.ExplodeOnceGtr:
|
||||||
case '!p>':
|
case DiceOptions.PenetratingExplosionGtr:
|
||||||
case '!!>':
|
case DiceOptions.CompoundingExplosionGtr:
|
||||||
// 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++) {
|
||||||
|
@ -372,10 +383,10 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
!rollConf.exploding.nums.includes(i) && rollConf.exploding.nums.push(i);
|
!rollConf.exploding.nums.includes(i) && rollConf.exploding.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '!<':
|
case DiceOptions.ExplodingLt:
|
||||||
case '!o<':
|
case DiceOptions.ExplodeOnceLt:
|
||||||
case '!p<':
|
case DiceOptions.PenetratingExplosionLt:
|
||||||
case '!!<':
|
case DiceOptions.CompoundingExplosionLt:
|
||||||
// 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++) {
|
||||||
|
@ -385,15 +396,12 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
!rollConf.exploding.nums.includes(i) && rollConf.exploding.nums.push(i);
|
!rollConf.exploding.nums.includes(i) && rollConf.exploding.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case DiceOptions.Matching:
|
||||||
case 'mt':
|
case DiceOptions.MatchingTotal:
|
||||||
rollConf.match.on = true;
|
rollConf.match.on = true;
|
||||||
if (afterNumIdx > 0) {
|
if (afterNumIdx > 0) {
|
||||||
// User gave a number to explode on, save it
|
// User gave a number to work with, save it
|
||||||
rollConf.match.minCount = tNum;
|
rollConf.match.minCount = tNum;
|
||||||
} else {
|
|
||||||
// User did not give number, use cs
|
|
||||||
afterNumIdx = 1;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -403,25 +411,25 @@ export const getRollConf = (rollStr: string): RollConf => {
|
||||||
|
|
||||||
// Followup switch to avoid weird duplicated code
|
// Followup switch to avoid weird duplicated code
|
||||||
switch (tSep) {
|
switch (tSep) {
|
||||||
case '!o':
|
case DiceOptions.ExplodeOnce:
|
||||||
case '!o=':
|
case DiceOptions.ExplodeOnceLt:
|
||||||
case '!o>':
|
case DiceOptions.ExplodeOnceGtr:
|
||||||
case '!o<':
|
case DiceOptions.ExplodeOnceEqu:
|
||||||
rollConf.exploding.once = true;
|
rollConf.exploding.once = true;
|
||||||
break;
|
break;
|
||||||
case '!p':
|
case DiceOptions.PenetratingExplosion:
|
||||||
case '!p=':
|
case DiceOptions.PenetratingExplosionLt:
|
||||||
case '!p>':
|
case DiceOptions.PenetratingExplosionGtr:
|
||||||
case '!p<':
|
case DiceOptions.PenetratingExplosionEqu:
|
||||||
rollConf.exploding.penetrating = true;
|
rollConf.exploding.penetrating = true;
|
||||||
break;
|
break;
|
||||||
case '!!':
|
case DiceOptions.CompoundingExplosion:
|
||||||
case '!!=':
|
case DiceOptions.CompoundingExplosionLt:
|
||||||
case '!!>':
|
case DiceOptions.CompoundingExplosionGtr:
|
||||||
case '!!<':
|
case DiceOptions.CompoundingExplosionEqu:
|
||||||
rollConf.exploding.compounding = true;
|
rollConf.exploding.compounding = true;
|
||||||
break;
|
break;
|
||||||
case 'mt':
|
case DiceOptions.MatchingTotal:
|
||||||
rollConf.match.returnTotal = true;
|
rollConf.match.returnTotal = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue