Add support for modifiers on multi-mode
This commit is contained in:
		
							parent
							
								
									cbac134f79
								
							
						
					
					
						commit
						41214bd0d3
					
				| 
						 | 
				
			
			@ -4,6 +4,7 @@ import { CountDetails, RollDistributionMap } from 'artigen/dice/dice.d.ts';
 | 
			
		|||
 | 
			
		||||
// ReturnData is the temporary internal type used before getting turned into SolvedRoll
 | 
			
		||||
export interface ReturnData {
 | 
			
		||||
  origIdx?: number;
 | 
			
		||||
  rollTotal: number;
 | 
			
		||||
  rollPreFormat: string;
 | 
			
		||||
  rollPostFormat: string;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ import { loopCountCheck } from 'artigen/managers/loopManager.ts';
 | 
			
		|||
import { tokenizeMath } from 'artigen/math/mathTokenizer.ts';
 | 
			
		||||
 | 
			
		||||
import { reduceCountDetails } from 'artigen/utils/counter.ts';
 | 
			
		||||
import { closeInternal, closeInternalGrp, internalGrpWrapRegex, internalWrapRegex, openInternal, openInternalGrp } from 'artigen/utils/escape.ts';
 | 
			
		||||
import { closeInternal, closeInternalGrp, internalGrpWrapRegex, internalWrapRegex, mathSplitRegex, openInternal, openInternalGrp } from 'artigen/utils/escape.ts';
 | 
			
		||||
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
 | 
			
		||||
import { assertGroupBalance, getMatchingGroupIdx, getMatchingInternalGrpIdx, getMatchingInternalIdx, getMatchingPostfixIdx } from 'artigen/utils/parenBalance.ts';
 | 
			
		||||
import { basicReducer } from 'artigen/utils/reducers.ts';
 | 
			
