Basic support added for CWOD rolls
This commit is contained in:
parent
61607dc75d
commit
6ad0d2ca2b
|
@ -0,0 +1,60 @@
|
|||
import config from '../../../config.ts';
|
||||
import {
|
||||
// Log4Deno deps
|
||||
log,
|
||||
LT,
|
||||
} from '../../../deps.ts';
|
||||
import { RollSet } from '../solver.d.ts';
|
||||
import { genRoll, loggingEnabled } from '../rollUtils.ts';
|
||||
|
||||
export const rollCWOD = (rollStr: string): RollSet[] => {
|
||||
// Parse the roll
|
||||
const cwodParts = rollStr.split('cwod');
|
||||
const cwodConf = {
|
||||
dieCount: parseInt(cwodParts[0] || '1'),
|
||||
difficulty: parseInt(cwodParts[1] || '10'),
|
||||
};
|
||||
|
||||
// Begin counting the number of loops to prevent from getting into an infinite loop
|
||||
let loopCount = 0;
|
||||
|
||||
// Roll the roll
|
||||
const rollSet = [];
|
||||
|
||||
const templateRoll: RollSet = {
|
||||
type: 'cwod',
|
||||
origidx: 0,
|
||||
roll: 0,
|
||||
dropped: false,
|
||||
rerolled: false,
|
||||
exploding: false,
|
||||
critHit: false,
|
||||
critFail: false,
|
||||
};
|
||||
|
||||
for (let i = 0; i < cwodConf.dieCount; i++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling cwod ${rollStr} | Initial rolling ${i} of ${JSON.stringify(cwodConf)}`);
|
||||
// If loopCount gets too high, stop trying to calculate infinity
|
||||
if (loopCount > config.limits.maxLoops) {
|
||||
throw new Error('MaxLoopsExceeded');
|
||||
}
|
||||
|
||||
// Copy the template to fill out for this iteration
|
||||
const rolling = JSON.parse(JSON.stringify(templateRoll));
|
||||
|
||||
// Roll this die
|
||||
rolling.roll = genRoll(10, false, false);
|
||||
rolling.origidx = i;
|
||||
|
||||
// Set success/fail flags
|
||||
rolling.critHit = rolling.roll >= cwodConf.difficulty;
|
||||
rolling.critFail = rolling.roll === 1;
|
||||
|
||||
// Add in the new roll
|
||||
rollSet.push(rolling);
|
||||
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
return rollSet;
|
||||
};
|
|
@ -7,7 +7,7 @@ import {
|
|||
import config from '../../config.ts';
|
||||
|
||||
import { RollModifiers } from '../mod.d.ts';
|
||||
import { CountDetails, ReturnData, SolvedRoll, SolvedStep } from './solver.d.ts';
|
||||
import { CountDetails, ReturnData, SolvedRoll, SolvedStep, RollType } from './solver.d.ts';
|
||||
import { compareTotalRolls, escapeCharacters, loggingEnabled } from './rollUtils.ts';
|
||||
import { formatRoll } from './rollFormatter.ts';
|
||||
import { fullSolver } from './solver.ts';
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
|
||||
import { roll } from './roller.ts';
|
||||
import { rollCounter } from './counter.ts';
|
||||
import { RollFormat } from './solver.d.ts';
|
||||
import { RollFormat, RollType } from './solver.d.ts';
|
||||
import { loggingEnabled } from './rollUtils.ts';
|
||||
|
||||
// formatRoll(rollConf, maximiseRoll, nominalRoll) returns one SolvedStep
|
||||
|
@ -16,6 +16,7 @@ export const formatRoll = (rollConf: string, maximiseRoll: boolean, nominalRoll:
|
|||
let tempDetails = '[';
|
||||
let tempCrit = false;
|
||||
let tempFail = false;
|
||||
let tempRollType: RollType = '';
|
||||
|
||||
// Generate the roll, passing flags thru
|
||||
const tempRollSet = roll(rollConf, maximiseRoll, nominalRoll);
|
||||
|
@ -23,12 +24,21 @@ export const formatRoll = (rollConf: string, maximiseRoll: boolean, nominalRoll:
|
|||
// Loop thru all parts of the roll to document everything that was done to create the total roll
|
||||
tempRollSet.forEach((e) => {
|
||||
loggingEnabled && log(LT.LOG, `Formatting roll ${rollConf} | ${JSON.stringify(e)}`);
|
||||
tempRollType = e.type;
|
||||
let preFormat = '';
|
||||
let postFormat = '';
|
||||
|
||||
if (!e.dropped && !e.rerolled) {
|
||||
// If the roll was not dropped or rerolled, add it to the stepTotal and flag the critHit/critFail
|
||||
switch(e.type) {
|
||||
case 'ova':
|
||||
case 'roll20':
|
||||
tempTotal += e.roll;
|
||||
break;
|
||||
case 'cwod':
|
||||
tempTotal += e.critHit ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
if (e.critHit) {
|
||||
tempCrit = true;
|
||||
}
|
||||
|
@ -58,6 +68,9 @@ export const formatRoll = (rollConf: string, maximiseRoll: boolean, nominalRoll:
|
|||
});
|
||||
// After the looping is done, remove the extra " + " from the details and cap it with the closing ]
|
||||
tempDetails = tempDetails.substring(0, tempDetails.length - 3);
|
||||
if (tempRollSet[0]?.type === 'cwod') {
|
||||
tempDetails += `, ${tempRollSet.filter(e => e.critHit).length} Successes, ${tempRollSet.filter(e => e.critFail).length} Fails`;
|
||||
}
|
||||
tempDetails += ']';
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import config from '../../config.ts';
|
||||
import {
|
||||
log,
|
||||
// Log4Deno deps
|
||||
log,
|
||||
LT,
|
||||
} from '../../deps.ts';
|
||||
|
||||
import { RollSet } from './solver.d.ts';
|
||||
import { RollSet, RollConf } from './solver.d.ts';
|
||||
import { rollCWOD } from './customRollers/cwod.ts';
|
||||
import { compareOrigidx, compareRolls, genRoll, loggingEnabled } from './rollUtils.ts';
|
||||
|
||||
// roll(rollStr, maximiseRoll, nominalRoll) returns RollSet
|
||||
|
@ -24,7 +25,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
const dpts = rollStr.split('d');
|
||||
|
||||
// Initialize the configuration to store the parsed data
|
||||
const rollConf = {
|
||||
const rollConf: RollConf = {
|
||||
dieCount: 0,
|
||||
dieSize: 0,
|
||||
drop: {
|
||||
|
@ -69,7 +70,8 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
}
|
||||
|
||||
// Fill out the die count, first item will either be an int or empty string, short circuit execution will take care of replacing the empty string with a 1
|
||||
const tempDC = (dpts.shift() || '1').replace(/\D/g, '');
|
||||
const rawDC = dpts.shift() || '1';
|
||||
const tempDC = rawDC.replace(/\D/g, '');
|
||||
rollConf.dieCount = parseInt(tempDC);
|
||||
|
||||
// Finds the end of the die size/beginnning of the additional options
|
||||
|
@ -88,8 +90,12 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
throw new Error('YouNeedAD');
|
||||
}
|
||||
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsed Die Count: ${rollConf.dieCount}`);
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsed Die Size: ${rollConf.dieSize}`);
|
||||
if (rawDC.endsWith('cwo')) {
|
||||
return rollCWOD(rollStr);
|
||||
}
|
||||
|
||||
loggingEnabled && log(LT.LOG, `Handling roll20 ${rollStr} | Parsed Die Count: ${rollConf.dieCount}`);
|
||||
loggingEnabled && log(LT.LOG, `Handling roll20 ${rollStr} | Parsed Die Size: ${rollConf.dieSize}`);
|
||||
|
||||
// Finish parsing the roll
|
||||
if (remains.length > 0) {
|
||||
|
@ -100,7 +106,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
|
||||
// Loop until all remaining args are parsed
|
||||
while (remains.length > 0) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing remains ${remains}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Parsing remains ${remains}`);
|
||||
// Find the next number in the remains to be able to cut out the rule name
|
||||
let afterSepIdx = remains.search(/\d/);
|
||||
if (afterSepIdx < 0) {
|
||||
|
@ -158,7 +164,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// 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++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing r> ${i}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Parsing r> ${i}`);
|
||||
rollConf.reroll.nums.push(i);
|
||||
}
|
||||
break;
|
||||
|
@ -169,7 +175,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// 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++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing r< ${i}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Parsing r< ${i}`);
|
||||
rollConf.reroll.nums.push(i);
|
||||
}
|
||||
break;
|
||||
|
@ -183,7 +189,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// 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++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing cs> ${i}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Parsing cs> ${i}`);
|
||||
rollConf.critScore.range.push(i);
|
||||
}
|
||||
break;
|
||||
|
@ -191,7 +197,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// 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++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing cs< ${i}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Parsing cs< ${i}`);
|
||||
rollConf.critScore.range.push(i);
|
||||
}
|
||||
break;
|
||||
|
@ -205,7 +211,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// 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++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing cf> ${i}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Parsing cf> ${i}`);
|
||||
rollConf.critFail.range.push(i);
|
||||
}
|
||||
break;
|
||||
|
@ -213,7 +219,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// 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++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing cf< ${i}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Parsing cf< ${i}`);
|
||||
rollConf.critFail.range.push(i);
|
||||
}
|
||||
break;
|
||||
|
@ -246,7 +252,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// 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++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing !> ${i}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Parsing !> ${i}`);
|
||||
rollConf.exploding.nums.push(i);
|
||||
}
|
||||
break;
|
||||
|
@ -257,7 +263,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// 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++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing !< ${i}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Parsing !< ${i}`);
|
||||
rollConf.exploding.nums.push(i);
|
||||
}
|
||||
break;
|
||||
|
@ -280,7 +286,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// Since only one drop or keep option can be active, count how many are active to throw the right error
|
||||
let dkdkCnt = 0;
|
||||
[rollConf.drop.on, rollConf.keep.on, rollConf.dropHigh.on, rollConf.keepLow.on].forEach((e) => {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Checking if drop/keep is on ${e}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Checking if drop/keep is on ${e}`);
|
||||
if (e) {
|
||||
dkdkCnt++;
|
||||
}
|
||||
|
@ -330,7 +336,8 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
*/
|
||||
|
||||
// Initialize a templet rollSet to copy multiple times
|
||||
const templateRoll = {
|
||||
const templateRoll: RollSet = {
|
||||
type: 'roll20',
|
||||
origidx: 0,
|
||||
roll: 0,
|
||||
dropped: false,
|
||||
|
@ -345,7 +352,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
|
||||
// Initial rolling, not handling reroll or exploding here
|
||||
for (let i = 0; i < rollConf.dieCount; i++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Initial rolling ${i} of ${JSON.stringify(rollConf)}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Initial rolling ${i} of ${JSON.stringify(rollConf)}`);
|
||||
// If loopCount gets too high, stop trying to calculate infinity
|
||||
if (loopCount > config.limits.maxLoops) {
|
||||
throw new Error('MaxLoopsExceeded');
|
||||
|
@ -379,7 +386,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
// If needed, handle rerolling and exploding dice now
|
||||
if (rollConf.reroll.on || rollConf.exploding.on) {
|
||||
for (let i = 0; i < rollSet.length; i++) {
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Handling rerolling and exploding ${JSON.stringify(rollSet[i])}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Handling rerolling and exploding ${JSON.stringify(rollSet[i])}`);
|
||||
// If loopCount gets too high, stop trying to calculate infinity
|
||||
if (loopCount > config.limits.maxLoops) {
|
||||
throw new Error('MaxLoopsExceeded');
|
||||
|
@ -456,7 +463,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
throw new Error('MaxLoopsExceeded');
|
||||
}
|
||||
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Setting originalIdx on ${JSON.stringify(rollSet[j])}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Setting originalIdx on ${JSON.stringify(rollSet[j])}`);
|
||||
rollSet[j].origidx = j;
|
||||
|
||||
if (rollSet[j].rerolled) {
|
||||
|
@ -510,7 +517,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
|||
throw new Error('MaxLoopsExceeded');
|
||||
}
|
||||
|
||||
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Dropping dice ${dropCount} ${JSON.stringify(rollSet[i])}`);
|
||||
loggingEnabled && log(LT.LOG, `handling roll20 ${rollStr} | Dropping dice ${dropCount} ${JSON.stringify(rollSet[i])}`);
|
||||
// Skip all rolls that were rerolled
|
||||
if (!rollSet[i].rerolled) {
|
||||
rollSet[i].dropped = true;
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
// solver.ts custom types
|
||||
|
||||
export type RollType = '' | 'roll20' | 'cwod' | 'ova';
|
||||
|
||||
// RollSet is used to preserve all information about a calculated roll
|
||||
export type RollSet = {
|
||||
type: RollType;
|
||||
origidx: number;
|
||||
roll: number;
|
||||
dropped: boolean;
|
||||
|
@ -55,3 +58,43 @@ export type SolvedRoll = {
|
|||
line3: string;
|
||||
counts: CountDetails;
|
||||
};
|
||||
|
||||
// RollConf is used by the roll20 setup
|
||||
export type RollConf = {
|
||||
dieCount: number;
|
||||
dieSize: number;
|
||||
drop: {
|
||||
on: boolean;
|
||||
count: number;
|
||||
};
|
||||
keep: {
|
||||
on: boolean;
|
||||
count: number;
|
||||
};
|
||||
dropHigh: {
|
||||
on: boolean;
|
||||
count: number;
|
||||
};
|
||||
keepLow: {
|
||||
on: boolean;
|
||||
count: number;
|
||||
};
|
||||
reroll: {
|
||||
on: boolean;
|
||||
once: boolean;
|
||||
nums: number[];
|
||||
};
|
||||
critScore: {
|
||||
on: boolean;
|
||||
range: number[];
|
||||
};
|
||||
critFail: {
|
||||
on: boolean;
|
||||
range: number[];
|
||||
};
|
||||
exploding: {
|
||||
on: boolean;
|
||||
once: boolean;
|
||||
nums: number[];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
LT,
|
||||
} from '../../deps.ts';
|
||||
|
||||
import { SolvedStep } from './solver.d.ts';
|
||||
import { SolvedStep, RollType } from './solver.d.ts';
|
||||
import { loggingEnabled } from './rollUtils.ts';
|
||||
|
||||
// fullSolver(conf, wrapDetails) returns one condensed SolvedStep
|
||||
|
@ -19,6 +19,7 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
|||
// Initialize PEMDAS
|
||||
const signs = ['^', '*', '/', '%', '+', '-'];
|
||||
const stepSolve = {
|
||||
rollType: <RollType> '',
|
||||
total: 0,
|
||||
details: '',
|
||||
containsCrit: false,
|
||||
|
|
Loading…
Reference in New Issue