fully fix fate dice

This commit is contained in:
Ean Milligan 2025-06-28 21:47:09 -04:00
parent b6b1f872d2
commit 3ea48838f4
4 changed files with 24 additions and 12 deletions

View File

@ -92,6 +92,8 @@ export const executeRoll = (rollStr: string, modifiers: RollModifiers): Executed
flagRoll(rollConf, rolling); flagRoll(rollConf, rolling);
loggingEnabled && log(LT.LOG, `${getLoopCount()} Roll done ${JSON.stringify(rolling)}`);
// Push the newly created roll and loop again // Push the newly created roll and loop again
rollSet.push(rolling); rollSet.push(rolling);
} }
@ -138,11 +140,13 @@ export const executeRoll = (rollStr: string, modifiers: RollModifiers): Executed
newReroll.roll = minMaxOverride; newReroll.roll = minMaxOverride;
} else { } else {
// If nominalRoll is on, set the roll to the average roll of dieSize, otherwise generate a new random roll // If nominalRoll is on, set the roll to the average roll of dieSize, otherwise generate a new random roll
newReroll.roll = genRoll(rollConf.dieSize, modifiers, rollConf.dPercent); newReroll.roll = rollConf.type === 'fate' ? genFateRoll(modifiers) : genRoll(rollConf.dieSize, modifiers, rollConf.dPercent);
} }
flagRoll(rollConf, newReroll); flagRoll(rollConf, newReroll);
loggingEnabled && log(LT.LOG, `${getLoopCount()} Roll done ${JSON.stringify(newReroll)}`);
// Slot this new roll in after the current iteration so it can be processed in the next loop // Slot this new roll in after the current iteration so it can be processed in the next loop
rollSet.splice(i + 1, 0, newReroll); rollSet.splice(i + 1, 0, newReroll);
} else if ( } else if (
@ -157,13 +161,15 @@ export const executeRoll = (rollStr: string, modifiers: RollModifiers): Executed
// Copy the template to fill out for this iteration // Copy the template to fill out for this iteration
const newExplodingRoll = getTemplateRoll(); const newExplodingRoll = getTemplateRoll();
// If maximizeRoll is on, set the roll to the dieSize, else if nominalRoll is on, set the roll to the average roll of dieSize, else generate a new random roll // If maximizeRoll is on, set the roll to the dieSize, else if nominalRoll is on, set the roll to the average roll of dieSize, else generate a new random roll
newExplodingRoll.roll = genRoll(rollConf.dieSize, modifiers, rollConf.dPercent); newExplodingRoll.roll = rollConf.type === 'fate' ? genFateRoll(modifiers) : genRoll(rollConf.dieSize, modifiers, rollConf.dPercent);
newExplodingRoll.size = rollConf.dieSize; newExplodingRoll.size = rollConf.dieSize;
// Always mark this roll as exploding // Always mark this roll as exploding
newExplodingRoll.exploding = true; newExplodingRoll.exploding = true;
flagRoll(rollConf, newExplodingRoll); flagRoll(rollConf, newExplodingRoll);
loggingEnabled && log(LT.LOG, `${getLoopCount()} Roll done ${JSON.stringify(newExplodingRoll)}`);
// Slot this new roll in after the current iteration so it can be processed in the next loop // Slot this new roll in after the current iteration so it can be processed in the next loop
rollSet.splice(i + 1, 0, newExplodingRoll); rollSet.splice(i + 1, 0, newExplodingRoll);
} }

View File