		||||
| 
						 | 
				
			
			@ -149,7 +149,16 @@ export const tokenizeCmd = (
 | 
			
		|||
 | 
			
		||||
      const currentGrp = groupParts.slice(openIdx + 1, closeIdx);
 | 
			
		||||
 | 
			
		||||
      const [tempData, tempCounts, tempDists] = handleGroup(currentGrp, '', modifiers, previousResults);
 | 
			
		||||
      // Try to find and "eat" any modifiers from the next groupPart
 | 
			
		||||
      let thisGrpMods = '';
 | 
			
		||||
      const possibleMods = groupParts[closeIdx + 1]?.trim() ?? '';
 | 
			
		||||
      if (possibleMods.match(/^[dk<>=f].*/g)) {
 | 
			
		||||
        const items = groupParts[closeIdx + 1].split(mathSplitRegex).filter((x) => x);
 | 
			
		||||
        thisGrpMods = items.shift() ?? '';
 | 
			
		||||
        groupParts[closeIdx + 1] = items.join('');
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const [tempData, tempCounts, tempDists] = handleGroup(currentGrp, thisGrpMods, modifiers, previousResults);
 | 
			
		||||
      const data = tempData[0];
 | 
			
		||||
      log(LT.LOG, `Solved Group is back ${JSON.stringify(data)} | ${JSON.stringify(returnData)} ${JSON.stringify(tempCounts)} ${JSON.stringify(tempDists)}`);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,16 +91,22 @@ export interface DPercentConf {
 | 
			
		|||
  critVal: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RollConf is used by the roll20 setup
 | 
			
		||||
export interface RollConf {
 | 
			
		||||
  type: RollType;
 | 
			
		||||
  dieCount: number;
 | 
			
		||||
  dieSize: number;
 | 
			
		||||
  dPercent: DPercentConf;
 | 
			
		||||
// GroupConf carries the machine readable group configuration the user specified
 | 
			
		||||
export interface GroupConf {
 | 
			
		||||
  drop: CountConf;
 | 
			
		||||
  keep: CountConf;
 | 
			
		||||
  dropHigh: CountConf;
 | 
			
		||||
  keepLow: CountConf;
 | 
			
		||||
  success: RangeConf;
 | 
			
		||||
  fail: RangeConf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RollConf carries the machine readable roll configuration the user specified
 | 
			
		||||
export interface RollConf extends GroupConf {
 | 
			
		||||
  type: RollType;
 | 
			
		||||
  dieCount: number;
 | 
			
		||||
  dieSize: number;
 | 
			
		||||
  dPercent: DPercentConf;
 | 
			
		||||
  reroll: {
 | 
			
		||||
    on: boolean;
 | 
			
		||||
    once: boolean;
 | 
			
		||||
| 
						 | 
				
			
			@ -121,8 +127,6 @@ export interface RollConf {
 | 
			
		|||
    returnTotal: boolean;
 | 
			
		||||
  };
 | 
			
		||||
  sort: SortDisabled | SortEnabled;
 | 
			
		||||
  success: RangeConf;
 | 
			
		||||
  fail: RangeConf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SumOverride {
 | 
			
		||||
| 
						 | 
				
			
			@ -136,3 +140,9 @@ export interface ExecutedRoll {
 | 
			
		|||
  countFailOverride: boolean;
 | 
			
		||||
  sumOverride: SumOverride;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface GroupResultFlags {
 | 
			
		||||
  dropped: boolean;
 | 
			
		||||
  success: boolean;
 | 
			
		||||
  failed: boolean;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
import { log, LogTypes as LT } from '@Log4Deno';
 | 
			
		||||
 | 
			
		||||
import { GroupConf } from 'artigen/dice/dice.d.ts';
 | 
			
		||||
import { getRollConf } from 'artigen/dice/getRollConf.ts';
 | 
			
		||||
 | 
			
		||||
import { loopCountCheck } from 'artigen/managers/loopManager.ts';
 | 
			
		||||
 | 
			
		||||
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
 | 
			
		||||
 | 
			
		||||
// Wrapper to abuse getRollConf, produces a GroupConf by making the groupStr into a rollStr by adding a 1d1 onto it
 | 
			
		||||
export const getGroupConf = (groupStr: string, rawStr: string): GroupConf => {
 | 
			
		||||
  const numberMatches = rawStr.match(/\d+/g) ?? ['1'];
 | 
			
		||||
 | 
			
		||||
  let biggest = parseInt(numberMatches.length ? numberMatches[0] : '1');
 | 
			
		||||
  for (const num of numberMatches) {
 | 
			
		||||
    loopCountCheck();
 | 
			
		||||
 | 
			
		||||
    const curNum = parseInt(num);
 | 
			
		||||
    loggingEnabled && log(LT.LOG, `Finding biggest number to use as die size, ${curNum} ${biggest}`);
 | 
			
		||||
    if (curNum > biggest) {
 | 
			
		||||
      biggest = curNum;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  loggingEnabled && log(LT.LOG, `Abusing getRollConf with "1d${biggest} ${groupStr}"`);
 | 
			
		||||
  const fakeRollConf = getRollConf(`1d${biggest}${groupStr}`);
 | 
			
		||||
  loggingEnabled && log(LT.LOG, `Abused rollConf back for ${groupStr}: ${JSON.stringify(fakeRollConf)}`);
 | 
			
		||||
  return {
 | 
			
		||||
    drop: fakeRollConf.drop,
 | 
			
		||||
    keep: fakeRollConf.keep,
 | 
			
		||||
    dropHigh: fakeRollConf.dropHigh,
 | 
			
		||||
    keepLow: fakeRollConf.keepLow,
 | 
			
		||||
    success: fakeRollConf.success,
 | 
			
		||||
    fail: fakeRollConf.fail,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -2,15 +2,18 @@ import { log, LogTypes as LT } from '@Log4Deno';
 | 
			
		|||
 | 
			
		||||
import { ReturnData } from 'artigen/artigen.d.ts';
 | 
			
		||||
 | 
			
		||||
import { CountDetails, RollDistributionMap, RollModifiers } from 'artigen/dice/dice.d.ts';
 | 
			
		||||
import { CountDetails, GroupConf, GroupResultFlags, RollDistributionMap, RollModifiers } from 'artigen/dice/dice.d.ts';
 | 
			
		||||
 | 
			
		||||
import { loopCountCheck } from 'artigen/managers/loopManager.ts';
 | 
			
		||||
 | 
			
		||||
import { tokenizeMath } from 'artigen/math/mathTokenizer.ts';
 | 
			
		||||
 | 
			
		||||
import { closeInternalGrp, openInternalGrp } from 'artigen/utils/escape.ts';
 | 
			
		||||
import { closeInternalGrp, internalGrpWrapRegex, mathSplitRegex, openInternalGrp } from 'artigen/utils/escape.ts';
 | 
			
		||||
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
 | 
			
		||||
import { getMatchingGroupIdx } from 'artigen/utils/parenBalance.ts';
 | 
			
		||||
import { getMatchingGroupIdx, getMatchingInternalGrpIdx } from 'artigen/utils/parenBalance.ts';
 | 
			
		||||
import { getGroupConf } from 'artigen/dice/getGroupConf.ts';
 | 
			
		||||
import { compareOrigIdx, compareTotalRolls } from 'artigen/utils/sortFuncs.ts';
 | 
			
		||||
import { applyFlags } from '../utils/groupResultFlagger.ts';
 | 
			
		||||
 | 
			
		||||
export const handleGroup = (
 | 
			
		||||
  groupParts: string[],
 | 
			
		||||
| 
						 | 
				
			
			@ -18,9 +21,12 @@ export const handleGroup = (
 | 
			
		|||
  modifiers: RollModifiers,
 | 
			
		||||
  previousResults: number[],
 | 
			
		||||
): [ReturnData[], CountDetails[], RollDistributionMap[]] => {
 | 
			
		||||
  let retData: ReturnData;
 | 
			
		||||
  const returnData: ReturnData[] = [];
 | 
			
		||||
  const countDetails: CountDetails[] = [];
 | 
			
		||||
  const rollDists: RollDistributionMap[] = [];
 | 
			
		||||
  const groupConf: GroupConf = getGroupConf(groupModifiers, groupParts.join(''));
 | 
			
		||||
  const prevGrpReturnData: ReturnData[] = [];
 | 
			
		||||
 | 
			
		||||
  // Nested groups still exist, unwrap them
 | 
			
		||||
  while (groupParts.includes('{')) {
 | 
			
		||||
| 
						 | 
				
			
			@ -28,12 +34,21 @@ export const handleGroup = (
 | 
			
		|||
 | 
			
		||||
    loggingEnabled && log(LT.LOG, `Handling Nested Groups | Current cmd: ${JSON.stringify(groupParts)}`);
 | 
			
		||||
 | 
			
		||||
    const openIdx = groupParts.indexOf('}');
 | 
			
		||||
    const openIdx = groupParts.indexOf('{');
 | 
			
		||||
    const closeIdx = getMatchingGroupIdx(groupParts, openIdx);
 | 
			
		||||
 | 
			
		||||
    const currentGrp = groupParts.slice(openIdx + 1, closeIdx);
 | 
			
		||||
 | 
			
		||||
    const [tempData, tempCounts, tempDists] = handleGroup(currentGrp, '', modifiers, previousResults);
 | 
			
		||||
    // Try to find and "eat" any modifiers from the next groupPart
 | 
			
		||||
    let thisGrpMods = '';
 | 
			
		||||
    const possibleMods = groupParts[closeIdx + 1]?.trim() ?? '';
 | 
			
		||||
    if (possibleMods.match(/^[dk<>=f].*/g)) {
 | 
			
		||||
      const items = groupParts[closeIdx + 1].split(mathSplitRegex).filter((x) => x);
 | 
			
		||||
      thisGrpMods = items.shift() ?? '';
 | 
			
		||||
      groupParts[closeIdx + 1] = items.join('');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const [tempData, tempCounts, tempDists] = handleGroup(currentGrp, thisGrpMods, modifiers, previousResults);
 | 
			
		||||
    const data = tempData[0];
 | 
			
		||||
    loggingEnabled && log(LT.LOG, `Solved Nested Group is back ${JSON.stringify(data)} | ${JSON.stringify(tempCounts)} ${JSON.stringify(tempDists)}`);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +56,8 @@ export const handleGroup = (
 | 
			
		|||
    rollDists.push(...tempDists);
 | 
			
		||||
 | 
			
		||||
    // Merge result back into groupParts
 | 
			
		||||
    groupParts.splice(openIdx, closeIdx - openIdx + 1, `${openInternalGrp}${data.rollTotal}${closeInternalGrp}`);
 | 
			
		||||
    groupParts.splice(openIdx, closeIdx - openIdx + 1, `${openInternalGrp}${prevGrpReturnData.length}${closeInternalGrp}`);
 | 
			
		||||
    prevGrpReturnData.push(data);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Handle the items in the groups
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +67,7 @@ export const handleGroup = (
 | 
			
		|||
    .filter((x) => x);
 | 
			
		||||
 | 
			
		||||
  if (commaParts.length > 1) {
 | 
			
		||||
    loggingEnabled && log(LT.LOG, `In multi-mode ${JSON.stringify(commaParts)} ${groupModifiers}`);
 | 
			
		||||
    loggingEnabled && log(LT.LOG, `In multi-mode ${JSON.stringify(commaParts)} ${groupModifiers} ${JSON.stringify(groupConf)}`);
 | 
			
		||||
    // Handle "normal operation" of group
 | 
			
		||||
    const groupResults: ReturnData[] = [];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +75,7 @@ export const handleGroup = (
 | 
			
		|||
      loopCountCheck();
 | 
			
		||||
 | 
			
		||||
      loggingEnabled && log(LT.LOG, `Solving commaPart: ${part}`);
 | 
			
		||||
      const [tempData, tempCounts, tempDists] = tokenizeMath(part, modifiers, previousResults, []);
 | 
			
		||||
      const [tempData, tempCounts, tempDists] = tokenizeMath(part, modifiers, previousResults, prevGrpReturnData);
 | 
			
		||||
      const data = tempData[0];
 | 
			
		||||
 | 
			
		||||
      loggingEnabled && log(LT.LOG, `Solved Math for Group is back ${JSON.stringify(data)} | ${JSON.stringify(tempCounts)} ${JSON.stringify(tempDists)}`);
 | 
			
		||||
| 
						 | 
				
			
			@ -69,29 +85,133 @@ export const handleGroup = (
 | 
			
		|||
      groupResults.push(data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (groupModifiers) {
 | 
			
		||||
    if (groupModifiers.trim()) {
 | 
			
		||||
      // Handle the provided modifiers
 | 
			
		||||
      const getTemplateFlags = (): GroupResultFlags => ({ dropped: false, success: false, failed: false });
 | 
			
		||||
 | 
			
		||||
      // Assign original indexes
 | 
			
		||||
      const resultFlags: GroupResultFlags[] = [];
 | 
			
		||||
      groupResults.forEach((rd, idx) => {
 | 
			
		||||
        rd.origIdx = idx;
 | 
			
		||||
        resultFlags.push(getTemplateFlags());
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // Handle drop/keep options
 | 
			
		||||
      if (groupConf.drop.on || groupConf.keep.on || groupConf.dropHigh.on || groupConf.keepLow.on) {
 | 
			
		||||
        groupResults.sort(compareTotalRolls);
 | 
			
		||||
        let dropCount = 0;
 | 
			
		||||
 | 
			
		||||
        // For normal drop and keep, simple subtraction is enough to determine how many to drop
 | 
			
		||||
        // Protections are in to prevent the dropCount from going below 0 or more than the valid rolls to drop
 | 
			
		||||
        if (groupConf.drop.on) {
 | 
			
		||||
          dropCount = groupConf.drop.count;
 | 
			
		||||
          if (dropCount > groupResults.length) {
 | 
			
		||||
            dropCount = groupResults.length;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (groupConf.keep.on) {
 | 
			
		||||
          dropCount = groupResults.length - groupConf.keep.count;
 | 
			
		||||
          if (dropCount < 0) {
 | 
			
		||||
            dropCount = 0;
 | 
			
		||||
          }
 | 
			
		||||
        } // For inverted drop and keep, order must be flipped to greatest to least before the simple subtraction can determine how many to drop
 | 
			
		||||
        // Protections are in to prevent the dropCount from going below 0 or more than the valid rolls to drop
 | 
			
		||||
        else if (groupConf.dropHigh.on) {
 | 
			
		||||
          groupResults.reverse();
 | 
			
		||||
          dropCount = groupConf.dropHigh.count;
 | 
			
		||||
          if (dropCount > groupResults.length) {
 | 
			
		||||
            dropCount = groupResults.length;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (groupConf.keepLow.on) {
 | 
			
		||||
          groupResults.reverse();
 | 
			
		||||
          dropCount = groupResults.length - groupConf.keepLow.count;
 | 
			
		||||
          if (dropCount < 0) {
 | 
			
		||||
            dropCount = 0;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let i = 0;
 | 
			
		||||
        while (dropCount > 0 && i < groupResults.length) {
 | 
			
		||||
          loopCountCheck();
 | 
			
		||||
 | 
			
		||||
          loggingEnabled && log(LT.LOG, `Handling group dropping | Dropping ${dropCount}`);
 | 
			
		||||
 | 
			
		||||
          resultFlags[groupResults[i].origIdx ?? -1].dropped = true;
 | 
			
		||||
 | 
			
		||||
          dropCount--;
 | 
			
		||||
          i++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        groupResults.sort(compareOrigIdx);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let successCnt = 0;
 | 
			
		||||
      let failCnt = 0;
 | 
			
		||||
      if (groupConf.success.on || groupConf.fail.on) {
 | 
			
		||||
        groupResults.forEach((rd, idx) => {
 | 
			
		||||
          loopCountCheck();
 | 
			
		||||
 | 
			
		||||
          if (!resultFlags[idx].dropped) {
 | 
			
		||||
            if (groupConf.success.on && groupConf.success.range.includes(rd.rollTotal)) {
 | 
			
		||||
              successCnt++;
 | 
			
		||||
              resultFlags[idx].success = true;
 | 
			
		||||
            }
 | 
			
		||||
            if (groupConf.fail.on && groupConf.fail.range.includes(rd.rollTotal)) {
 | 
			
		||||
              failCnt++;
 | 
			
		||||
              resultFlags[idx].failed = true;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      loggingEnabled && log(LT.LOG, `Applying group flags: ${JSON.stringify(resultFlags)}`);
 | 
			
		||||
      const data = groupResults.reduce((prev, cur, idx) => ({
 | 
			
		||||
        rollTotal: resultFlags[idx].dropped ? prev.rollTotal : prev.rollTotal + cur.rollTotal,
 | 
			
		||||
        rollPreFormat: '',
 | 
			
		||||
        rollPostFormat: '',
 | 
			
		||||
        rollDetails: `${prev.rollDetails}, ${applyFlags(cur.rollDetails, resultFlags[idx])}`,
 | 
			
		||||
        containsCrit: resultFlags[idx].dropped ? prev.containsCrit : prev.containsCrit || cur.containsCrit,
 | 
			
		||||
        containsFail: resultFlags[idx].dropped ? prev.containsFail : prev.containsFail || cur.containsFail,
 | 
			
		||||
        initConfig: `${prev.initConfig}, ${cur.initConfig}`,
 | 
			
		||||
        isComplex: prev.isComplex || cur.isComplex,
 | 
			
		||||
      }));
 | 
			
		||||
      data.initConfig = `{${data.initConfig}}`;
 | 
			
		||||
 | 
			
		||||
      if (groupConf.success.on || groupConf.fail.on) {
 | 
			
		||||
        data.rollTotal = 0;
 | 
			
		||||
      }
 | 
			
		||||
      if (groupConf.success.on) {
 | 
			
		||||
        data.rollTotal += successCnt;
 | 
			
		||||
        data.rollDetails += `, ${successCnt} Success${successCnt !== 1 ? 'es' : ''}`;
 | 
			
		||||
      }
 | 
			
		||||
      if (groupConf.fail.on) {
 | 
			
		||||
        data.rollTotal -= failCnt;
 | 
			
		||||
        data.rollDetails += `, ${failCnt} Fail${failCnt !== 1 ? 's' : ''}`;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      data.rollDetails = `{${data.rollDetails}}`;
 | 
			
		||||
      retData = data;
 | 
			
		||||
    } else {
 | 
			
		||||
      // Sum mode
 | 
			
		||||
      const data = groupResults.reduce((prev, cur) => ({
 | 
			
		||||
        rollTotal: prev.rollTotal + cur.rollTotal,
 | 
			
		||||
        rollPreFormat: '',
 | 
			
		||||
        rollPostFormat: '',
 | 
			
		||||
        rollDetails: prev.rollDetails + ' + ' + cur.rollDetails,
 | 
			
		||||
        rollDetails: `${prev.rollDetails} + ${cur.rollDetails}`,
 | 
			
		||||
        containsCrit: prev.containsCrit || cur.containsCrit,
 | 
			
		||||
        containsFail: prev.containsFail || cur.containsFail,
 | 
			
		||||
        initConfig: prev.initConfig + ', ' + cur.initConfig,
 | 
			
		||||
        initConfig: `${prev.initConfig}, ${cur.initConfig}`,
 | 
			
		||||
        isComplex: prev.isComplex || cur.isComplex,
 | 
			
		||||
      }));
 | 
			
		||||
      data.initConfig = `{${data.initConfig}}`;
 | 
			
		||||
      data.rollDetails = `{${data.rollDetails}}`;
 | 
			
		||||
      returnData.push(data);
 | 
			
		||||
      retData = data;
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    loggingEnabled && log(LT.LOG, `In single-mode ${JSON.stringify(commaParts)} ${groupModifiers}`);
 | 
			
		||||
    if (groupModifiers) {
 | 
			
		||||
    loggingEnabled && log(LT.LOG, `In single-mode ${JSON.stringify(commaParts)} ${groupModifiers} ${JSON.stringify(groupConf)}`);
 | 
			
		||||
    if (groupModifiers.trim()) {
 | 
			
		||||
      // Handle special case where the group modifiers are applied across the dice rolled
 | 
			
		||||
      // ex from roll20 docs: {4d6+3d8}k4 - Roll 4 d6's and 3 d8's, out of those 7 dice the highest 4 are kept and summed up.
 | 
			
		||||
      retData = <ReturnData> {};
 | 
			
		||||
    } else {
 | 
			
		||||
      // why did you put this in a group, that was entirely pointless
 | 
			
		||||
      loggingEnabled && log(LT.LOG, `Solving commaPart: ${commaParts[0]}`);
 | 
			
		||||
| 
						 | 
				
			
			@ -104,9 +224,28 @@ export const handleGroup = (
 | 
			
		|||
      rollDists.push(...tempDists);
 | 
			
		||||
      data.initConfig = `{${data.initConfig}}`;
 | 
			
		||||
      data.rollDetails = `{${data.rollDetails}}`;
 | 
			
		||||
      returnData.push(data);
 | 
			
		||||
      retData = data;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Handle merging back any nested groups to prevent an internalGrp marker from sneaking out
 | 
			
		||||
  const initConf = retData.initConfig.split(internalGrpWrapRegex).filter((x) => x);
 | 
			
		||||
  loggingEnabled && log(LT.LOG, `Split retData into initConf ${JSON.stringify(initConf)}`);
 | 
			
		||||
  while (initConf.includes(openInternalGrp)) {
 | 
			
		||||
    loopCountCheck();
 | 
			
		||||
 | 
			
		||||
    const openIdx = initConf.indexOf(openInternalGrp);
 | 
			
		||||
    const closeIdx = getMatchingInternalGrpIdx(initConf, openIdx);
 | 
			
		||||
 | 
			
		||||
    // Take first groupResult out of array
 | 
			
		||||
    const dataToMerge = prevGrpReturnData.shift();
 | 
			
		||||
 | 
			
		||||
    // Replace the found pair with the nested initConfig and result
 | 
			
		||||
    initConf.splice(openIdx, closeIdx - openIdx + 1, `${dataToMerge?.initConfig}`);
 | 
			
		||||
    loggingEnabled && log(LT.LOG, `Current initConf state ${JSON.stringify(initConf)}`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  retData.initConfig = initConf.join('');
 | 
			
		||||
  returnData.push(retData);
 | 
			
		||||
  return [returnData, countDetails, rollDists];
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import { loopCountCheck } from 'artigen/managers/loopManager.ts';
 | 
			
		|||
 | 
			
		||||
import { mathSolver } from 'artigen/math/mathSolver.ts';
 | 
			
		||||
 | 
			
		||||
import { closeInternalGrp, cmdSplitRegex, internalWrapRegex, openInternalGrp } from 'artigen/utils/escape.ts';
 | 
			
		||||
import { closeInternalGrp, cmdSplitRegex, internalWrapRegex, mathSplitRegex, openInternalGrp } from 'artigen/utils/escape.ts';
 | 
			
		||||
import { legalMathOperators } from 'artigen/utils/legalMath.ts';
 | 
			
		||||
import { loggingEnabled } from 'artigen/utils/logFlag.ts';
 | 
			
		||||
import { assertParenBalance } from 'artigen/utils/parenBalance.ts';
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +36,7 @@ export const tokenizeMath = (
 | 
			
		|||
    .replace(cmdSplitRegex, '')
 | 
			
		||||
    .replace(internalWrapRegex, '')
 | 
			
		||||
    .replace(/ /g, '')
 | 
			
		||||
    // breaks the string on the following: (\*\*) ** for exponents ([+()*/^] for basic algebra (?<![d%])% for breaking on d%%%% dice correctly (?<![rsfop!=<>])- for breaking on - correctly with fate dice) (x\d+(\.\d*)?) x# for variables
 | 
			
		||||
    .split(/(\*\*)|([+()*/^]|(?<![d%])%|(?<![rsfop!=<>])-)|(x\d+(\.\d*)?)/g)
 | 
			
		||||
    .split(mathSplitRegex)
 | 
			
		||||
    .filter((x) => x);
 | 
			
		||||
  loggingEnabled && log(LT.LOG, `Split roll into mathConf ${JSON.stringify(mathConf)}`);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,9 @@ export const escapeCharacters = (str: string, esc: string): string => {
 | 
			
		|||
const escapePrefixPostfix = (str: string): string => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
 | 
			
		||||
export const cmdSplitRegex = new RegExp(`(${escapePrefixPostfix(config.prefix)})|(${escapePrefixPostfix(config.postfix)})`, 'g');
 | 
			
		||||
 | 
			
		||||
// breaks the string on the following: (\*\*) ** for exponents ([+()*/^] for basic algebra (?<![d%])% for breaking on d%%%% dice correctly (?<![rsfop!=<>])- for breaking on - correctly with fate dice) (x\d+(\.\d*)?) x# for variables
 | 
			
		||||
export const mathSplitRegex = /(\*\*)|([+()*/^]|(?<![d%])%|(?<![rsfop!=<>])-)|(x\d+(\.\d*)?)/g;
 | 
			
		||||
 | 
			
		||||
// Internal is used for recursive text replacement, these will always be the top level as they get replaced with config.prefix/postfix when exiting each level
 | 
			
		||||
export const openInternal = '\u2045';
 | 
			
		||||
export const closeInternal = '\u2046';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
import { GroupResultFlags } from 'artigen/dice/dice.d.ts';
 | 
			
		||||
 | 
			
		||||
export const applyFlags = (rollDetails: string, flags: GroupResultFlags): string => {
 | 
			
		||||
  if (flags.dropped) {
 | 
			
		||||
    return `~~${rollDetails.replaceAll('~', '')}~~`;
 | 
			
		||||
  } else if (flags.success) {
 | 
			
		||||
    return `S:${rollDetails}`;
 | 
			
		||||
  } else if (flags.failed) {
 | 
			
		||||
    return `F:${rollDetails}`;
 | 
			
		||||
  } else {
 | 
			
		||||
    return rollDetails;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -39,12 +39,12 @@ export const compareTotalRolls = (a: ReturnData, b: ReturnData): number => inter
 | 
			
		|||
export const compareTotalRollsReverse = (a: ReturnData, b: ReturnData): number => internalCompareTotalRolls(a, b, -1);
 | 
			
		||||
 | 
			
		||||
// compareRolls(a, b) returns -1|0|1
 | 
			
		||||
// compareRolls is used to order an array of RollSets by RollSet.origIdx
 | 
			
		||||
export const compareOrigIdx = (a: RollSet, b: RollSet): number => {
 | 
			
		||||
  if (a.origIdx < b.origIdx) {
 | 
			
		||||
// compareRolls is used to order an array of RollSet or ReturnData by X.origIdx
 | 
			
		||||
export const compareOrigIdx = (a: RollSet | ReturnData, b: RollSet | ReturnData): number => {
 | 
			
		||||
  if ((a.origIdx ?? 0) < (b.origIdx ?? 0)) {
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
  if (a.origIdx > b.origIdx) {
 | 
			
		||||
  if ((a.origIdx ?? 0) > (b.origIdx ?? 0)) {
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue