roll-parser 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/MIGRATION.md +73 -1
  3. package/README.md +85 -19
  4. package/dist/cli/format.d.ts.map +1 -1
  5. package/dist/cli/format.js +8 -7
  6. package/dist/cli/format.js.map +1 -1
  7. package/dist/evaluator/die.d.ts +2 -1
  8. package/dist/evaluator/die.d.ts.map +1 -1
  9. package/dist/evaluator/die.js.map +1 -1
  10. package/dist/evaluator/env.d.ts +31 -0
  11. package/dist/evaluator/env.d.ts.map +1 -1
  12. package/dist/evaluator/env.js.map +1 -1
  13. package/dist/evaluator/evaluator.d.ts.map +1 -1
  14. package/dist/evaluator/evaluator.js +29 -21
  15. package/dist/evaluator/evaluator.js.map +1 -1
  16. package/dist/evaluator/modifiers/crit-threshold.d.ts +57 -4
  17. package/dist/evaluator/modifiers/crit-threshold.d.ts.map +1 -1
  18. package/dist/evaluator/modifiers/crit-threshold.js +27 -8
  19. package/dist/evaluator/modifiers/crit-threshold.js.map +1 -1
  20. package/dist/evaluator/modifiers/die-bound.d.ts +5 -2
  21. package/dist/evaluator/modifiers/die-bound.d.ts.map +1 -1
  22. package/dist/evaluator/modifiers/die-bound.js +6 -3
  23. package/dist/evaluator/modifiers/die-bound.js.map +1 -1
  24. package/dist/evaluator/modifiers/explode.d.ts.map +1 -1
  25. package/dist/evaluator/modifiers/explode.js +7 -5
  26. package/dist/evaluator/modifiers/explode.js.map +1 -1
  27. package/dist/evaluator/modifiers/flags.d.ts +10 -0
  28. package/dist/evaluator/modifiers/flags.d.ts.map +1 -1
  29. package/dist/evaluator/modifiers/flags.js +7 -0
  30. package/dist/evaluator/modifiers/flags.js.map +1 -1
  31. package/dist/evaluator/modifiers/keep-drop.d.ts +4 -2
  32. package/dist/evaluator/modifiers/keep-drop.d.ts.map +1 -1
  33. package/dist/evaluator/modifiers/keep-drop.js +7 -7
  34. package/dist/evaluator/modifiers/keep-drop.js.map +1 -1
  35. package/dist/evaluator/modifiers/reroll.d.ts.map +1 -1
  36. package/dist/evaluator/modifiers/reroll.js +16 -10
  37. package/dist/evaluator/modifiers/reroll.js.map +1 -1
  38. package/dist/evaluator/modifiers/sort.d.ts +1 -1
  39. package/dist/evaluator/modifiers/sort.d.ts.map +1 -1
  40. package/dist/evaluator/modifiers/sort.js +3 -3
  41. package/dist/evaluator/modifiers/sort.js.map +1 -1
  42. package/dist/evaluator/modifiers/success-count.d.ts +5 -2
  43. package/dist/evaluator/modifiers/success-count.d.ts.map +1 -1
  44. package/dist/evaluator/modifiers/success-count.js +7 -6
  45. package/dist/evaluator/modifiers/success-count.js.map +1 -1
  46. package/dist/parser/ast.d.ts +12 -7
  47. package/dist/parser/ast.d.ts.map +1 -1
  48. package/dist/parser/ast.js.map +1 -1
  49. package/dist/render.d.ts +95 -0
  50. package/dist/render.d.ts.map +1 -0
  51. package/dist/render.js +227 -0
  52. package/dist/render.js.map +1 -0
  53. package/dist/types.d.ts +49 -9
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/types.js.map +1 -1
  56. package/dist/version.d.ts +1 -1
  57. package/dist/version.js +1 -1
  58. package/package.json +11 -1
  59. package/src/cli/format.ts +15 -23
  60. package/src/evaluator/die.ts +2 -1
  61. package/src/evaluator/env.ts +32 -0
  62. package/src/evaluator/evaluator.ts +48 -21
  63. package/src/evaluator/modifiers/crit-threshold.ts +95 -10
  64. package/src/evaluator/modifiers/die-bound.ts +13 -4
  65. package/src/evaluator/modifiers/explode.ts +12 -6
  66. package/src/evaluator/modifiers/flags.ts +17 -0
  67. package/src/evaluator/modifiers/keep-drop.ts +9 -5
  68. package/src/evaluator/modifiers/reroll.ts +20 -11
  69. package/src/evaluator/modifiers/sort.ts +9 -3
  70. package/src/evaluator/modifiers/success-count.ts +21 -6
  71. package/src/parser/ast.ts +12 -7
  72. package/src/render.ts +392 -0
  73. package/src/types.ts +49 -9
  74. package/src/version.ts +1 -1
