Generalize Rolemaster standard dice parsing

This commit is contained in:
2026-04-03 01:33:32 +02:00
parent e5f00fa693
commit f0dd79e589
17 changed files with 121 additions and 275 deletions

View File

@@ -2,13 +2,12 @@
## Goal
Extend the app with a new `rolemaster` ruleset that supports three Rolemaster-oriented skill roll types:
Extend the app with a new `rolemaster` ruleset that supports generic standard Rolemaster expressions plus the special open-ended percentile case:
1. Initiative: `2d10 + x`
2. Standard percentile: non-open-ended `1d100 + x`
3. Open-ended percentile: `1d100 + x` with Rolemaster low-end and high-end behavior
1. Standard expressions: `NdS + x`, with an implicit dice count of `1` when no digit appears before `d`
2. Open-ended percentile: `d100! + x` with Rolemaster low-end and high-end behavior
The initial scope is only roll definition, validation, execution, logging, and UI support for these three roll types. This does not include Rolemaster attack tables, critical tables, resistance rolls, maneuver tables, or character sheet math beyond the explicit roll modifier entered for a skill.
The initial scope is only roll definition, validation, execution, logging, and UI support for generic standard Rolemaster rolls and open-ended percentile rolls. This does not include Rolemaster attack tables, critical tables, resistance rolls, maneuver tables, or character sheet math beyond the explicit roll modifier entered for a skill.
## Scope Assumptions
@@ -19,8 +18,7 @@ The initial scope is only roll definition, validation, execution, logging, and U
- If the first roll is `96` or higher, roll another high-ended `d100` recursively and add it.
- If the first roll is less than or equal to the skill's configured fumble range, roll another high-ended `d100` recursively and subtract it.
- Recursive follow-up rolls are high-ended only.
- Standard percentile rolls do not open-end and do not use a fumble range.
- Initiative rolls are simple `2d10 + x` rolls with no open-ended behavior.
- Standard Rolemaster rolls do not open-end and do not use a fumble range.
- The modifier `x` should be an integer.
- Negative modifiers are supported for Rolemaster only.
- D6 and D&D 5e keep their current non-negative modifier rules unless separately re-scoped in a future change.
@@ -35,11 +33,12 @@ The initial scope is only roll definition, validation, execution, logging, and U
- Roll breakdown text format for low-ended subtraction: `12 (03) -97 -44 +15 = -114`
- Skill groups need to support Rolemaster defaults for all of these fields, to stay consistent with current prototype behavior
- Rolemaster uses expression parsing with canonical syntax:
- initiative: `2d10+48`
- standard roll with implicit count: `d10`
- standard roll with explicit count: `15d10`
- standard percentile: `d100+4`
- open-ended percentile: `d100!+85`
- negative modifiers are valid only for Rolemaster, for example `d100-15`
- `15d10` e.g. for spells indicating "heals 1d10/lvl hit points".
- open-ended syntax is only valid for `d100!`
## Architecture Guardrails
@@ -108,12 +107,9 @@ Affected areas:
Current validation is split between generic expression parsing and D6 option validation. Rolemaster needs its own validation layer.
Validation rules to add:
- `RolemasterInitiative`
- fixed base roll `2d10`
- integer modifier required
- no fumble range
- `RolemasterPercentile`
- fixed base roll `1d100`
- `RolemasterStandard`
- supports generic `NdS` syntax with any supported side count
- assumes a dice count of `1` when the count is omitted before `d`
- integer modifier required
- no fumble range
- `RolemasterOpenEndedPercentile`
@@ -130,13 +126,14 @@ Tasks:
- Replace or extend `ValidateSkillDefinition`.
- Extend `DiceRules.ParseExpression` with a Rolemaster-focused parser/validator path.
- Add canonical Rolemaster expression parsing rules:
- `2d10+48` and `2d10-15` for initiative
- `d10`, `2d10+48`, and `15d10-15` for generic standard rolls
- `d100+4` and `d100-20` for standard percentile
- `d100!+85` and `d100!-15` for open-ended percentile
- reject open-ended syntax for non-percentile or multi-die expressions such as `2d10!+1`
- Keep Rolemaster fumble range validation separate from the expression because it is configured independently.
- Add canonical display formatting for Rolemaster skills, for example:
- `Initiative: 2d10+15`
- `Percentile: 1d100+48`
- `Rolemaster: d10`
- `Rolemaster: 15d10+15`
- `Open-ended percentile: OE 1d100+48, fumble <= 5`
- Add explicit regression tests that D6 / D&D still reject negative modifiers after Rolemaster support lands.
@@ -154,8 +151,7 @@ Add a new Rolemaster execution path alongside the existing D6 and standard roll
Recommended internal shape:
- `ComputeRoll` dispatches by ruleset and roll kind.
- Add dedicated methods:
- `ComputeRolemasterInitiativeRoll`
- `ComputeRolemasterPercentileRoll`
- `ComputeRolemasterStandardRoll`
- `ComputeRolemasterOpenEndedRoll`
- helper `RollRolemasterHighOpenEndedChain`
@@ -231,14 +227,9 @@ Tasks:
Recommended frontend model changes:
- Introduce ruleset-aware form state rather than raw D6 toggles.
- Keep "Expression" as the primary input, but provide Rolemaster-specific help text, examples, and validation when the selected campaign ruleset is `rolemaster`.
- Add a "Roll type" selector with options:
- `Initiative`
- `Percentile`
- `Open-ended percentile`
- Keep the selector and expression input synchronized so users can either choose a type or see the parsed/canonical expression clearly.
- Show fumble range input only for open-ended percentile.
- Use progressive disclosure so only the fields relevant to the chosen Rolemaster roll type are shown.
- Keep "Expression" as the primary input, and provide Rolemaster-specific help text, examples, and validation when the selected campaign ruleset is `rolemaster`.
- Show fumble range input only when the current Rolemaster expression is an open-ended percentile roll.
- Use progressive disclosure so only the fields relevant to the current Rolemaster expression are shown.
- Add inline validation on blur and submit, visible required indicators, and `aria-live` / alert semantics for validation errors.
- Preserve the existing app visual language instead of introducing a separate Rolemaster-specific theme.
@@ -287,7 +278,7 @@ Service-level tests to add:
- rejection of D6-only options on Rolemaster skills
- rejection of negative modifiers on D6 / D&D skills
- acceptance of negative modifiers on Rolemaster expressions
- initiative roll math
- generic standard Rolemaster roll math
- standard percentile roll math
- open-ended high roll with one extra roll
- open-ended high roll with recursive extra rolls
@@ -350,7 +341,7 @@ Recommended implementation order:
- Keep existing D6 / D&D behavior green.
#### Iteration 3: roll engine
- Implement initiative and standard percentile execution.
- Implement generic standard and standard percentile execution.
- Implement open-ended percentile execution with recursive high-end chaining and low-end subtraction.
- Extend die-result metadata and breakdown formatting.
- Add focused service tests for roll math and payload/detail serialization compatibility.
@@ -382,10 +373,9 @@ Recommended implementation order:
- A campaign can be created with ruleset id `rolemaster`.
- Rolemaster skill groups and skills can be created and edited through API and UI.
- Supported Rolemaster roll types are limited to:
- initiative `2d10 + x`
- standard percentile `1d100 + x`
- open-ended percentile `1d100 + x` with fumble range
- Supported Rolemaster roll types are:
- generic standard rolls `NdS + x`, with implicit dice count `1` for `dS`
- open-ended percentile `d100! + x` with fumble range
- Open-ended percentile rolls correctly:
- add recursively on first-roll `96+`
- subtract a recursive high-end chain on first-roll `<= fumble range`