@ -211,7 +211,7 @@ export const getRollConf = (rollStr: string): RollConf => {
loggingEnabled && log(LT.LOG, `${getLoopCount()} Handling ${rollConf.type} ${rollStr} | Parsing remains ${remains}`); loggingEnabled && log(LT.LOG, `${getLoopCount()} Handling ${rollConf.type} ${rollStr} | Parsing remains ${remains}`);
// Find the next number in the remains to be able to cut out the rule name // Find the next number in the remains to be able to cut out the rule name
let afterSepIdx = remains.search(/\d/); let afterSepIdx = remains.search(/[-\d]/);
if (afterSepIdx < 0) { if (afterSepIdx < 0) {
afterSepIdx = remains.length; afterSepIdx = remains.length;
} }
@ -220,6 +220,7 @@ export const getRollConf = (rollStr: string): RollConf => {
const tempSep = remains.slice(0, afterSepIdx); const tempSep = remains.slice(0, afterSepIdx);
let noNumberAfter = false; let noNumberAfter = false;
NumberlessDiceOptions.some((opt) => { NumberlessDiceOptions.some((opt) => {
loopCountCheck();
if (tempSep.startsWith(opt) && tempSep !== opt) { if (tempSep.startsWith(opt) && tempSep !== opt) {
afterSepIdx = opt.length; afterSepIdx = opt.length;
noNumberAfter = true; noNumberAfter = true;
@ -232,13 +233,15 @@ export const getRollConf = (rollStr: string): RollConf => {
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 = noNumberAfter ? 0 : remains.search(/\D/); let afterNumIdx = noNumberAfter ? 0 : remains.search(/(?![-\d])/);
if (afterNumIdx < 0) { if (afterNumIdx < 0) {
afterNumIdx = remains.length; afterNumIdx = remains.length;
} }
// Save the count/num to tNum leaving it in remains for the time being // Save the count/num to tNum leaving it in remains for the time being
const tNum = parseInt(remains.slice(0, afterNumIdx)); const tNum = parseInt(remains.slice(0, afterNumIdx));
loggingEnabled && log(LT.LOG, `${getLoopCount()} tSep: ${tSep} ${afterSepIdx}, tNum: ${tNum} ${afterNumIdx}`);
// Switch on rule name // Switch on rule name
switch (tSep) { switch (tSep) {
case DiceOptions.Drop: case DiceOptions.Drop:
@ -303,7 +306,7 @@ export const getRollConf = (rollStr: string): RollConf => {
case DiceOptions.RerollLt: 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;
ltAddToRange(tSep, rollConf.reroll.nums, tNum); ltAddToRange(tSep, rollConf.reroll.nums, tNum, rollConf.type);
break; break;
case DiceOptions.CritSuccess: case DiceOptions.CritSuccess:
case DiceOptions.CritSuccessEqu: case DiceOptions.CritSuccessEqu:
@ -319,7 +322,7 @@ export const getRollConf = (rollStr: string): RollConf => {
case DiceOptions.CritSuccessLt: 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;
ltAddToRange(tSep, rollConf.critScore.range, tNum); ltAddToRange(tSep, rollConf.critScore.range, tNum, rollConf.type);
break; break;
case DiceOptions.CritFail: case DiceOptions.CritFail:
case DiceOptions.CritFailEqu: case DiceOptions.CritFailEqu:
@ -335,7 +338,7 @@ export const getRollConf = (rollStr: string): RollConf => {
case DiceOptions.CritFailLt: 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;
ltAddToRange(tSep, rollConf.critFail.range, tNum); ltAddToRange(tSep, rollConf.critFail.range, tNum, rollConf.type);
break; break;
case DiceOptions.Exploding: case DiceOptions.Exploding:
case DiceOptions.ExplodeOnce: case DiceOptions.ExplodeOnce:
@ -370,7 +373,7 @@ export const getRollConf = (rollStr: string): RollConf => {
case DiceOptions.CompoundingExplosionLt: 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;
ltAddToRange(tSep, rollConf.exploding.nums, tNum); ltAddToRange(tSep, rollConf.exploding.nums, tNum, rollConf.type);
break; break;
case DiceOptions.MatchingTotal: case DiceOptions.MatchingTotal:
rollConf.match.returnTotal = true; rollConf.match.returnTotal = true;
@ -416,7 +419,7 @@ export const getRollConf = (rollStr: string): RollConf => {
case DiceOptions.SuccessLt: case DiceOptions.SuccessLt:
// Configure success for all numbers less than or equal to tNum (this could happen multiple times, but why) // Configure success for all numbers less than or equal to tNum (this could happen multiple times, but why)
rollConf.success.on = true; rollConf.success.on = true;
ltAddToRange(tSep, rollConf.success.range, tNum); ltAddToRange(tSep, rollConf.success.range, tNum, rollConf.type);
break; break;
case DiceOptions.Fail: case DiceOptions.Fail:
case DiceOptions.FailEqu: case DiceOptions.FailEqu:
@ -432,7 +435,7 @@ export const getRollConf = (rollStr: string): RollConf => {
case DiceOptions.FailLt: case DiceOptions.FailLt:
// Configure fail for all numbers less than or equal to tNum (this could happen multiple times, but why) // Configure fail for all numbers less than or equal to tNum (this could happen multiple times, but why)
rollConf.fail.on = true; rollConf.fail.on = true;
ltAddToRange(tSep, rollConf.fail.range, tNum); ltAddToRange(tSep, rollConf.fail.range, tNum, rollConf.type);
break; break;
default: default:
// Throw error immediately if unknown op is encountered // Throw error immediately if unknown op is encountered

View File

@ -31,7 +31,8 @@ export const tokenizeMath = (cmd: string, modifiers: RollModifiers, previousResu
.replace(cmdSplitRegex, '') .replace(cmdSplitRegex, '')
.replace(internalWrapRegex, '') .replace(internalWrapRegex, '')
.replace(/ /g, '') .replace(/ /g, '')
.split(/(\*\*)|([-+()*/^]|(?<![d%])%)|(x\d+(\.\d*)?)/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)
.filter((x) => x); .filter((x) => x);
loggingEnabled && log(LT.LOG, `Split roll into mathConf ${JSON.stringify(mathConf)}`); loggingEnabled && log(LT.LOG, `Split roll into mathConf ${JSON.stringify(mathConf)}`);

View File

@ -1,5 +1,7 @@
import { log, LogTypes as LT } from '@Log4Deno'; import { log, LogTypes as LT } from '@Log4Deno';
import { RollType } 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';
@ -18,7 +20,7 @@ const internalAddMultipleToRange = (tSep: string, range: Array<number>, start: n
}; };
// Add numbers less than or equal to tNum to range // Add numbers less than or equal to tNum to range
export const ltAddToRange = (tSep: string, range: Array<number>, tNum: number) => internalAddMultipleToRange(tSep, range, 0, tNum); export const ltAddToRange = (tSep: string, range: Array<number>, tNum: number, rollType: RollType) => internalAddMultipleToRange(tSep, range, rollType === 'fate' ? -1 : 0, tNum);
// Add numbers greater than or equal to tNum to range // Add numbers greater than or equal to tNum to range
export const gtrAddToRange = (tSep: string, range: Array<number>, tNum: number, dieSize: number) => internalAddMultipleToRange(tSep, range, tNum, dieSize); export const gtrAddToRange = (tSep: string, range: Array<number>, tNum: number, dieSize: number) => internalAddMultipleToRange(tSep, range, tNum, dieSize);