package/dist/render.js ADDED
@@ -0,0 +1,227 @@
1
+ import { DegreeOfSuccess } from './types.js';
2
+ export const MARKDOWN_MARKS = {
3
+ dropped: (_die, text) => `~~${text}~~`,
4
+ success: (_die, text) => `**${text}**`,
5
+ failure: (_die, text) => `__${text}__`,
6
+ droppedGroup: (inner) => `~~${inner}~~`,
7
+ };
8
+ const KEEP_DROP_CODES = {
9
+ keep: { highest: 'kh', lowest: 'kl' },
10
+ drop: { highest: 'dh', lowest: 'dl' },
11
+ };
12
+ const EXPLODE_MARKERS = {
13
+ standard: '!',
14
+ compound: '!!',
15
+ penetrating: '!p',
16
+ };
17
+ const DEGREE_LABELS = {
18
+ [DegreeOfSuccess.CriticalFailure]: 'Critical Failure',
19
+ [DegreeOfSuccess.Failure]: 'Failure',
20
+ [DegreeOfSuccess.Success]: 'Success',
21
+ [DegreeOfSuccess.CriticalSuccess]: 'Critical Success',
22
+ };
23
+ const BARE_VARIABLE = /^[A-Za-z_][A-Za-z0-9_]*$/;
24
+ function comparePointCode(point) {
25
+ return `${point.operator}${point.value}`;
26
+ }
27
+ function critCode(prefix, threshold) {
28
+ return threshold === 'default' ? prefix : `${prefix}${comparePointCode(threshold)}`;
29
+ }
30
+ function keepDropCode(spec) {
31
+ return `${KEEP_DROP_CODES[spec.kind][spec.selector]}${spec.count}`;
32
+ }
33
+ function failCode(point) {
34
+ return point.operator === '=' ? `f${point.value}` : `f${comparePointCode(point)}`;
35
+ }
36
+ function expr(part) {
37
+ switch (part.type) {
38
+ case 'literal':
39
+ return String(part.value);
40
+ case 'variable':
41
+ return String(part.value);
42
+ case 'dice':
43
+ return `${part.count}d${part.sides}`;
44
+ case 'fateDice':
45
+ return `${part.count}dF`;
46
+ case 'grouped':
47
+ return `(${expr(part.inner)})`;
48
+ case 'binaryOp':
49
+ return `${expr(part.left)} ${part.operator} ${expr(part.right)}`;
50
+ case 'unaryOp':
51
+ return `-${expr(part.operand)}`;
52
+ case 'group':
53
+ return `{${part.parts.map(expr).join(', ')}}`;
54
+ case 'functionCall':
55
+ return `${part.name}(${part.args.map(expr).join(', ')})`;
56
+ case 'keepDrop':
57
+ return `${expr(part.target)}${part.specs.map(keepDropCode).join('')}`;
58
+ case 'explode':
59
+ return `${expr(part.target)}${explodeCode(part)}`;
60
+ case 'reroll':
61
+ return `${expr(part.target)}${part.once ? 'ro' : 'r'}${comparePointCode(part.condition)}`;
62
+ case 'dieBound':
63
+ return `${expr(part.target)}${dieBoundCode(part)}`;
64
+ case 'sort':
65
+ return `${expr(part.target)}${part.order === 'ascending' ? 's' : 'sd'}`;
66
+ case 'critThreshold':
67
+ return `${expr(part.target)}${critThresholdCode(part)}`;
68
+ case 'successCount':
69
+ return `${expr(part.target)}${successCountCode(part)}`;
70
+ case 'versus':
71
+ return `${expr(part.roll)} vs ${expr(part.dc)}`;
72
+ }
73
+ }
74
+ function explodeCode(part) {
75
+ const marker = EXPLODE_MARKERS[part.variant];
76
+ return part.threshold == null ? marker : `${marker}${comparePointCode(part.threshold)}`;
77
+ }
78
+ function dieBoundCode(part) {
79
+ return part.value < 0 ? `${part.bound}(${part.value})` : `${part.bound}${part.value}`;
80
+ }
81
+ function critThresholdCode(part) {
82
+ return [
83
+ ...part.successThresholds.map((threshold) => critCode('cs', threshold)),
84
+ ...part.failThresholds.map((threshold) => critCode('cf', threshold)),
85
+ ].join('');
86
+ }
87
+ function successCountCode(part) {
88
+ const fail = part.failThreshold == null ? '' : failCode(part.failThreshold);
89
+ return `${comparePointCode(part.threshold)}${fail}`;
90
+ }
91
+ function collectDice(part, out) {
92
+ switch (part.type) {
93
+ case 'dice':
94
+ case 'fateDice':
95
+ case 'sort':
96
+ case 'explode':
97
+ case 'reroll':
98
+ case 'successCount':
99
+ for (const die of part.rolls)
100
+ out.push(die);
101
+ return;
102
+ case 'grouped':
103
+ collectDice(part.inner, out);
104
+ return;
105
+ case 'unaryOp':
106
+ collectDice(part.operand, out);
107
+ return;
108
+ case 'binaryOp':
109
+ collectDice(part.left, out);
110
+ collectDice(part.right, out);
111
+ return;
112
+ case 'keepDrop':
113
+ case 'dieBound':
114
+ case 'critThreshold':
115
+ collectDice(part.target, out);
116
+ return;
117
+ case 'group':
118
+ for (const sub of part.parts)
119
+ collectDice(sub, out);
120
+ return;
121
+ case 'functionCall':
122
+ for (const arg of part.args)
123
+ collectDice(arg, out);
124
+ return;
125
+ case 'versus':
126
+ collectDice(part.roll, out);
127
+ collectDice(part.dc, out);
128
+ return;
129
+ case 'literal':
130
+ case 'variable':
131
+ return;
132
+ }
133
+ }
134
+ function poolOf(part) {
135
+ const dice = [];
136
+ collectDice(part, dice);
137
+ return dice;
138
+ }
139
+ function markDie(die, marks, plain) {
140
+ let text = String(die.result);
141
+ if (die.critical)
142
+ text = marks.critical?.(die, text) ?? text;
143
+ if (die.fumble)
144
+ text = marks.fumble?.(die, text) ?? text;
145
+ if (plain)
146
+ return text;
147
+ const { modifiers } = die;
148
+ if (modifiers.includes('dropped'))
149
+ return marks.dropped?.(die, text) ?? text;
150
+ if (modifiers.includes('success'))
151
+ return marks.success?.(die, text) ?? text;
152
+ if (modifiers.includes('failure'))
153
+ return marks.failure?.(die, text) ?? text;
154
+ return text;
155
+ }
156
+ function renderPool(dice, marks, plain) {
157
+ const shown = [];
158
+ for (const die of dice) {
159
+ if (die.modifiers.includes('meta'))
160
+ continue;
161
+ shown.push(markDie(die, marks, plain));
162
+ }
163
+ return `[${shown.join(', ')}]`;
164
+ }
165
+ function renderModifier(target, code, dice, marks, plain) {
166
+ const pool = dice.length === 0 ? '' : renderPool(dice, marks, plain);
167
+ return `${expr(target)}${code}${pool}`;
168
+ }
169
+ function renderPart(part, marks, plain) {
170
+ switch (part.type) {
171
+ case 'literal':
172
+ return String(part.value);
173
+ case 'variable': {
174
+ const display = BARE_VARIABLE.test(part.name) ? `@${part.name}` : `@{${part.name}}`;
175
+ return `${display}[${part.value}]`;
176
+ }
177
+ case 'dice':
178
+ case 'fateDice':
179
+ return `${expr(part)}${renderPool(part.rolls, marks, plain)}`;
180
+ case 'grouped':
181
+ return `(${renderPart(part.inner, marks, plain)})`;
182
+ case 'binaryOp':
183
+ return `${renderPart(part.left, marks, plain)} ${part.operator} ${renderPart(part.right, marks, plain)}`;
184
+ case 'unaryOp':
185
+ return `-${renderPart(part.operand, marks, plain)}`;
186
+ case 'functionCall': {
187
+ const args = part.args.map((arg) => renderPart(arg, marks, plain)).join(', ');
188
+ return `${part.name}(${args})`;
189
+ }
190
+ case 'versus':
191
+ return `${renderPart(part.roll, marks, plain)} vs ${renderPart(part.dc, marks, plain)}`;
192
+ case 'group':
193
+ return renderGroup(part, marks, plain);
194
+ case 'keepDrop':
195
+ return part.target.type === 'group' && part.target.keptIndices != null
196
+ ? renderPart(part.target, marks, plain)
197
+ : `${expr(part.target)}${renderPool(poolOf(part.target), marks, plain)}`;
198
+ case 'explode':
199
+ return renderModifier(part.target, explodeCode(part), part.rolls, marks, plain);
200
+ case 'reroll':
201
+ return renderModifier(part.target, `${part.once ? 'ro' : 'r'}${comparePointCode(part.condition)}`, part.rolls, marks, plain);
202
+ case 'successCount':
203
+ return renderModifier(part.target, successCountCode(part), part.rolls, marks, plain);
204
+ case 'dieBound':
205
+ return `${expr(part.target)}${dieBoundCode(part)}${renderPool(poolOf(part.target), marks, plain)}`;
206
+ case 'sort':
207
+ return `${expr(part.target)}${part.order === 'ascending' ? 's' : 'sd'}${renderPool(part.rolls, marks, plain)}`;
208
+ case 'critThreshold':
209
+ return `${expr(part.target)}${critThresholdCode(part)}${renderPool(poolOf(part.target), marks, plain)}`;
210
+ }
211
+ }
212
+ function renderGroup(part, marks, plain) {
213
+ const { keptIndices } = part;
214
+ const subRolls = part.parts.map((sub, index) => {
215
+ if (keptIndices == null || keptIndices.includes(index)) {
216
+ return renderPart(sub, marks, plain);
217
+ }
218
+ const inner = renderPart(sub, marks, true);
219
+ return marks.droppedGroup?.(inner) ?? inner;
220
+ });
221
+ return `{${subRolls.join(', ')}}`;
222
+ }
223
+ export function renderBreakdown(result, marks = MARKDOWN_MARKS) {
224
+ const trailing = result.degree == null ? String(result.total) : DEGREE_LABELS[result.degree];
225
+ return `${renderPart(result.parts, marks, false)} = ${trailing}`;
226
+ }
227
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -37,9 +37,12 @@ export type ResolvedComparePoint = {
37
37
  readonly value: number;
38
38
  };
