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 { loggingEnabled } from 'artigen/utils/logFlag.ts';
|
||||
import { DiceOptions, NumberlessDiceOptions } from 'artigen/dice/diceOptions.ts';
|
||||
|
||||
const throwDoubleSepError = (sep: string): void => {
|
||||
throw new Error(`DoubleSeparator_${sep}`);
|
||||
|
@ -198,11 +199,24 @@ export const getRollConf = (rollStr: string): RollConf => {
|
|||
if (afterSepIdx < 0) {
|
||||
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
|
||||
const tSep = remains.slice(0, afterSepIdx);
|
||||
remains = remains.slice(afterSepIdx);
|
||||
// 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) {
|
||||
afterNumIdx = remains.length;
|
||||
}
|
||||
|
@ -211,8 +225,8 @@ export const getRollConf = (rollStr: string): RollConf => {
|
|||
|
||||
// Switch on rule name
|
||||
switch (tSep) {
|
||||
case 'dl':
|
||||
case 'd':
|
||||
case DiceOptions.Drop:
|
||||
case DiceOptions.DropLow:
|
||||
if (rollConf.drop.on) {
|
||||
// Ensure we do not override existing settings
|
||||
throwDoubleSepError(tSep);
|
||||
|
@ -221,8 +235,8 @@ export const getRollConf = (rollStr: string): RollConf => {
|
|||
rollConf.drop.on = true;
|
||||
rollConf.drop.count = tNum;
|
||||
break;
|
||||
case 'kh':
|
||||
case 'k':
|
||||
case DiceOptions.Keep:
|
||||
case DiceOptions.KeepHigh:
|
||||
if (rollConf.keep.on) {
|
||||
// Ensure we do not override existing settings
|
||||
throwDoubleSepError(tSep);
|
||||
|
@ -231,7 +245,7 @@ export const getRollConf = (rollStr: string): RollConf => {
|
|||
rollConf.keep.on = true;
|
||||
rollConf.keep.count = tNum;
|
||||
break;
|
||||
case 'dh':
|
||||
case DiceOptions.DropHigh:
|
||||
if (rollConf.dropHigh.on) {
|
||||
// Ensure we do not override existing settings
|
||||
throwDoubleSepError(tSep);
|
||||
|
@ -240,7 +254,7 @@ export const getRollConf = (rollStr: string): RollConf => {
|
|||
rollConf.dropHigh.on = true;
|
||||
rollConf.dropHigh.count = tNum;
|
||||
break;
|
||||
case 'kl':
|
||||
case DiceOptions.KeepLow:
|
||||
if (rollConf.keepLow.on) {
|
||||
// Ensure we do not override existing settings
|
||||
throwDoubleSepError(tSep);
|
||||
|
@ -249,20 +263,20 @@ export const getRollConf = (rollStr: string): RollConf => {
|
|||
rollConf.keepLow.on = true;
|
||||
rollConf.keepLow.count = tNum;
|
||||
break;
|
||||
case 'ro':
|
||||
case 'ro=':
|
||||
case DiceOptions.RerollOnce:
|
||||
case DiceOptions.RerollOnceEqu:
|
||||
rollConf.reroll.once = true;
|
||||
// falls through as ro/ro= functions the same as r/r= in this context
|
||||
case 'r':
|
||||
case 'r=':
|
||||
case DiceOptions.Reroll:
|
||||
case DiceOptions.RerollEqu:
|
||||
// Configure Reroll (this can happen multiple times)
|
||||
rollConf.reroll.on = true;
|
||||
!rollConf.reroll.nums.includes(tNum) && rollConf.reroll.nums.push(tNum);
|
||||
break;
|
||||
case 'ro>':
|
||||
case DiceOptions.RerollOnceGtr:
|
||||
rollConf.reroll.once = true;
|
||||
// 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)
|
||||
rollConf.reroll.on = true;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 'ro<':
|
||||
case DiceOptions.RerollOnceLt:
|
||||
rollConf.reroll.once = true;
|
||||
// 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)
|
||||
rollConf.reroll.on = true;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 'cs':
|
||||
case 'cs=':
|
||||
case DiceOptions.CritSuccess:
|
||||
case DiceOptions.CritSuccessEqu:
|
||||
// Configure CritScore for one number (this can happen multiple times)
|
||||
rollConf.critScore.on = true;
|
||||
!rollConf.critScore.range.includes(tNum) && rollConf.critScore.range.push(tNum);
|
||||
break;
|
||||
case 'cs>':
|
||||
case DiceOptions.CritSuccessGtr:
|
||||
// Configure CritScore for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||
rollConf.critScore.on = true;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 'cs<':
|
||||
case DiceOptions.CritSuccessLt:
|
||||
// Configure CritScore for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||
rollConf.critScore.on = true;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 'cf':
|
||||
case 'cf=':
|
||||
case DiceOptions.CritFail:
|
||||
case DiceOptions.CritFailEqu:
|
||||
// Configure CritFail for one number (this can happen multiple times)
|
||||
rollConf.critFail.on = true;
|
||||
!rollConf.critFail.range.includes(tNum) && rollConf.critFail.range.push(tNum);
|
||||
break;
|
||||
case 'cf>':
|
||||
case DiceOptions.CritFailGtr:
|
||||
// Configure CritFail for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||
rollConf.critFail.on = true;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 'cf<':
|
||||
case DiceOptions.CritFailLt:
|
||||
// Configure CritFail for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||
rollConf.critFail.on = true;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case '!':
|
||||
case '!o':
|
||||
case '!p':
|
||||
case '!!':
|
||||
case DiceOptions.Exploding:
|
||||
case DiceOptions.ExplodeOnce:
|
||||
case DiceOptions.PenetratingExplosion:
|
||||
case DiceOptions.CompoundingExplosion:
|
||||
// Configure Exploding
|
||||
rollConf.exploding.on = true;
|
||||
if (afterNumIdx > 0) {
|
||||
// User gave a number to explode on, save it
|
||||
!rollConf.exploding.nums.includes(tNum) && rollConf.exploding.nums.push(tNum);
|
||||
} else {
|
||||
// User did not give number, use cs
|
||||
afterNumIdx = 1;
|
||||
}
|
||||
break;
|
||||
case '!=':
|
||||
case '!o=':
|
||||
case '!p=':
|
||||
case '!!=':
|
||||
case DiceOptions.ExplodingEqu:
|
||||
case DiceOptions.ExplodeOnceEqu:
|
||||
case DiceOptions.PenetratingExplosionEqu:
|
||||
case DiceOptions.CompoundingExplosionEqu:
|
||||
// Configure Exploding (this can happen multiple times)
|
||||
rollConf.exploding.on = true;
|
||||
!rollConf.exploding.nums.includes(tNum) && rollConf.exploding.nums.push(tNum);
|
||||
break;
|
||||
case '!>':
|
||||
case '!o>':
|
||||
case '!p>':
|
||||
case '!!>':
|
||||
case DiceOptions.ExplodingGtr:
|
||||
case DiceOptions.ExplodeOnceGtr:
|
||||
case DiceOptions.PenetratingExplosionGtr:
|
||||
case DiceOptions.CompoundingExplosionGtr:
|
||||
// Configure Exploding for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||
rollConf.exploding.on = true;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case '!<':
|
||||
case '!o<':
|
||||
case '!p<':
|
||||
case '!!<':
|
||||
case DiceOptions.ExplodingLt:
|
||||
case DiceOptions.ExplodeOnceLt:
|
||||
case DiceOptions.PenetratingExplosionLt:
|
||||
case DiceOptions.CompoundingExplosionLt:
|
||||
// Configure Exploding for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||
rollConf.exploding.on = true;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
case 'mt':
|
||||
case DiceOptions.Matching:
|
||||
case DiceOptions.MatchingTotal:
|
||||
rollConf.match.on = true;
|
||||
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;
|
||||
} else {
|
||||
// User did not give number, use cs
|
||||
afterNumIdx = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -403,25 +411,25 @@ export const getRollConf = (rollStr: string): RollConf => {
|
|||
|
||||
// Followup switch to avoid weird duplicated code
|
||||
switch (tSep) {
|
||||
case '!o':
|
||||
case '!o=':
|
||||
case '!o>':
|
||||
case '!o<':
|
||||
case DiceOptions.ExplodeOnce:
|
||||
case DiceOptions.ExplodeOnceLt:
|
||||
case DiceOptions.ExplodeOnceGtr:
|
||||
case DiceOptions.ExplodeOnceEqu:
|
||||
rollConf.exploding.once = true;
|
||||
break;
|
||||
case '!p':
|
||||
case '!p=':
|
||||
case '!p>':
|
||||
case '!p<':
|
||||
case DiceOptions.PenetratingExplosion:
|
||||
case DiceOptions.PenetratingExplosionLt:
|
||||
case DiceOptions.PenetratingExplosionGtr:
|
||||
case DiceOptions.PenetratingExplosionEqu:
|
||||
rollConf.exploding.penetrating = true;
|
||||
break;
|
||||
case '!!':
|
||||
case '!!=':
|
||||
case '!!>':
|
||||
case '!!<':
|
||||
case DiceOptions.CompoundingExplosion:
|
||||
case DiceOptions.CompoundingExplosionLt:
|
||||
case DiceOptions.CompoundingExplosionGtr:
|
||||
case DiceOptions.CompoundingExplosionEqu:
|
||||
rollConf.exploding.compounding = true;
|
||||
break;
|
||||
case 'mt':
|
||||
case DiceOptions.MatchingTotal:
|
||||
rollConf.match.returnTotal = true;
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue