Reference → Syntax

Dice expression syntax

Everything the engine accepts. Every example below links to its live distribution at /strike/ — click any to see the exact rationals.

Quick reference

Form Meaning Example
K integer constant 5
NdM roll N M-sided dice, sum the faces 2d6
NdM+K / NdM-K add or subtract a constant to the sum 2d6+5
A + B + … mix any number of dice + constant terms 1d8 + 1d6 + 3
X * K / K * X scalar multiplication — roll X once, multiply the result by integer K (one operand must be a constant; both-random is rejected) (1d4+3)*3
(X) parenthesised group — overrides default precedence (+/- at the bottom, then *, then atoms) (1d6+1d4)*2
NdM! exploding dice — max face rolls again, sums in 1d6!
NdMrK reroll once if the first roll is ≤ K (GWF rule when K=1) 2d6r1+5
NdMkh<K> roll N, keep the highest K and sum (advantage when N=2 K=1; ability-score gen at 4d6kh3) 2d20kh1 · 4d6kh3
NdMkl<K> roll N, keep the lowest K and sum (disadvantage when N=2 K=1; drop-highest pattern at K>1) 2d20kl1 · 4d6kl3
X @ AC<n> +/-<m> attack roll: deal X on a hit, 0 on a miss, doubled dice on a crit 1d8+5 @ AC15 +9
… adv / disadv / elven attack roll with advantage / disadvantage / Elven Accuracy 1d8+5 @ AC15 +9 adv
… c<k> crit on natural ≥ k (Champion: c19) 1d12+5 @ AC15 +9 c19
… dr<n> defender DR — flat reduction to base damage per hit, clamped at 0 (Heavy Armor Master: dr3) 1d8+5 @ AC15 +9 dr3
… dr<n>:<type> per-type DR — only reduces the named damage type's bucket of base damage (RAW HAM: BPS only) 1d8:slashing+1d6:fire @ AC15 +9 dr3:slashing
… brutal<n> extra weapon damage dice on crit (Half-Orc Savage Attacks: brutal1; Barb 9 / 13 / 17: brutal1 / brutal2 / brutal3) 1d12+5 @ AC15 +9 brutal1
… attacks N multi-attack — N independent attacks of this profile (Extra Attack: attacks 2) 1d12+5 @ AC15 +9 attacks 2
X @ hit <p>[%] [crit <p>[%]] [graze <p>[%]] percentage attack (XCOM, Hard West, tactical games) — single hit roll against a flat probability; crit conditional on hit; graze halves damage and eats into miss 1d3+4 @ hit 65 crit 10 graze 15
X save +<b> DC<n> save-for-half (Fireball) — full damage on fail, half on save 8d6 save +5 DC15
… zero save-or-suck (Hold Person) — full damage on fail, zero on save 1d6 save +1 DC13 zero
… t<N> multi-target — N targets share the damage roll, each saves independently (Fireball-into-pod) 8d6 save +5 DC15 t4
… rider <expr> extra damage on hit, doubled dice on a crit (Smite, Hex, Hunter's Mark, Divine Strike) 1d8+5 @ AC15 +9 rider 2d8
… attacks N sneak <expr> once-per-chain rider on the first hit of a multi-attack — Sneak Attack semantics; doubled on crit 1d6+3 @ AC15 +5 attacks 2 sneak 3d6
… attacks N oncrit <attack> once-per-chain bonus attack triggered by any crit in the chain — Great Weapon Master's bonus haft 1d12+15 @ AC15 +4 attacks 2 oncrit 1d12+15 @ AC15 +4
… attacks N bonus <attack> unconditional bonus-action attack — Polearm Master haft, Crossbow Expert bonus shot, Two-Weapon Fighting offhand 1d10+5 @ AC15 +9 attacks 2 bonus 1d4+5 @ AC15 +9
… attacks N bonus X oncrit Y mutually-exclusive bonus actions — PAM haft when no crit, GWM bonus replaces it on a crit (one bonus action per turn, RAW) 1d10+15 @ AC15 +4 attacks 2 bonus 1d4+15 @ AC15 +4 oncrit 1d10+15 @ AC15 +4

Constants and dice

An expression is a sum of terms. Each term is either an integer constant (K) or a dice term (NdM, possibly with a modifier). Whitespace between tokens is optional and ignored; the d can be uppercase (D) too.

  • 5 — a constant 5 (degenerate "distribution" with one outcome).
  • 1d6 — one six-sided die. Six equally-likely faces, mean 3.5.
  • 2d6 — two d6 summed. The classic triangular distribution: 36 outcomes, mean 7, mode 7.
  • 4d6 — four d6, used in 5e ability score generation. The "drop the lowest" variant is 4d6kh3 — keep the highest 3 of 4.

Additive modifiers

The most common 5e weapon-damage form: NdM plus your ability modifier. + and - are left-associative; you can chain any number of terms.

  • 1d8+3 — longsword with +3 STR. Range 4–11, mean 7.5.
  • 2d6+5 — greatsword with +5 STR. Range 7–17, mean 12.
  • 1d12+5 — greataxe with +5 STR. Same modifier; very different shape.

For mixing different dice (e.g., weapon + sneak attack die, base damage + elemental rider), see the next section.

2d6+5
min 7 max 17 mean 12.00 12
  • 7 2.78%
  • 8 5.56%
  • 9 8.33%
  • 10 11.11%
  • 11 13.89%
  • 12 16.67%
  • 13 13.89%
  • 14 11.11%
  • 15 8.33%
  • 16 5.56%
  • 17 2.78%

Mixing dice and constants — the main reason to use the engine

Anyone can compute 2d6 alone. The interesting cases combine different dice — weapon + sneak attack, base damage + elemental rider, primary swing + bonus-action attack — and the resulting distribution isn't an obvious shape. Convolving exact rationals is what this engine does well.

Add as many dice and constant terms as you want, in any order, with + or - between them. Whitespace is optional.

  • 2d6 + 1d4 — pure dice mix, no constant. Range 3–16, mean 19/2 = 9.5.
  • 1d8 + 1d6 + 3 — 5e rogue with a shortbow + sneak attack die + DEX modifier. Three independent terms. Range 5–17, mean 11.
  • 2d6 + 1d4 - 2 — dice plus dice plus a negative constant. Useful for "deal 2d6 + 1d4 damage, target gains 2 temp HP" kind of net-damage scenarios. Range 1–14.
  • 1d8 + 33 + 1d8 — order doesn't matter for + terms; both produce the same distribution and the same slug encoding when you flip them through the parser.

The convolved shape is what you'd expect from the central limit theorem — adding more independent dice pulls the distribution toward a bell curve. Side by side: pure 1d8+1d6 (no modifier) vs the rogue pattern with +3 (same shape, shifted right by 3):

1d8+1d6
min 2 max 14 mean 8.00 8
  • 2 2.08%
  • 3 4.17%
  • 4 6.25%
  • 5 8.33%
  • 6 10.42%
  • 7 12.50%
  • 8 12.50%
  • 9 12.50%
  • 10 10.42%
  • 11 8.33%
  • 12 6.25%
  • 13 4.17%
  • 14 2.08%
1d8+1d6+3
min 5 max 17 mean 11.00 11
  • 5 2.08%
  • 6 4.17%
  • 7 6.25%
  • 8 8.33%
  • 9 10.42%
  • 10 12.50%
  • 11 12.50%
  • 12 12.50%
  • 13 10.42%
  • 14 8.33%
  • 15 6.25%
  • 16 4.17%
  • 17 2.08%

Exploding dice (!)

On a maximum-face roll, roll the die again and add. Recurses up to depth 20 (truncation error ~M⁻²⁰, well below floating-point noise for any practical M). Notation: append ! to the dice term.

Constraint: a 1-sided die can't explode (it would loop forever). Combining ! with r on the same die is rejected — pick one modifier per die term.

1d6
min 1 max 6 mean 3.50 7/2
  • 1 16.67%
  • 2 16.67%
  • 3 16.67%
  • 4 16.67%
  • 5 16.67%
  • 6 16.67%
1d6!
min 1 max 72 mean 4.20 21/5
  • 1 16.67%
  • 2 16.67%
  • 3 16.67%
  • 4 16.67%
  • 5 16.67%
  • 6 0.00%
  • 7 2.78%
  • 8 2.78%
  • 9 2.78%
  • 10 2.78%
  • 11 2.78%
  • 12 0.00%
  • 13 0.46%
  • 14 0.46%
  • 15 0.46%
  • 16 0.46%
  • 17 0.46%
  • 18 0.00%
  • 19 0.08%
  • 20 0.08%
  • 21 0.08%
  • 22 0.08%
  • 23 0.08%
  • 24 0.00%
  • 25 0.01%
  • 26 0.01%
  • 27 0.01%
  • 28 0.01%
  • 29 0.01%
  • 30 0.00%
  • 31 0.00%
  • 32 0.00%
  • 33 0.00%
  • 34 0.00%
  • 35 0.00%
  • 36 0.00%
  • 37 0.00%
  • 38 0.00%
  • 39 0.00%
  • 40 0.00%
  • 41 0.00%
  • 42 0.00%
  • 43 0.00%
  • 44 0.00%
  • 45 0.00%
  • 46 0.00%
  • 47 0.00%
  • 48 0.00%
  • 49 0.00%
  • 50 0.00%
  • 51 0.00%
  • 52 0.00%
  • 53 0.00%
  • 54 0.00%
  • 55 0.00%
  • 56 0.00%
  • 57 0.00%
  • 58 0.00%
  • 59 0.00%
  • 60 0.00%
  • 61 0.00%
  • 62 0.00%
  • 63 0.00%
  • 64 0.00%
  • 65 0.00%
  • 66 0.00%
  • 67 0.00%
  • 68 0.00%
  • 69 0.00%
  • 70 0.00%
  • 71 0.00%
  • 72 0.00%

Reroll once (r<K>)

If the first roll is ≤ K, roll a second time and keep the second result (whether it's higher or lower). The 5e Great Weapon Fighting style is exactly NdMr1 — reroll any 1s and 2s once. (Strict 5e GWF rerolls 1s AND 2s; the engine currently supports only an inclusive ≤ K threshold, so r2 covers both.)

  • 2d6r1+5 — greatsword with GWF "reroll 1s" rule. Compare to plain 2d6+5.
  • 1d12r1+5 — greataxe with the same rule.

Keep-highest / keep-lowest (kh1 / kl1)

Roll N dice, keep only the single highest (kh1) or single lowest (kl1). When N=2 this is exactly 5e advantage and disadvantage.

Generic kh<K> / kl<K> with K ≥ 1 is supported. The kept=1 case uses a closed-form recursion (max-of-N / min-of-N); kept>1 brute-enumerates sides^count outcomes (capped at 200K, which fits 4d6 / 4d20 / 5d6 / 6d6 — the realistic d-and-d ability-gen cases plus a few homebrew variants).

2d20kh1
min 1 max 20 mean 13.82 553/40
  • 1 0.25%
  • 2 0.75%
  • 3 1.25%
  • 4 1.75%
  • 5 2.25%
  • 6 2.75%
  • 7 3.25%
  • 8 3.75%
  • 9 4.25%
  • 10 4.75%
  • 11 5.25%
  • 12 5.75%
  • 13 6.25%
  • 14 6.75%
  • 15 7.25%
  • 16 7.75%
  • 17 8.25%
  • 18 8.75%
  • 19 9.25%
  • 20 9.75%
2d20kl1
min 1 max 20 mean 7.17 287/40
  • 1 9.75%
  • 2 9.25%
  • 3 8.75%
  • 4 8.25%
  • 5 7.75%
  • 6 7.25%
  • 7 6.75%
  • 8 6.25%
  • 9 5.75%
  • 10 5.25%
  • 11 4.75%
  • 12 4.25%
  • 13 3.75%
  • 14 3.25%
  • 15 2.75%
  • 16 2.25%
  • 17 1.75%
  • 18 1.25%
  • 19 0.75%
  • 20 0.25%

Attack rolls (@ AC<n> +/-<m>)

The @ postfix wraps a damage expression with an attack roll vs Armor Class. The result is a per-attempt distribution that includes a zero-mass spike on miss and a crit-doubled tail on natural-20 (or whatever crit range you set):

  • 1d8+5 @ AC15 +9 — a longsword swing with +9 to-hit against an AC 15 target. Per 5e RAW: nat 1 always misses, nat 20 always hits and crits, and the modified roll vs AC handles everything else.
  • 2d6+5 @ AC15 +9 — a greatsword swing under the same conditions. Same hit rate, different damage shape.
  • 1d12+15 @ AC15 +4 — a Greataxe Fighter using Great Weapon Master: −5 to-hit, +10 damage. The break-even AC sits at attack-bonus + 8.

Three optional flags can follow the AC and bonus, in any order:

  • adv / disadv / elven — advantage (2d20 keep highest), disadvantage (2d20 keep lowest), or Elven Accuracy (3d20 keep highest). With advantage, crit rate jumps to 1 − (19/20)² = 9.75%; with Elven Accuracy, to 1 − (19/20)³ ≈ 14.26%. 1d8+5 @ AC15 +9 adv.
  • c<k> — lower the crit range. Champion Fighter is c19 (crits on 19 or 20). 1d12+5 @ AC15 +9 c19.
  • Combine flags: 1d8+5 @ AC15 +9 elven c19 for the Elven Accuracy + Champion crit-fish stack.

Crit damage follows the 5e rule: roll the dice twice, add the modifier once. So a crit on 1d12+5 becomes 2d12+5, not 2(d12+5). The engine handles this automatically — you never write the doubled form by hand.

The @ postfix binds looser than + and -: 2d6+5 @ AC15 +9 parses as "the attack expression with damage = 2d6+5", not as "the attack 5 @ AC15 plus 2d6 plus 9." The damage expression is everything to the left of @.

1d8+5
min 6 max 13 mean 9.50 19/2
  • 6 12.50%
  • 7 12.50%
  • 8 12.50%
  • 9 12.50%
  • 10 12.50%
  • 11 12.50%
  • 12 12.50%
  • 13 12.50%
1d8+5 @ AC15 +9
min 0 max 21 mean 7.35 147/20
  • 0 25.00%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 8.75%
  • 7 8.83%
  • 8 8.91%
  • 9 8.98%
  • 10 9.06%
  • 11 9.14%
  • 12 9.22%
  • 13 9.30%
  • 14 0.63%
  • 15 0.55%
  • 16 0.47%
  • 17 0.39%
  • 18 0.31%
  • 19 0.23%
  • 20 0.16%
  • 21 0.08%

Multi-attack (attacks N)

Postfix attacks N on an attack expression replays the same attack profile N times and convolves the per-attempt distributions. The canonical 5e use case is Extra Attack at level 5 (Fighter, Paladin, Ranger, Barbarian) — two swings with the same weapon per round.

  • 1d12+5 @ AC15 +9 attacks 2 — a Greataxe Fighter at level 5 vs AC 15 with +9 to-hit. The per-round distribution is the convolution of two independent single-swing distributions: each one independently misses, hits, or crits.
  • 1d12+15 @ AC15 +4 attacks 2 — same Fighter using GWM (−5 to-hit, +10 damage) on both swings. Compare to the base form to see the GWM trade across a full round, not just per-attack.
  • 1d12+5 @ AC15 +9 attacks 4 — Action Surge round at level 5 (4 attacks). Mean and variance both quadruple; the distribution narrows toward normal as N grows (CLT in action).

Constraints: N must be in [1, 20]. Main-attack heterogeneity (e.g. Greatsword first attack + Shortsword second attack) isn't expressible directly — write those as a sum of separate Attack expressions, or use the comparison tool's two-side form. The bonus <attack> postfix DOES handle the "homogeneous main + one different bonus" case (PAM haft, TWF offhand, CBE bonus shot), and sneak composes with bonus for Rogue/PAM and Rogue/TWF builds. attacks N only applies after @ — it's strictly the multi-attack convolution. For "roll once and multiply the result", use the * infix operator on a damage expression: (1d4+3)*3 is a single 1d4+3 roll multiplied by 3 (uniform over {12, 15, 18, 21}), distinct from 3d4+9 which sums three independent rolls (same mean, tighter distribution).

1d12+5 @ AC15 +9
min 0 max 29 mean 8.95 179/20
  • 0 25.00%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 5.83%
  • 7 5.87%
  • 8 5.90%
  • 9 5.94%
  • 10 5.97%
  • 11 6.01%
  • 12 6.04%
  • 13 6.08%
  • 14 6.11%
  • 15 6.15%
  • 16 6.18%
  • 17 6.22%
  • 18 0.42%
  • 19 0.38%
  • 20 0.35%
  • 21 0.31%
  • 22 0.28%
  • 23 0.24%
  • 24 0.21%
  • 25 0.17%
  • 26 0.14%
  • 27 0.10%
  • 28 0.07%
  • 29 0.03%
1d12+5 @ AC15 +9 attacks 2
min 0 max 58 mean 17.90 179/10
  • 0 6.25%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 2.92%
  • 7 2.93%
  • 8 2.95%
  • 9 2.97%
  • 10 2.99%
  • 11 3.00%
  • 12 3.36%
  • 13 3.72%
  • 14 4.09%
  • 15 4.46%
  • 16 4.83%
  • 17 5.21%
  • 18 2.68%
  • 19 3.03%
  • 20 3.38%
  • 21 3.74%
  • 22 4.11%
  • 23 4.47%
  • 24 4.17%
  • 25 3.85%
  • 26 3.53%
  • 27 3.19%
  • 28 2.85%
  • 29 2.51%
  • 30 2.15%
  • 31 1.80%
  • 32 1.45%
  • 33 1.08%
  • 34 0.71%
  • 35 0.33%
  • 36 0.28%
  • 37 0.24%
  • 38 0.20%
  • 39 0.16%
  • 40 0.13%
  • 41 0.10%
  • 42 0.07%
  • 43 0.05%
  • 44 0.03%
  • 45 0.02%
  • 46 0.01%
  • 47 0.00%
  • 48 0.00%
  • 49 0.00%
  • 50 0.00%
  • 51 0.00%
  • 52 0.00%
  • 53 0.00%
  • 54 0.00%
  • 55 0.00%
  • 56 0.00%
  • 57 0.00%
  • 58 0.00%

Scalar multiplication and grouping (*, ())

The infix * operator multiplies the rolled value of an expression by an integer constant. At least one operand must be a constant — both-random (1d4*1d6) is rejected because the meaning is ambiguous (scalar mult vs. convolution). Use + to convolve independent rolls.

Grouping parentheses (…) override default precedence. Precedence is +/- (lowest), then *, then atoms — so 1d6 + 1d4*2 parses as 1d6 + (1d4*2). Parens accept an optional :tag postfix for type-tagging the whole group, equivalent to the bracket form ((1d6+5):slashing[1d6+5]:slashing; brackets require the tag, parens make it optional).

  • (1d4+1)*3 — the 2014 Magic Missile shape: roll one 1d4+1 and apply it to all three darts. Mean 10.5, uniform over {6, 9, 12, 15} (4 outcomes).
  • 3d4+3 — the 2024 Magic Missile shape: each dart rolls independently. Same mean (10.5), but tighter — the convolution narrows the distribution by a factor of 3 in variance.
  • 1d6 + 1d4*2 — illustrates precedence: parses as 1d6 + (1d4*2), not (1d6 + 1d4)*2. Wrap in parens to force the other reading.

* is independent of the attacks N multi-attack postfix. Multi-attack is convolution (sum of N independent attack rolls); scalar mult is point-multiplication of one rolled value. Both can appear in the same expression when applicable.

(1d4+1)*3
min 6 max 15 mean 10.50 21/2
  • 6 25.00%
  • 7 0.00%
  • 8 0.00%
  • 9 25.00%
  • 10 0.00%
  • 11 0.00%
  • 12 25.00%
  • 13 0.00%
  • 14 0.00%
  • 15 25.00%
3d4+3
min 6 max 15 mean 10.50 21/2
  • 6 1.56%
  • 7 4.69%
  • 8 9.38%
  • 9 15.63%
  • 10 18.75%
  • 11 18.75%
  • 12 15.63%
  • 13 9.38%
  • 14 4.69%
  • 15 1.56%

Percentage attacks (@ hit <p>%)

The @ hit <p>% postfix is the alternative to @ AC<n> +<m> — a single roll against a flat hit probability instead of d20-vs-AC math. Models XCOM 2, Hard West, Pillars of Eternity, Fire Emblem, and any other tactical game where the player sees a "65%" tooltip rather than a d20 attack roll. Trailing % is optional; hit 65 and hit 65% parse identically.

Two optional postfix flags:

  • crit <p>% — conditional crit chance on a successful hit. P(crit) = P(hit) · crit_chance. Crit damage doubles the damage dice (same rule as the d20 path). Cannot fire on a graze.
  • graze <p>% — partial-hit bucket. P(graze) eats into the miss probability, so a 65% hit / 15% graze build has 80% chance of dealing some damage. Graze damage = floor(dmg / 2) — same div_euclid(2) as Save::Half. Invariant: hit + graze ≤ 100.

The four-way outcome split for 1d3+4 @ hit 65 crit 10 graze 15:

  • P(crit) = 0.65 · 0.10 = 39/400 = 9.75%
  • P(non-crit hit) = 0.65 - 0.0975 = 221/400 = 55.25%
  • P(graze) = 60/400 = 15%
  • P(true miss) = 1 - 0.65 - 0.15 = 80/400 = 20%

What the d20 attack flags do NOT do here. adv / disadv / elven apply only to d20 to-hit ensembles — there's no d20 to roll multiple of in the percentage path, so they're rejected by the parser. Same for c<n> (crit range — replaced by crit <p>%) and shield (defender Shield is a d20 mechanic). What DOES carry over: rider, dr, dr:type, brutal, and attacks N all work identically — they operate on the post-branch damage, not on the to-hit math.

Worked-out math, the variance picture, and what's out of scope (miss-streak protection, Hard West Luck pool) — see the XCOM 2 outcome model pillar. Pre-baked weapon panels live at /games/xcom/.

1d3+4 @ hit 65 crit 10
min 0 max 10 mean 4.03 403/100
  • 0 35.00%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 19.50%
  • 6 20.22%
  • 7 20.94%
  • 8 2.17%
  • 9 1.44%
  • 10 0.72%
1d3+4 @ hit 65 crit 10 graze 15
min 0 max 10 mean 4.43 443/100
  • 0 20.00%
  • 1 0.00%
  • 2 5.00%
  • 3 10.00%
  • 4 0.00%
  • 5 19.50%
  • 6 20.22%
  • 7 20.94%
  • 8 2.17%
  • 9 1.44%
  • 10 0.72%

Saving throws (save +<b> DC<n> [half|zero])

The save postfix wraps a damage expression with a target's saving throw. Per RAW, the result depends on the save:

  • Half on save (default — Fireball-style): full damage on fail, floor(damage/2) on success. The dice are rolled once; the same random variable is halved on save (a Fireball that rolls 30 deals 30 on fail and 15 on save — not "roll separately").
  • Zero on save (use zero flag — Hold Person-style "save-or-suck"): full damage on fail, nothing on success.

Examples:

  • 8d6 save +5 DC15 — Fireball at 3rd-level slot vs a CR-5 monster's DEX +5 save. P(save) = (21+5−15)/20 = 11/20 = 55%; expected damage drops from 28 (always full) to ~20.3 (55% half).
  • 8d6 save +0 DC15 — same Fireball vs a target with no DEX save bonus (CR-1 humanoids, low-tier undead). P(save) = 6/20 = 30%.
  • 10d6 save +5 DC17 — Fireball upcast to 5th-level slot, DC 17 (mid-tier caster). P(save) = 9/20 = 45%.
  • 1d6 save +1 DC13 zero — a save-or-suck cantrip-tier effect: the 1d6 is the "damage-or-control" payload; zero flag means success means it does nothing.

5e RAW for saves: no nat-1 auto-fail or nat-20 auto-success (those rules are for attack rolls; death saves are a separate mechanic). Save probability is just clamp((21 + bonus − DC) / 20, 0, 1). The engine handles boundary cases — a save you can't make (DC 25 vs +0) collapses to the unmodified damage distribution; a save you can't fail collapses to all-zero (Zero) or all-half (Half).

8d6
min 8 max 48 mean 28.00 28
  • 8 0.00%
  • 9 0.00%
  • 10 0.00%
  • 11 0.01%
  • 12 0.02%
  • 13 0.05%
  • 14 0.10%
  • 15 0.20%
  • 16 0.37%
  • 17 0.62%
  • 18 1.00%
  • 19 1.52%
  • 20 2.18%
  • 21 2.99%
  • 22 3.92%
  • 23 4.90%
  • 24 5.88%
  • 25 6.77%
  • 26 7.48%
  • 27 7.94%
  • 28 8.09%
  • 29 7.94%
  • 30 7.48%
  • 31 6.77%
  • 32 5.88%
  • 33 4.90%
  • 34 3.92%
  • 35 2.99%
  • 36 2.18%
  • 37 1.52%
  • 38 1.00%
  • 39 0.62%
  • 40 0.37%
  • 41 0.20%
  • 42 0.10%
  • 43 0.05%
  • 44 0.02%
  • 45 0.01%
  • 46 0.00%
  • 47 0.00%
  • 48 0.00%
8d6 save +5 DC15
min 4 max 48 mean 20.16 1613/80
  • 4 0.00%
  • 5 0.01%
  • 6 0.04%
  • 7 0.17%
  • 8 0.54%
  • 9 1.39%
  • 10 2.85%
  • 11 4.86%
  • 12 6.97%
  • 13 8.50%
  • 14 8.86%
  • 15 7.93%
  • 16 6.10%
  • 17 4.08%
  • 18 2.49%
  • 19 1.58%
  • 20 1.29%
  • 21 1.43%
  • 22 1.78%
  • 23 2.21%
  • 24 2.65%
  • 25 3.05%
  • 26 3.36%
  • 27 3.57%
  • 28 3.64%
  • 29 3.57%
  • 30 3.36%
  • 31 3.05%
  • 32 2.65%
  • 33 2.21%
  • 34 1.76%
  • 35 1.35%
  • 36 0.98%
  • 37 0.68%
  • 38 0.45%
  • 39 0.28%
  • 40 0.16%
  • 41 0.09%
  • 42 0.05%
  • 43 0.02%
  • 44 0.01%
  • 45 0.00%
  • 46 0.00%
  • 47 0.00%
  • 48 0.00%

Multi-target AOE (t<N>)

Postfix t<N> on a save expression extends to multi-target: the SAME damage roll applies to N independent saves. Per RAW, the dice are rolled once and each target saves separately, taking either full damage on fail or transformed damage on success. The per-cast total is the sum across targets.

  • 8d6 save +5 DC15 t4 — Fireball (3rd-level slot) into a pod of 4 CR-5 monsters (DEX +5 save, P(save) = 55%). Per-cast mean ≈ 81 (4× the single-target ≈ 20).
  • 8d6 save +0 DC15 t8 — Fireball into a swarm of 8 weak humanoids (no DEX save). Per-cast mean ≈ 190. This is the "DEX +0 minions are Fireball food" regime.
  • 8d8 save +5 DC17 t4 — Cone of Cold (5th-level slot) into 4 mid-tier targets, DC bumped to 17.

Implementation: for each rolled damage value x and number of failed saves k (where K ~ binomial(N, P(fail))), the per-cast total is x·k + transform(x)·(N − k). Independence of damage roll and per-target save outcomes makes this a clean product-of-distributions over the support — sub-millisecond even for Cone-of-Cold-into-8 (8d8 × 9-bucket binomial = ~500 pre-mix outcomes).

Constraint: N must be in [1, 20]. t1 is the default and identical to omitting the flag. The t flag composes with half / zero in any order: 1d6 save +1 DC13 zero t3 (save-or-suck into 3 targets) parses fine.

8d6 save +5 DC15
min 4 max 48 mean 20.16 1613/80
  • 4 0.00%
  • 5 0.01%
  • 6 0.04%
  • 7 0.17%
  • 8 0.54%
  • 9 1.39%
  • 10 2.85%
  • 11 4.86%
  • 12 6.97%
  • 13 8.50%
  • 14 8.86%
  • 15 7.93%
  • 16 6.10%
  • 17 4.08%
  • 18 2.49%
  • 19 1.58%
  • 20 1.29%
  • 21 1.43%
  • 22 1.78%
  • 23 2.21%
  • 24 2.65%
  • 25 3.05%
  • 26 3.36%
  • 27 3.57%
  • 28 3.64%
  • 29 3.57%
  • 30 3.36%
  • 31 3.05%
  • 32 2.65%
  • 33 2.21%
  • 34 1.76%
  • 35 1.35%
  • 36 0.98%
  • 37 0.68%
  • 38 0.45%
  • 39 0.28%
  • 40 0.16%
  • 41 0.09%
  • 42 0.05%
  • 43 0.02%
  • 44 0.01%
  • 45 0.00%
  • 46 0.00%
  • 47 0.00%
  • 48 0.00%
8d6 save +5 DC15 t4
min 16 max 192 mean 80.65 1613/20
  • 16 0.00%
  • 17 0.00%
  • 18 0.00%
  • 19 0.00%
  • 20 0.00%
  • 21 0.00%
  • 22 0.00%
  • 23 0.00%
  • 24 0.01%
  • 25 0.00%
  • 26 0.00%
  • 27 0.00%
  • 28 0.03%
  • 29 0.00%
  • 30 0.01%
  • 31 0.01%
  • 32 0.09%
  • 33 0.00%
  • 34 0.00%
  • 35 0.03%
  • 36 0.30%
  • 37 0.00%
  • 38 0.02%
  • 39 0.00%
  • 40 0.58%
  • 41 0.19%
  • 42 0.04%
  • 43 0.00%
  • 44 0.88%
  • 45 0.31%
  • 46 0.45%
  • 47 0.00%
  • 48 1.29%
  • 49 0.02%
  • 50 0.88%
  • 51 0.90%
  • 52 1.45%
  • 53 0.00%
  • 54 0.37%
  • 55 1.17%
  • 56 3.57%
  • 57 0.00%
  • 58 0.00%
  • 59 0.13%
  • 60 3.88%
  • 61 2.03%
  • 62 1.10%
  • 63 0.20%
  • 64 1.00%
  • 65 2.24%
  • 66 4.12%
  • 67 0.00%
  • 68 2.46%
  • 69 0.00%
  • 70 2.86%
  • 71 2.38%
  • 72 2.54%
  • 73 0.60%
  • 74 2.49%
  • 75 2.24%
  • 76 2.24%
  • 77 0.79%
  • 78 2.75%
  • 79 0.00%
  • 80 5.80%
  • 81 1.47%
  • 82 0.00%
  • 83 0.00%
  • 84 4.29%
  • 85 1.17%
  • 86 3.81%
  • 87 1.36%
  • 88 0.16%
  • 89 0.00%
  • 90 3.40%
  • 91 1.95%
  • 92 2.69%
  • 93 0.00%
  • 94 1.59%
  • 95 0.30%
  • 96 2.59%
  • 97 0.00%
  • 98 3.43%
  • 99 0.00%
  • 100 0.39%
  • 101 1.65%
  • 102 1.44%
  • 103 0.00%
  • 104 1.41%
  • 105 1.53%
  • 106 0.01%
  • 107 0.00%
  • 108 2.49%
  • 109 0.00%
  • 110 0.56%
  • 111 0.00%
  • 112 1.51%
  • 113 0.00%
  • 114 0.37%
  • 115 0.98%
  • 116 0.55%
  • 117 0.00%
  • 118 0.00%
  • 119 0.79%
  • 120 0.44%
  • 121 0.00%
  • 122 0.67%
  • 123 0.00%
  • 124 0.28%
  • 125 0.00%
  • 126 0.48%
  • 127 0.00%
  • 128 0.26%
  • 129 0.30%
  • 130 0.00%
  • 131 0.00%
  • 132 0.21%
  • 133 0.20%
  • 134 0.00%
  • 135 0.00%
  • 136 0.29%
  • 137 0.00%
  • 138 0.00%
  • 139 0.00%
  • 140 0.20%
  • 141 0.00%
  • 142 0.00%
  • 143 0.04%
  • 144 0.09%
  • 145 0.00%
  • 146 0.00%
  • 147 0.02%
  • 148 0.06%
  • 149 0.00%
  • 150 0.01%
  • 151 0.00%
  • 152 0.04%
  • 153 0.00%
  • 154 0.00%
  • 155 0.00%
  • 156 0.03%
  • 157 0.00%
  • 158 0.00%
  • 159 0.00%
  • 160 0.02%
  • 161 0.00%
  • 162 0.00%
  • 163 0.00%
  • 164 0.01%
  • 165 0.00%
  • 166 0.00%
  • 167 0.00%
  • 168 0.00%
  • 169 0.00%
  • 170 0.00%
  • 171 0.00%
  • 172 0.00%
  • 173 0.00%
  • 174 0.00%
  • 175 0.00%
  • 176 0.00%
  • 177 0.00%
  • 178 0.00%
  • 179 0.00%
  • 180 0.00%
  • 181 0.00%
  • 182 0.00%
  • 183 0.00%
  • 184 0.00%
  • 185 0.00%
  • 186 0.00%
  • 187 0.00%
  • 188 0.00%
  • 189 0.00%
  • 190 0.00%
  • 191 0.00%
  • 192 0.00%

Rider damage (rider <expr>)

The rider postfix attaches an extra damage expression that fires on every hit. On a normal hit the rider's value is added to the base damage; on a crit the rider's dice are doubled too (per RAW — the same rule that doubles the base damage dice). On a miss, no rider — the rider only fires when the swing connects.

Use this for any "extra dice on hit" mechanic that fires every time:

Sneak Attack is not a rider — use sneak instead. Sneak Attack triggers once per turn, on the first qualifying hit. Using rider for it on a multi-attack chain would double-count, since rider fires on every hit. The sneak postfix on a multi-attack chain (next section) models the once-per-chain semantics correctly.

1d8+5 @ AC15 +9 rider 2d8
min 0 max 53 mean 14.55 291/20
  • 0 25.00%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.00%
  • 8 0.14%
  • 9 0.41%
  • 10 0.82%
  • 11 1.37%
  • 12 2.05%
  • 13 2.87%
  • 14 3.83%
  • 15 4.92%
  • 16 5.75%
  • 17 6.30%
  • 18 6.58%
  • 19 6.59%
  • 20 6.33%
  • 21 5.80%
  • 22 5.00%
  • 23 3.93%
  • 24 3.01%
  • 25 2.22%
  • 26 1.57%
  • 27 1.06%
  • 28 0.69%
  • 29 0.44%
  • 30 0.33%
  • 31 0.34%
  • 32 0.35%
  • 33 0.34%
  • 34 0.33%
  • 35 0.30%
  • 36 0.27%
  • 37 0.24%
  • 38 0.21%
  • 39 0.17%
  • 40 0.13%
  • 41 0.10%
  • 42 0.08%
  • 43 0.05%
  • 44 0.04%
  • 45 0.02%
  • 46 0.02%
  • 47 0.01%
  • 48 0.00%
  • 49 0.00%
  • 50 0.00%
  • 51 0.00%
  • 52 0.00%
  • 53 0.00%
1d8+5 @ AC15 +9 rider 2d8 attacks 2
min 0 max 106 mean 29.10 291/10
  • 0 6.25%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.00%
  • 8 0.07%
  • 9 0.21%
  • 10 0.41%
  • 11 0.68%
  • 12 1.03%
  • 13 1.44%
  • 14 1.91%
  • 15 2.46%
  • 16 2.87%
  • 17 3.15%
  • 18 3.29%
  • 19 3.30%
  • 20 3.19%
  • 21 2.95%
  • 22 2.59%
  • 23 2.11%
  • 24 1.74%
  • 25 1.48%
  • 26 1.32%
  • 27 1.29%
  • 28 1.36%
  • 29 1.54%
  • 30 1.82%
  • 31 2.19%
  • 32 2.55%
  • 33 2.88%
  • 34 3.17%
  • 35 3.39%
  • 36 3.53%
  • 37 3.57%
  • 38 3.53%
  • 39 3.39%
  • 40 3.18%
  • 41 2.91%
  • 42 2.60%
  • 43 2.27%
  • 44 1.94%
  • 45 1.63%
  • 46 1.35%
  • 47 1.11%
  • 48 0.92%
  • 49 0.76%
  • 50 0.64%
  • 51 0.55%
  • 52 0.48%
  • 53 0.43%
  • 54 0.38%
  • 55 0.34%
  • 56 0.31%
  • 57 0.27%
  • 58 0.24%
  • 59 0.20%
  • 60 0.17%
  • 61 0.14%
  • 62 0.12%
  • 63 0.09%
  • 64 0.07%
  • 65 0.06%
  • 66 0.04%
  • 67 0.03%
  • 68 0.03%
  • 69 0.02%
  • 70 0.02%
  • 71 0.01%
  • 72 0.01%
  • 73 0.01%
  • 74 0.01%
  • 75 0.01%
  • 76 0.00%
  • 77 0.00%
  • 78 0.00%
  • 79 0.00%
  • 80 0.00%
  • 81 0.00%
  • 82 0.00%
  • 83 0.00%
  • 84 0.00%
  • 85 0.00%
  • 86 0.00%
  • 87 0.00%
  • 88 0.00%
  • 89 0.00%
  • 90 0.00%
  • 91 0.00%
  • 92 0.00%
  • 93 0.00%
  • 94 0.00%
  • 95 0.00%
  • 96 0.00%
  • 97 0.00%
  • 98 0.00%
  • 99 0.00%
  • 100 0.00%
  • 101 0.00%
  • 102 0.00%
  • 103 0.00%
  • 104 0.00%
  • 105 0.00%
  • 106 0.00%

Sneak Attack chain (attacks N sneak <expr>)

The sneak postfix attaches to a multi-attack chain (attacks N) and adds extra damage to the first hit (or crit) of the chain — exactly once per round, regardless of how many attacks land. Models 5e Sneak Attack, where a Rogue gets their bonus dice once per turn on whichever swing connects first.

On a crit the sneak dice are doubled too, just like the base damage. On a no-hit chain (every attack misses), no sneak is added — chain damage is zero.

The semantic difference from rider matters as soon as N > 1:

  • 1d6+3 @ AC15 +5 rider 3d6 attacks 2 — Rogue with TWO attacks each carrying 3d6 sneak dice (incorrect: doubles up the per-turn limit).
  • 1d6+3 @ AC15 +5 attacks 2 sneak 3d6 — Rogue with TWO attacks where the first hit triggers 3d6 sneak (correct: the per-turn limit is enforced at the chain level).

Composes with rider on the inner attack — a Paladin/Rogue multiclass declares both, and both fire: 1d8+5 @ AC15 +9 rider 2d8 attacks 2 sneak 3d6 gives every hit Improved Divine Smite (2d8) and pours sneak dice (3d6) into whichever swing lands first.

Edge case: attacks 1 sneak X is mathematically equivalent to rider X — there's only one attack, so "first hit" and "every hit" are the same event. The engine recognises this; both forms produce the same distribution.

1d6+3 @ AC15 +5 attacks 2 sneak 3d6
min 0 max 66 mean 16.63 3327/200
  • 0 20.25%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.03%
  • 8 0.14%
  • 9 0.35%
  • 10 0.69%
  • 11 1.22%
  • 12 1.96%
  • 13 2.83%
  • 14 3.73%
  • 15 4.57%
  • 16 5.28%
  • 17 5.75%
  • 18 5.88%
  • 19 5.75%
  • 20 5.44%
  • 21 5.01%
  • 22 4.50%
  • 23 3.98%
  • 24 3.53%
  • 25 3.11%
  • 26 2.69%
  • 27 2.29%
  • 28 1.92%
  • 29 1.58%
  • 30 1.27%
  • 31 1.01%
  • 32 0.82%
  • 33 0.68%
  • 34 0.58%
  • 35 0.50%
  • 36 0.44%
  • 37 0.39%
  • 38 0.35%
  • 39 0.30%
  • 40 0.26%
  • 41 0.22%
  • 42 0.18%
  • 43 0.14%
  • 44 0.11%
  • 45 0.09%
  • 46 0.07%
  • 47 0.05%
  • 48 0.03%
  • 49 0.02%
  • 50 0.01%
  • 51 0.01%
  • 52 0.01%
  • 53 0.00%
  • 54 0.00%
  • 55 0.00%
  • 56 0.00%
  • 57 0.00%
  • 58 0.00%
  • 59 0.00%
  • 60 0.00%
  • 61 0.00%
  • 62 0.00%
  • 63 0.00%
  • 64 0.00%
  • 65 0.00%
  • 66 0.00%
1d6+3 @ AC15 +5 attacks 2 sneak 5d6
min 0 max 90 mean 22.73 909/40
  • 0 20.25%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.00%
  • 8 0.00%
  • 9 0.00%
  • 10 0.01%
  • 11 0.02%
  • 12 0.05%
  • 13 0.12%
  • 14 0.24%
  • 15 0.44%
  • 16 0.74%
  • 17 1.14%
  • 18 1.65%
  • 19 2.25%
  • 20 2.91%
  • 21 3.56%
  • 22 4.17%
  • 23 4.67%
  • 24 5.02%
  • 25 5.19%
  • 26 5.19%
  • 27 5.02%
  • 28 4.73%
  • 29 4.35%
  • 30 3.91%
  • 31 3.45%
  • 32 3.00%
  • 33 2.55%
  • 34 2.14%
  • 35 1.76%
  • 36 1.43%
  • 37 1.14%
  • 38 0.90%
  • 39 0.72%
  • 40 0.59%
  • 41 0.50%
  • 42 0.45%
  • 43 0.43%
  • 44 0.42%
  • 45 0.42%
  • 46 0.42%
  • 47 0.42%
  • 48 0.41%
  • 49 0.40%
  • 50 0.38%
  • 51 0.36%
  • 52 0.33%
  • 53 0.29%
  • 54 0.26%
  • 55 0.23%
  • 56 0.19%
  • 57 0.16%
  • 58 0.14%
  • 59 0.11%
  • 60 0.09%
  • 61 0.07%
  • 62 0.05%
  • 63 0.04%
  • 64 0.03%
  • 65 0.02%
  • 66 0.01%
  • 67 0.01%
  • 68 0.01%
  • 69 0.00%
  • 70 0.00%
  • 71 0.00%
  • 72 0.00%
  • 73 0.00%
  • 74 0.00%
  • 75 0.00%
  • 76 0.00%
  • 77 0.00%
  • 78 0.00%
  • 79 0.00%
  • 80 0.00%
  • 81 0.00%
  • 82 0.00%
  • 83 0.00%
  • 84 0.00%
  • 85 0.00%
  • 86 0.00%
  • 87 0.00%
  • 88 0.00%
  • 89 0.00%
  • 90 0.00%

Bonus attack on crit (attacks N oncrit <attack>)

The oncrit postfix attaches to a multi-attack chain (attacks N) and adds a once-per-chain bonus attack that triggers when at least one of the main attacks crits. Models 5e Great Weapon Master's bonus haft attack: on a crit, you get a free bonus-action swing with a melee weapon. The kill-trigger half of GWM lives in the GWM-on-kill cascade pillar — that's the same bonus action wired into the cascade machinery instead of the per-attack chain.

The bonus is a full attack — it has its own to-hit roll, miss/hit/crit branches, and damage. Syntax requires the @ AC<n> +/-<m> postfix on the bonus expression so the parser can build a complete attack profile:

1d12+15 @ AC15 +4 attacks 2 oncrit 1d12+15 @ AC15 +4

Critical resource semantic: the bonus action is a per-turn resource, so even when both main attacks crit (a Champion's day out), the bonus fires once, not twice. This mirrors how Sneak Attack caps at one trigger per turn — and the analytic mean reflects it: bonus contribution = P(≥1 crit in N) × E[bonus per-attempt], not N × P(crit) × E[bonus per-attempt].

Composes with rider on the inner attack — Smite (rider, every-hit) plus GWM (oncrit, once-per-chain bonus attack) is a real Paladin/Fighter multiclass move: 1d12+5 @ AC15 +9 rider 2d8 attacks 2 oncrit 1d12+5 @ AC15 +9. Each main hit gets Improved Divine Smite damage, and a crit on either swing triggers a fresh bonus attack with its own to-hit.

sneak and oncrit are mutually exclusive postfixes on the same chain — the parser rejects that combination with an explicit error rather than silently producing the wrong distribution. The realistic build that would want both (Rogue / Fighter with GWM dipping) is rare enough that the explicit error is the right surface.

1d12+15 @ AC15 +4 attacks 2 oncrit 1d12+15 @ AC15 +4
min 0 max 117 mean 23.23 371677/16000
  • 0 25.00%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.00%
  • 8 0.00%
  • 9 0.00%
  • 10 0.00%
  • 11 0.00%
  • 12 0.00%
  • 13 0.00%
  • 14 0.00%
  • 15 0.00%
  • 16 3.75%
  • 17 3.77%
  • 18 3.78%
  • 19 3.80%
  • 20 3.82%
  • 21 3.84%
  • 22 3.85%
  • 23 3.87%
  • 24 3.89%
  • 25 3.91%
  • 26 3.92%
  • 27 3.94%
  • 28 0.21%
  • 29 0.19%
  • 30 0.17%
  • 31 0.16%
  • 32 0.28%
  • 33 0.41%
  • 34 0.53%
  • 35 0.67%
  • 36 0.80%
  • 37 0.94%
  • 38 1.07%
  • 39 1.22%
  • 40 1.36%
  • 41 1.53%
  • 42 1.69%
  • 43 1.86%
  • 44 1.76%
  • 45 1.64%
  • 46 1.52%
  • 47 1.40%
  • 48 1.27%
  • 49 1.14%
  • 50 1.00%
  • 51 0.86%
  • 52 0.71%
  • 53 0.55%
  • 54 0.40%
  • 55 0.23%
  • 56 0.20%
  • 57 0.18%
  • 58 0.16%
  • 59 0.14%
  • 60 0.13%
  • 61 0.12%
  • 62 0.11%
  • 63 0.11%
  • 64 0.10%
  • 65 0.10%
  • 66 0.11%
  • 67 0.11%
  • 68 0.12%
  • 69 0.12%
  • 70 0.13%
  • 71 0.13%
  • 72 0.13%
  • 73 0.12%
  • 74 0.12%
  • 75 0.11%
  • 76 0.11%
  • 77 0.10%
  • 78 0.09%
  • 79 0.08%
  • 80 0.07%
  • 81 0.06%
  • 82 0.05%
  • 83 0.04%
  • 84 0.03%
  • 85 0.03%
  • 86 0.02%
  • 87 0.02%
  • 88 0.01%
  • 89 0.01%
  • 90 0.01%
  • 91 0.01%
  • 92 0.00%
  • 93 0.00%
  • 94 0.00%
  • 95 0.00%
  • 96 0.00%
  • 97 0.00%
  • 98 0.00%
  • 99 0.00%
  • 100 0.00%
  • 101 0.00%
  • 102 0.00%
  • 103 0.00%
  • 104 0.00%
  • 105 0.00%
  • 106 0.00%
  • 107 0.00%
  • 108 0.00%
  • 109 0.00%
  • 110 0.00%
  • 111 0.00%
  • 112 0.00%
  • 113 0.00%
  • 114 0.00%
  • 115 0.00%
  • 116 0.00%
  • 117 0.00%
1d12+15 @ AC15 +4 c19 attacks 2 oncrit 1d12+15 @ AC15 +4 c19
min 0 max 117 mean 24.97 12483/500
  • 0 25.00%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.00%
  • 8 0.00%
  • 9 0.00%
  • 10 0.00%
  • 11 0.00%
  • 12 0.00%
  • 13 0.00%
  • 14 0.00%
  • 15 0.00%
  • 16 3.33%
  • 17 3.37%
  • 18 3.40%
  • 19 3.44%
  • 20 3.47%
  • 21 3.51%
  • 22 3.54%
  • 23 3.58%
  • 24 3.61%
  • 25 3.65%
  • 26 3.68%
  • 27 3.72%
  • 28 0.42%
  • 29 0.38%
  • 30 0.35%
  • 31 0.31%
  • 32 0.39%
  • 33 0.47%
  • 34 0.56%
  • 35 0.65%
  • 36 0.74%
  • 37 0.84%
  • 38 0.95%
  • 39 1.06%
  • 40 1.17%
  • 41 1.33%
  • 42 1.49%
  • 43 1.65%
  • 44 1.60%
  • 45 1.54%
  • 46 1.48%
  • 47 1.40%
  • 48 1.31%
  • 49 1.22%
  • 50 1.12%
  • 51 1.00%
  • 52 0.88%
  • 53 0.75%
  • 54 0.61%
  • 55 0.46%
  • 56 0.41%
  • 57 0.36%
  • 58 0.33%
  • 59 0.29%
  • 60 0.26%
  • 61 0.24%
  • 62 0.22%
  • 63 0.21%
  • 64 0.20%
  • 65 0.20%
  • 66 0.20%
  • 67 0.21%
  • 68 0.22%
  • 69 0.22%
  • 70 0.23%
  • 71 0.23%
  • 72 0.23%
  • 73 0.23%
  • 74 0.22%
  • 75 0.21%
  • 76 0.20%
  • 77 0.19%
  • 78 0.18%
  • 79 0.16%
  • 80 0.15%
  • 81 0.13%
  • 82 0.11%
  • 83 0.10%
  • 84 0.08%
  • 85 0.07%
  • 86 0.06%
  • 87 0.05%
  • 88 0.04%
  • 89 0.03%
  • 90 0.02%
  • 91 0.02%
  • 92 0.02%
  • 93 0.01%
  • 94 0.01%
  • 95 0.01%
  • 96 0.01%
  • 97 0.00%
  • 98 0.00%
  • 99 0.00%
  • 100 0.00%
  • 101 0.00%
  • 102 0.00%
  • 103 0.00%
  • 104 0.00%
  • 105 0.00%
  • 106 0.00%
  • 107 0.00%
  • 108 0.00%
  • 109 0.00%
  • 110 0.00%
  • 111 0.00%
  • 112 0.00%
  • 113 0.00%
  • 114 0.00%
  • 115 0.00%
  • 116 0.00%
  • 117 0.00%

Bonus action attack (attacks N bonus <attack>)

The bonus postfix attaches an unconditional bonus- action attack to a multi-attack chain — the bonus always fires once per chain, regardless of main-attack outcomes. Models any "you always get one extra attack with X" feature: Polearm Master's haft, Two-Weapon Fighting's offhand, Crossbow Expert's hand-crossbow bonus shot, Monk Martial Arts.

Same parse shape as oncrit — the bonus is a full attack expression with its own @ AC<n> +/-<m> to-hit. PAM with a glaive (1d10+STR main, 1d4+STR haft) at +9 vs AC 15:

1d10+5 @ AC15 +9 attacks 2 bonus 1d4+5 @ AC15 +9

Why a postfix when + would seem to suffice? The grammar actually rejects attacks N + <attack> (the multi-attack chain returns at the top level), so prior to this construct PAM wasn't expressible at all. Stacking bonus with oncrit on the same chain builds an exclusive-mutex node — see the next section (PAM + GWM with the per-turn-bonus-action constraint enforced).

Distribution-equivalent at the math layer to a hypothetical attacks N main + bonus — both are an N-fold convolution of the main per-attempt distribution, then convolved with the bonus per-attempt. Linearity gives the closed-form mean: N · E[main per-attempt] + E[bonus per-attempt].

1d10+5 @ AC15 +9 attacks 2 bonus 1d4+5 @ AC15 +9
min 0 max 63 mean 22.05 441/20
  • 0 1.56%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 1.97%
  • 7 1.99%
  • 8 2.02%
  • 9 2.05%
  • 10 0.98%
  • 11 0.96%
  • 12 1.69%
  • 13 2.43%
  • 14 3.18%
  • 15 3.97%
  • 16 3.30%
  • 17 3.47%
  • 18 3.73%
  • 19 4.06%
  • 20 4.47%
  • 21 4.98%
  • 22 4.65%
  • 23 4.30%
  • 24 3.94%
  • 25 3.56%
  • 26 3.78%
  • 27 4.01%
  • 28 4.08%
  • 29 3.99%
  • 30 3.73%
  • 31 3.28%
  • 32 2.92%
  • 33 2.55%
  • 34 2.17%
  • 35 1.78%
  • 36 1.39%
  • 37 0.99%
  • 38 0.66%
  • 39 0.42%
  • 40 0.27%
  • 41 0.21%
  • 42 0.16%
  • 43 0.12%
  • 44 0.08%
  • 45 0.06%
  • 46 0.04%
  • 47 0.02%
  • 48 0.01%
  • 49 0.01%
  • 50 0.00%
  • 51 0.00%
  • 52 0.00%
  • 53 0.00%
  • 54 0.00%
  • 55 0.00%
  • 56 0.00%
  • 57 0.00%
  • 58 0.00%
  • 59 0.00%
  • 60 0.00%
  • 61 0.00%
  • 62 0.00%
  • 63 0.00%
1d10+15 @ AC15 +4 attacks 2 bonus 1d4+15 @ AC15 +4
min 0 max 93 mean 29.93 1197/40
  • 0 12.50%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.00%
  • 8 0.00%
  • 9 0.00%
  • 10 0.00%
  • 11 0.00%
  • 12 0.00%
  • 13 0.00%
  • 14 0.00%
  • 15 0.00%
  • 16 5.06%
  • 17 5.17%
  • 18 5.27%
  • 19 5.37%
  • 20 2.66%
  • 21 2.61%
  • 22 2.56%
  • 23 2.50%
  • 24 2.45%
  • 25 2.48%
  • 26 0.25%
  • 27 0.22%
  • 28 0.20%
  • 29 0.18%
  • 30 0.15%
  • 31 0.13%
  • 32 0.71%
  • 33 1.31%
  • 34 1.94%
  • 35 2.59%
  • 36 2.75%
  • 37 2.93%
  • 38 3.10%
  • 39 3.25%
  • 40 3.40%
  • 41 3.55%
  • 42 2.99%
  • 43 2.40%
  • 44 1.78%
  • 45 1.13%
  • 46 0.96%
  • 47 0.79%
  • 48 0.66%
  • 49 0.55%
  • 50 0.49%
  • 51 0.44%
  • 52 0.50%
  • 53 0.56%
  • 54 0.64%
  • 55 0.73%
  • 56 0.83%
  • 57 0.93%
  • 58 1.00%
  • 59 1.02%
  • 60 0.99%
  • 61 0.92%
  • 62 0.84%
  • 63 0.75%
  • 64 0.65%
  • 65 0.55%
  • 66 0.44%
  • 67 0.33%
  • 68 0.24%
  • 69 0.17%
  • 70 0.12%
  • 71 0.09%
  • 72 0.07%
  • 73 0.05%
  • 74 0.04%
  • 75 0.03%
  • 76 0.02%
  • 77 0.01%
  • 78 0.01%
  • 79 0.00%
  • 80 0.00%
  • 81 0.00%
  • 82 0.00%
  • 83 0.00%
  • 84 0.00%
  • 85 0.00%
  • 86 0.00%
  • 87 0.00%
  • 88 0.00%
  • 89 0.00%
  • 90 0.00%
  • 91 0.00%
  • 92 0.00%
  • 93 0.00%

Mutually-exclusive bonus actions (attacks N bonus X oncrit Y)

RAW you have a single bonus action per turn. Two feats that both grant a bonus-action attack — PAM (always available) and GWM (on a crit) — are mutually exclusive in practice: the optimal play uses the GWM bonus when at least one main attack crits (bigger weapon damage), and the PAM haft otherwise.

Stacking bonus and oncrit on the same attacks N chain encodes exactly this. The two postfixes can appear in either order; the engine builds the same mixture distribution either way:

1d10+15 @ AC15 +4 attacks 2 bonus 1d4+15 @ AC15 +4 oncrit 1d10+15 @ AC15 +4

Closed-form mean is straightforward by linearity:

E[total] = N · E[main] + P(no crit) · E[PAM] + P(≥1 crit) · E[GWM]

where P(no crit) = (1 − p_crit)N. The result sits strictly between the PAM-only number (lower bound; no crit advantage taken) and the both-bonuses-fire upper bound (which would over-count the bonus-action slot).

Stacking sneak with bonus on the same chain (Rogue / PAM, Rogue / TWF — heterogeneous-chain Sneak) is supported. The Sneak Attack rider attaches to the first hit-or-crit anywhere in the (main_1, …, main_N, bonus) sequence, doubled on crit per RAW. sneak with oncrit on the same chain is mutually exclusive — the parser rejects it with an explicit error rather than silently producing the wrong distribution.

Rogue/PAM Glaive at level 5 (1d10+5 main + 1d4+5 haft + 3d6 Sneak), two main attacks vs AC 15 with +9 to hit:

1d10+5 @ AC15 +9 attacks 2 sneak 3d6 bonus 1d4+5 @ AC15 +9
min 0 max 99 mean 33.08 1323/40
  • 0 1.56%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.00%
  • 8 0.00%
  • 9 0.01%
  • 10 0.04%
  • 11 0.09%
  • 12 0.18%
  • 13 0.31%
  • 14 0.49%
  • 15 0.69%
  • 16 0.90%
  • 17 1.10%
  • 18 1.30%
  • 19 1.47%
  • 20 1.65%
  • 21 1.83%
  • 22 2.04%
  • 23 2.29%
  • 24 2.56%
  • 25 2.84%
  • 26 3.12%
  • 27 3.39%
  • 28 3.62%
  • 29 3.80%
  • 30 3.93%
  • 31 4.01%
  • 32 4.04%
  • 33 4.03%
  • 34 3.99%
  • 35 3.93%
  • 36 3.85%
  • 37 3.76%
  • 38 3.65%
  • 39 3.53%
  • 40 3.36%
  • 41 3.16%
  • 42 2.92%
  • 43 2.63%
  • 44 2.33%
  • 45 2.01%
  • 46 1.70%
  • 47 1.40%
  • 48 1.14%
  • 49 0.91%
  • 50 0.72%
  • 51 0.58%
  • 52 0.46%
  • 53 0.38%
  • 54 0.32%
  • 55 0.28%
  • 56 0.25%
  • 57 0.22%
  • 58 0.20%
  • 59 0.17%
  • 60 0.15%
  • 61 0.13%
  • 62 0.11%
  • 63 0.10%
  • 64 0.08%
  • 65 0.07%
  • 66 0.05%
  • 67 0.04%
  • 68 0.03%
  • 69 0.02%
  • 70 0.02%
  • 71 0.01%
  • 72 0.01%
  • 73 0.01%
  • 74 0.00%
  • 75 0.00%
  • 76 0.00%
  • 77 0.00%
  • 78 0.00%
  • 79 0.00%
  • 80 0.00%
  • 81 0.00%
  • 82 0.00%
  • 83 0.00%
  • 84 0.00%
  • 85 0.00%
  • 86 0.00%
  • 87 0.00%
  • 88 0.00%
  • 89 0.00%
  • 90 0.00%
  • 91 0.00%
  • 92 0.00%
  • 93 0.00%
  • 94 0.00%
  • 95 0.00%
  • 96 0.00%
  • 97 0.00%
  • 98 0.00%
  • 99 0.00%
1d10+15 @ AC15 +4 attacks 2 bonus 1d4+15 @ AC15 +4 oncrit 1d10+15 @ AC15 +4
min 0 max 105 mean 30.09 240687/8000
  • 0 12.50%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.00%
  • 8 0.00%
  • 9 0.00%
  • 10 0.00%
  • 11 0.00%
  • 12 0.00%
  • 13 0.00%
  • 14 0.00%
  • 15 0.00%
  • 16 5.06%
  • 17 5.17%
  • 18 5.27%
  • 19 5.37%
  • 20 2.66%
  • 21 2.61%
  • 22 2.56%
  • 23 2.50%
  • 24 2.45%
  • 25 2.48%
  • 26 0.25%
  • 27 0.22%
  • 28 0.20%
  • 29 0.18%
  • 30 0.15%
  • 31 0.13%
  • 32 0.71%
  • 33 1.31%
  • 34 1.93%
  • 35 2.57%
  • 36 2.72%
  • 37 2.88%
  • 38 3.04%
  • 39 3.19%
  • 40 3.33%
  • 41 3.47%
  • 42 2.91%
  • 43 2.33%
  • 44 1.72%
  • 45 1.09%
  • 46 0.94%
  • 47 0.80%
  • 48 0.69%
  • 49 0.60%
  • 50 0.55%
  • 51 0.51%
  • 52 0.56%
  • 53 0.62%
  • 54 0.69%
  • 55 0.77%
  • 56 0.85%
  • 57 0.93%
  • 58 0.98%
  • 59 0.99%
  • 60 0.95%
  • 61 0.87%
  • 62 0.79%
  • 63 0.70%
  • 64 0.61%
  • 65 0.52%
  • 66 0.43%
  • 67 0.33%
  • 68 0.25%
  • 69 0.19%
  • 70 0.15%
  • 71 0.14%
  • 72 0.12%
  • 73 0.11%
  • 74 0.09%
  • 75 0.08%
  • 76 0.06%
  • 77 0.05%
  • 78 0.04%
  • 79 0.03%
  • 80 0.02%
  • 81 0.02%
  • 82 0.01%
  • 83 0.01%
  • 84 0.01%
  • 85 0.00%
  • 86 0.00%
  • 87 0.00%
  • 88 0.00%
  • 89 0.00%
  • 90 0.00%
  • 91 0.00%
  • 92 0.00%
  • 93 0.00%
  • 94 0.00%
  • 95 0.00%
  • 96 0.00%
  • 97 0.00%
  • 98 0.00%
  • 99 0.00%
  • 100 0.00%
  • 101 0.00%
  • 102 0.00%
  • 103 0.00%
  • 104 0.00%
  • 105 0.00%
1d10+15 @ AC15 +4 c19 attacks 2 bonus 1d4+15 @ AC15 +4 c19 oncrit 1d10+15 @ AC15 +4 c19
min 0 max 105 mean 30.94 15471/500
  • 0 12.50%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 0.00%
  • 7 0.00%
  • 8 0.00%
  • 9 0.00%
  • 10 0.00%
  • 11 0.00%
  • 12 0.00%
  • 13 0.00%
  • 14 0.00%
  • 15 0.00%
  • 16 4.50%
  • 17 4.71%
  • 18 4.91%
  • 19 5.12%
  • 20 2.83%
  • 21 2.72%
  • 22 2.61%
  • 23 2.51%
  • 24 2.40%
  • 25 2.45%
  • 26 0.50%
  • 27 0.45%
  • 28 0.40%
  • 29 0.35%
  • 30 0.30%
  • 31 0.25%
  • 32 0.68%
  • 33 1.14%
  • 34 1.64%
  • 35 2.17%
  • 36 2.33%
  • 37 2.53%
  • 38 2.71%
  • 39 2.87%
  • 40 3.02%
  • 41 3.18%
  • 42 2.78%
  • 43 2.35%
  • 44 1.88%
  • 45 1.37%
  • 46 1.21%
  • 47 1.07%
  • 48 0.95%
  • 49 0.85%
  • 50 0.78%
  • 51 0.71%
  • 52 0.71%
  • 53 0.72%
  • 54 0.74%
  • 55 0.77%
  • 56 0.80%
  • 57 0.85%
  • 58 0.87%
  • 59 0.88%
  • 60 0.85%
  • 61 0.80%
  • 62 0.75%
  • 63 0.70%
  • 64 0.64%
  • 65 0.57%
  • 66 0.50%
  • 67 0.43%
  • 68 0.37%
  • 69 0.32%
  • 70 0.28%
  • 71 0.26%
  • 72 0.23%
  • 73 0.21%
  • 74 0.19%
  • 75 0.16%
  • 76 0.14%
  • 77 0.12%
  • 78 0.10%
  • 79 0.08%
  • 80 0.06%
  • 81 0.05%
  • 82 0.04%
  • 83 0.03%
  • 84 0.02%
  • 85 0.02%
  • 86 0.01%
  • 87 0.01%
  • 88 0.01%
  • 89 0.00%
  • 90 0.00%
  • 91 0.00%
  • 92 0.00%
  • 93 0.00%
  • 94 0.00%
  • 95 0.00%
  • 96 0.00%
  • 97 0.00%
  • 98 0.00%
  • 99 0.00%
  • 100 0.00%
  • 101 0.00%
  • 102 0.00%
  • 103 0.00%
  • 104 0.00%
  • 105 0.00%

Defender Shield reaction (shield)

The shield postfix on an attack expression models the 5e wizard / sorcerer Shield reaction: the defender, after seeing the d20 roll, casts the 1st-level Shield spell and gains +5 AC against this attack. The d20 faces in the band [ac − to-hit, ac − to-hit + 4] flip from hits to misses; everything else is unchanged. A natural 20 still hits and crits — RAW: nat 20 always hits regardless of AC, so Shield doesn't stop a crit.

Single-attack model. The per-round Shield interaction (Shield lasts a turn, so subsequent attacks in the same round face +5 AC for free) isn't part of the surface grammar — every attack with the shield postfix is modelled as one independent Shield reaction against that attack alone.

1d8+5 @ AC15 +9
min 0 max 21 mean 7.35 147/20
  • 0 25.00%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 8.75%
  • 7 8.83%
  • 8 8.91%
  • 9 8.98%
  • 10 9.06%
  • 11 9.14%
  • 12 9.22%
  • 13 9.30%
  • 14 0.63%
  • 15 0.55%
  • 16 0.47%
  • 17 0.39%
  • 18 0.31%
  • 19 0.23%
  • 20 0.16%
  • 21 0.08%
1d8+5 @ AC15 +9 shield
min 0 max 21 mean 4.97 199/40
  • 0 50.00%
  • 1 0.00%
  • 2 0.00%
  • 3 0.00%
  • 4 0.00%
  • 5 0.00%
  • 6 5.63%
  • 7 5.70%
  • 8 5.78%
  • 9 5.86%
  • 10 5.94%
  • 11 6.02%
  • 12 6.09%
  • 13 6.17%
  • 14 0.63%
  • 15 0.55%
  • 16 0.47%
  • 17 0.39%
  • 18 0.31%
  • 19 0.23%
  • 20 0.16%
  • 21 0.08%

Same Longbow attack vs AC 15 with +9 to-hit. Without Shield (left), per-attempt mean is 147/20 = 7.35. With Shield (right) the effective AC becomes 20: faces 6-10 flip from hits to misses, which is 5 of 20 faces × the ~9.5 mean per hit, so the per-attempt mean drops by ~2.375 to ~4.975. The crit branch (1/20 × 14) is identical in both panels.

Flat damage reduction (dr<n>)

The dr<n> postfix on an attack expression models flat damage reduction on the defender — Heavy Armor Master's DR 3 vs non-magical bludgeoning / piercing / slashing, magic-item DR, and similar mechanics. Subtracted from the rolled per-hit base damage and clamped to zero — a small roll reduced below zero just deals 0, not negative.

Applied to base damage only; rider damage is not reduced. Riders are typically a different damage type (Smite radiant, Hex necrotic, Hunter's Mark force) and type-specific resistance via the Typed pipeline is the right tool for those cases. On crit the rule still holds: DR applies once to the doubled-dice base damage total (RAW: HAM reduces 3 from any qualifying damage instance, including crits — only one application per damage instance).

Worked example: 1d8+5 @ AC15 +9 dr3 on a Longbow vs AC 15 with +9 to-hit. Without DR, per-attempt mean is 147/20 = 7.35. With DR 3, every per-hit base damage gets 3 shaved off (clamped at 0); per-attempt mean drops to ~5.6. Hit and crit branch probabilities are unchanged — DR is a damage modifier, not an attack-roll modifier. Try it at /strike/1d8+5 @ AC15 +9 dr3.

Combine with shield for a defender wearing heavy armor + casting Shield, with elven for attacker advantage variants, with rider for Smite-on-Heavy-Armor-Master matchups (note the rider damage bypasses DR per the rule above).

Per-type DR (dr<n>:<type>)

The flat dr<n> applies to total per-hit base damage. The typed form dr<n>:<type> reduces only the named damage type's contribution to the hit. RAW Heavy Armor Master is *"DR 3 vs non-magical bludgeoning / piercing / slashing"* — explicitly typed — so this is the right tool for HAM-vs-flaming-sword matchups where the slashing portion gets reduced and the fire portion passes through.

Multiple dr<n>:<type> clauses stack (one per type). Untyped dr<n> and typed clauses can coexist on the same attack — typed buckets are reduced first (per type, clamped at 0), then the resulting total is clamped by any flat dr. Try 1d8:slashing+1d6:fire @ AC15 +9 dr3:slashing — Longbow + flaming arrowhead vs HAM target.

Caveat: only explicitly-tagged components are reduced. In 1d8:slashing+5 the +5 is untyped, so dr3:slashing reduces only the d8 portion. To have HAM-shaped DR cover the modifier too, type it explicitly with [1d8+5]:slashing or 1d8:slashing+5:slashing.

Brutal Critical / Savage Attacks (brutal<n>)

The brutal<n> postfix on an attack expression adds N copies of the weapon's largest damage die to the crit damage (on top of the existing crit-doubled dice). Models 5e Half-Orc Savage Attacks (always +1 die on melee crit) and Barbarian Brutal Critical (+1 at L9, +2 at L13, +3 at L17). Hits are unaffected — brutal only fires on crit.

The "weapon die" is the largest die in the damage subtree: d10 for a Glaive (1d10+5), d12 for a Greataxe (1d12+5), d6 for a Greatsword (2d6+5), d8 for a Longsword (1d8+5). Heterogeneous-die damage expressions take the largest die size present.

Applied to base damage only — rider damage (Smite radiant, Hex necrotic, Hunter's Mark force) does not get extra brutal dice. The flat dr still clamps the post-brutal total normally; per-type dr<n>:<type> treats brutal dice as untyped (documented v0.1 limitation — use flat dr for HAM-vs-brutal-Greatsword modeling).

Worked example: 1d12+5 @ AC15 +9 brutal1 for a Half-Orc Greataxe Fighter. Without Brutal, crit damage = 2d12+5. With brutal1, crit damage = 3d12+5. The mean shift is P(crit) × E[1d12] = 0.05 × 6.5 = 0.325 DPR. Stack with adv (Reckless Attack barbarian) and that contribution doubles via the doubled crit chance.

Combination rules

  • One modifier per die term. 1d6!r1 is rejected — pick exploding or reroll.
  • Modifiers attach to the dice term, not to the sum. 2d6!+5 means "exploding 2d6, then add 5", not "explode the whole sum".
  • No multiplication, no parentheses. The grammar is intentionally additive-only. 3 × 1d6 is just 3d6 (which has the same distribution as one die's worth tripled in count, by linearity).
  • Case-insensitive operators. 2D20KH1 works the same as 2d20kh1.
  • Whitespace is ignored between tokens. 2d6 + 1d4 - 2 and 2d6+1d4-2 are equivalent.

What's not supported

  • Multiplication (3 × 1d6). Use 3d6 instead — the engine has no multiplication operator.
  • Comparison / threshold operators (, =, …). The kill-probability question is asked via the URL (/kill/<expr>/<hp>) or the per-page HP slider, not via expression syntax.
  • Save-roll attack chains (Cleric Sacred Flame: save DEX with no damage on fail). The save layer ships the half / zero modes; rarer "negative save" effects (deal damage iff save succeeds) aren't supported.
  • Fully heterogeneous main chains where every attack has a different damage profile. The bonus <attack> postfix lets you attach an offhand-different-die attack (PAM glaive haft, CBE bonus shot, TWF offhand) to a homogeneous main chain, and sneak composes with bonus across the (main_1, …, main_N, bonus) sequence — the Rogue/PAM and Rogue/TWF cases. What doesn't work is a chain where the main attacks themselves are non-homogeneous (e.g. greatsword first attack + shortsword second attack), which is rare enough in 5e that no canonical build needs it. sneak + oncrit on the same chain (Rogue multiclassing into Champion + GWM) is also rejected with an explicit error.
  • Per-target state machines beyond cumulative damage. The engine models per-attempt and per-round distributions exactly, and the Markov rounds-to-kill layer extends that to "how many rounds until the boss drops" with optional per-round healing or regeneration (gambler's ruin). What isn't modelled: per-target state machines that aren't cumulative-damage — concentration check chains, save-or- suck conditions propagating across turns, mid-fight HP-threshold transitions that change the strike profile.
  • Reactions (Sentinel, Riposte, opportunity attacks). The bonus-action slot is modeled per-turn; reactions need a separate per-turn slot with their own trigger semantics — compose by adding the per-reaction expected damage on top of the per-round chain output for whatever reaction rate your encounter generates.

URL slug encoding

Pages under /strike/<slug> and /vs/<a>/<b> use a tiny URL-safe substitution so links don't need percent-encoding:

  • +p
  • -m
  • :. (typed-damage tags)
  • @~ (attack-roll postfix)
  • *x (multi-attack postfix)
  • whitespace stripped on encode

So 2d6+5 becomes /strike/2d6'5; 1d8+5 @ AC15 +9 becomes /strike/1d8'5~AC15'9. Modifiers that don't contain special characters (like !, r1, kh1, adv, c19) pass through unchanged. The substituted characters (p m . ~) are all RFC 3986 unreserved — no percent-encoding ever needed.

Error messages

The parser surfaces specific errors rather than a generic "syntax error". Common ones:

  • unexpected end of input — truncated expression.
  • unexpected character: 'x' — couldn't parse past x.
  • dice count must be at least 10d6.
  • dice must have at least 1 side1d0.
  • a 1-sided die cannot explode1d1!.
  • a die can carry at most one modifier (! or r<N>)1d6!r1.
  • kh0 / kl0 is meaningless — keep at least one die4d6kh0.
  • 4d20kh<n> with kept > 1 enumerates 160000 outcomes … — when the brute-enumeration cost (sides^count) exceeds the 200K cap, e.g. 5d20kh4.

Try it yourself

The same Rust core powers every surface — the website, the Android app, the WebAssembly browser bundle, and every licensed binding (Rust, C / C++ via FFI, Elixir via NIF, Android via JNI). Every surface accepts the same expressions and produces the same exact rationals.