39
39
  /**
40
- * A resolved crit threshold — `'default'` means the per-die default rule
41
- * (`result === sides` for critical, `result === 1` for fumble), which is what
42
- * bare `cs` / `cf` produce.
40
+ * A resolved crit threshold — `'default'` means the per-die default rule,
41
+ * which is what bare `cs` / `cf` produce. It reads the natural face
42
+ * (`initialResult ?? result`): critical when it equals `sides`, fumble when
43
+ * it equals 1, both only for `sides > 1`. An explicit ComparePoint instead
44
+ * reads the die's current `result`, so a preceding modifier that rewrote it
45
+ * is visible to the comparison.
43
46
  *
44
47
  * @category Results
45
48
  */
@@ -64,10 +67,14 @@ export type ResolvedCritThreshold = ResolvedComparePoint | 'default';
64
67
  *
65
68
  * `'meta'` is the one tag with no counterpart in the notation. Dice counts,
66
69
  * sides, modifier counts and computed thresholds may themselves be dice
67
- * (`(1d4)d6`, `4d6kh(1d2)`, `1d6!>(1d2+3)`). Those inner dice are not part of
68
- * any pool, so they never appear in a {@link RollPart}; they are appended to
69
- * `RollResult.rolls` tagged `'meta'` so an audit log can still show what the
70
- * meta-expression rolled. Filter them out when summing or displaying a pool.
70
+ * (`(1d4)d6`, `4d6kh(1d2)`, `1d6!>(1d2+3)`). Those inner dice belong to no
71
+ * pool: they never appear on a `dice` or `fateDice` part, and they are
72
+ * appended to `RollResult.rolls` tagged `'meta'` so an audit log can still
73
+ * show what the meta-expression rolled.
74
+ *
75
+ * The four whole-pool views — `sort`, `explode`, `reroll`, and `successCount`
76
+ * `rolls` — are snapshots of an evaluation context rather than of a pool, so
77
+ * they do carry meta dice. Filter them out when summing or displaying a pool.
71
78
  *
72
79
  * `'dc'` marks the DC side of a `vs` comparison. Unlike `'meta'` these dice do
73
80
  * render — `1d20[3] vs 2d10[5, 6]` shows both sides — but they are not part of
@@ -148,9 +155,19 @@ export type DieResult = {
148
155
  initialResult?: number;
149
156
  /** Modifiers applied to this die */
150
157
  modifiers: DieModifier[];
151
- /** True if rolled the maximum value (always false for Fate dice) */
158
+ /**
159
+ * True if the die met its critical criteria — by default, rolling the
160
+ * maximum face on a die with more than one side. That default never fires
161
+ * on `d1` or on Fate dice (`sides = 0` has no maximum face), but an
162
+ * explicit `cs` threshold does: `4dFcs>0` flags every `+1`.
163
+ */
152
164
  critical: boolean;
153
- /** True if rolled 1 (always false for Fate dice) */
165
+ /**
166
+ * True if the die met its fumble criteria — by default, rolling a 1 on a
167
+ * die with more than one side. As with {@link DieResult.critical}, the
168
+ * default never fires on `d1` or Fate dice, while an explicit `cf`
169
+ * threshold does: `4dFcf=-1` flags every `-1`.
170
+ */
154
171
  fumble: boolean;
155
172
  };
156
173
  /**
@@ -296,11 +313,29 @@ export type RollPart = (RollPartBase & {
296
313
  type: 'explode';
297
314
  variant: 'standard' | 'compound' | 'penetrating';
298
315
  threshold?: ResolvedComparePoint;
316
+ /**
317
+ * The expanded pool. Standard and penetrating explosions append dice
318
+ * that exist nowhere under `target`, so this is the only view of the
319
+ * pool the modifier actually produced. Compound explosions accumulate
320
+ * in place, making it the same dice as `target` carries.
321
+ *
322
+ * Like `RollResult.rolls` — and unlike the pool under `target` — this
323
+ * keeps `'meta'` dice. Filter them out before counting or displaying.
324
+ */
325
+ rolls: DieResult[];
299
326
  target: RollPart;
300
327
  }) | (RollPartBase & {
301
328
  type: 'reroll';
302
329
  once: boolean;
303
330
  condition: ResolvedComparePoint;
331
+ /**
332
+ * The post-reroll pool: discarded intermediates (`'rerolled'` +
333
+ * `'dropped'`) alongside their replacements. Both are appended rather
334
+ * than substituted, so neither appears under `target`.
335
+ *
336
+ * Keeps `'meta'` dice, as `RollResult.rolls` does.
337
+ */
338
+ rolls: DieResult[];
304
339
  target: RollPart;
305
340
  }) | (RollPartBase & {
306
341
  type: 'dieBound';
@@ -311,6 +346,11 @@ export type RollPart = (RollPartBase & {
311
346
  type: 'successCount';
312
347
  threshold: ResolvedComparePoint;
313
348
  failThreshold?: ResolvedComparePoint;
349
+ /**
350
+ * The tallied pool, sharing `DieResult` references with `target`.
351
+ * Keeps `'meta'` dice, as `RollResult.rolls` does.
352
+ */
353
+ rolls: DieResult[];
314
354
  target: RollPart;
315
355
  successes: number;
316
356
  failures: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA0HA,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IACzB,2EAAmB,CAAA;IACnB,2DAAW,CAAA;IACX,2DAAW,CAAA;IACX,2EAAmB,CAAA;AACrB,CAAC,EALW,eAAe,KAAf,eAAe,QAK1B"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAiIA,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IACzB,2EAAmB,CAAA;IACnB,2DAAW,CAAA;IACX,2DAAW,CAAA;IACX,2EAAmB,CAAA;AACrB,CAAC,EALW,eAAe,KAAf,eAAe,QAK1B"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const version = "3.0.0";
1
+ export declare const version = "3.1.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const version = '3.0.0';
1
+ export const version = '3.1.0';
2
2
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roll-parser",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "High-performance dice notation parser for tabletop RPGs. TypeScript-first, runs on Node, Bun, and browsers with zero dependencies.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,6 +12,10 @@
12
12
  "types": "./dist/index.d.ts",
13
13
  "default": "./dist/index.js"
14
14
  },
15
+ "./render": {
16
+ "types": "./dist/render.d.ts",
17
+ "default": "./dist/render.js"
18
+ },
15
19
  "./testing": {
16
20
  "types": "./dist/testing.d.ts",
17
21
  "default": "./dist/testing.js"
@@ -112,6 +116,12 @@
112
116
  "import": "{ roll }",
113
117
  "limit": "12 kB"
114
118
  },
119
+ {
120
+ "name": "render.js — { renderBreakdown }",
121
+ "path": "dist/render.js",
122
+ "import": "{ renderBreakdown }",
123
+ "limit": "2 kB"
124
+ },
115
125
  {
116
126
  "name": "testing.js — { createMockRng }",
117
127
  "path": "dist/testing.js",
package/src/cli/format.ts CHANGED
@@ -6,8 +6,22 @@
6
6
  * @module cli/format
7
7
  */
8
8
 
9
+ import { type DieMarks, renderBreakdown } from '../render.js';
9
10
  import type { RollResult } from '../types.js';
10
11
 
12
+ /**
13
+ * Terminal stand-ins for the markdown markers `RollResult.rendered` uses:
14
+ * dropped dice become `(value)`, successes `[value]`, failures `{value}`, so
15
+ * the per-die classification stays visible with no markup dependency. A
16
+ * dropped group sub-roll takes the same parentheses as a dropped die.
17
+ */
18
+ const TERMINAL_MARKS: DieMarks = {
19
+ dropped: (_die, text) => `(${text})`,
20
+ success: (_die, text) => `[${text}]`,
21
+ failure: (_die, text) => `{${text}}`,
22
+ droppedGroup: (inner) => `(${inner})`,
23
+ };
24
+
11
25
  /**
12
26
  * Output mode selectors for {@link formatResult}.
13
27
  */
@@ -42,27 +56,5 @@ export function formatResult(result: RollResult, options: FormatOptions = {}): s
42
56
  return String(result.total);
43
57
  }
44
58
 
45
- return formatRendered(result.rendered);
46
- }
47
-
48
- /**
49
- * Converts markdown-style dice markers to terminal-friendly forms.
50
- *
51
- * The evaluator uses markdown syntax in the rendered field:
52
- * `~~value~~` — dropped dice or dropped group sub-rolls
53
- * `**value**` — dice counted as success
54
- * `__value__` — dice counted as failure
55
- *
56
- * For plain terminals these become `(value)`, `[value]`, and `{value}` so
57
- * the per-die classification stays visible without any markup dependency.
58
- * Dropped spans can wrap a whole sub-roll (e.g. `~~1d8[2]~~` from
59
- * `{1d8, 1d10}kh1`), so the strikethrough pattern accepts any tilde-free
60
- * content, not just a single number. The evaluator never nests `~~`
61
- * (see `stripInnerMarkers`), so the tilde-free span match is safe.
62
- */
63
- function formatRendered(rendered: string): string {
64
- return rendered
65
- .replace(/\*\*(-?\d+)\*\*/g, '[$1]')
66
- .replace(/__(-?\d+)__/g, '{$1}')
67
- .replace(/~~([^~]+)~~/g, '($1)');
59
+ return renderBreakdown(result, TERMINAL_MARKS);
68
60
  }
@@ -37,7 +37,8 @@ export function createDieResult(
37
37
 
38
38
  /**
39
39
  * Creates a Fate/Fudge die result. Uses `sides = 0` as a sentinel — Fate dice
40
- * have no max-face concept, so `critical` and `fumble` are always `false`.
40
+ * have no max-face concept, so `critical` and `fumble` start `false` and the
41
+ * default rule never sets them. An explicit `cs`/`cf` threshold still can.
41
42
  */
42
43
  export function createFateDieResult(result: number, modifiers: DieModifier[]): DieResult {
43
44
  return {
@@ -10,6 +10,17 @@
10
10
 
11
11
  import { EvaluatorError } from '../errors.js';
12
12
  import type { ASTNode } from '../parser/ast.js';
13
+ import type { DieResult, ResolvedCritThreshold } from '../types.js';
14
+
15
+ /**
16
+ * A resolved `cs`/`cf` pair, recorded per die so that dice minted later by
17
+ * explode or reroll can be judged by the rule the user declared instead of
18
+ * the built-in default.
19
+ */
20
+ export type CritRule = {
21
+ readonly success: readonly ResolvedCritThreshold[];
22
+ readonly fail: readonly ResolvedCritThreshold[];
23
+ };
13
24
 
14
25
  /**
15
26
  * Per-evaluation shared environment (created once, shared across all branches).
@@ -35,6 +46,27 @@ export type EvalEnv = {
35
46
  * left-chain check.
36
47
  */
37
48
  insideVersus: boolean;
49
+ /**
50
+ * `true` once a `vs` has tagged its DC dice `'dc'`. Lets every pool
51
+ * operation skip its per-die `isVersusDc` check outright — the tag exists in
52
+ * a small minority of notation, and the call inside the loop cost 11-38% on
53
+ * keep/drop, success, and sort notation that can never carry one (#281).
54
+ *
55
+ * ! Monotonic: set by `evalVersus`, never cleared. `insideVersus` is not a
56
+ * ! model for it — that flag resets in a `finally`, and it is false exactly
57
+ * ! when the tagged DC dice become visible to the enclosing pool.
58
+ */
59
+ hasVersusDc: boolean;
60
+ /**
61
+ * Crit rule per die, keyed on the `DieResult` object itself. Populated by
62
+ * `applyCritThresholds`; read by explode and reroll so a die they mint
63
+ * inherits the rule of the die it descended from.
64
+ *
65
+ * Out of band rather than a `DieResult` field because `DieResult` is public
66
+ * and serialized. `undefined` until the first `cs`/`cf` node — declared here
67
+ * so the shape stays stable for notation that has none.
68
+ */
69
+ critRules: WeakMap<DieResult, CritRule> | undefined;
38
70
  /**
39
71
  * User-supplied variable map for `@name` / `@{name}` references. Always
40
72
  * defined — `evaluate()` defaults to an empty object so lookups can be