Skip to content

feat(rules): Rifts rules engine — attributes, dice, LLW O.C.C., combat, skills#2

Merged
StreamDemon merged 6 commits into
mainfrom
feat/rules-engine-llw-slice
Jul 1, 2026
Merged

feat(rules): Rifts rules engine — attributes, dice, LLW O.C.C., combat, skills#2
StreamDemon merged 6 commits into
mainfrom
feat/rules-engine-llw-slice

Conversation

@StreamDemon

@StreamDemon StreamDemon commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

First vertical slice of the RiftForge rules layer — a smart character builder + live sheet for the Rifts TTRPG (Rifts Ultimate Edition). Establishes the decoupled rules architecture and drives the Ley Line Walker O.C.C. end-to-end.

Architecture (packages/rules)

  • src/content/ — rules as page-stamped JSON, transcribed from the scanned rulebook via vision extraction
  • src/schema/ — Zod schemas that validate the content at load (a mis-transcribed cell fails fast)
  • src/engine/ — pure, testable TypeScript deriving every number (no Convex, no UI)

What's included

  • Attributes (p.281) — Attribute Bonus Chart → derived strike/parry/dodge/save bonuses
  • Dice — notation parser/roller (3D6*10+20), min/max/average
  • Ley Line Walker O.C.C. (pp.113–116) — P.P.E. (3D6×10+20 + P.E.), level-gated bonuses, abilities, skill grants, money
  • Combat/HP (pp.287, 346–347) — Hit Points, S.D.C., attacks-per-melee, Hand-to-Hand tables, saving-throw targets; combatProfile()
  • Skills (pp.299, 304–330) — resolveSkill(): base% + O.C.C./I.Q./per-level bonuses, 98% cap; the LLW's full skill list resolves

Verification

  • vp run rules#test44 tests pass
  • vp run rules#check → format + lint + typecheck clean

Notes

  • The 59 MB source PDF (© Palladium Books) is git-ignored; docs/rules/PAGE_MAP.md indexes it.
  • Follow-ups: magic subsystem + spells; Hand-to-Hand Expert/MA/Assassin; Convex backend wiring.

StreamDemon and others added 2 commits July 1, 2026 23:22
Baseline created via `vp create vite:monorepo` (pnpm workspace + root
Vite+ config). Demo apps/packages removed; the rules package lands next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ur5Eu6dC17feVQH5smrFw
…t, skills

First vertical slice of the RiftForge rules layer, transcribed from Rifts
Ultimate Edition (scanned PDF -> vision extraction). Decoupled content
(page-stamped JSON) / schema (Zod) / engine (pure TS).

- Attribute Bonus Chart (p.281) -> derived combat/save bonuses
- Dice notation parser/roller (3D6*10+20 etc.)
- Ley Line Walker O.C.C. (pp.113-116): P.P.E., bonuses, abilities, skills, money
- Combat/HP: Hit Points, S.D.C., attacks/melee, Hand-to-Hand tables, saving throws
- Skill system: base% + O.C.C./I.Q./per-level, 98% cap; LLW skill list resolves

44 tests pass; `vp check` (format + lint + typecheck) clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ur5Eu6dC17feVQH5smrFw
@StreamDemon

Copy link
Copy Markdown
Owner Author

@cubic-dev-ai Please review this PR.

@cubic-dev-ai

cubic-dev-ai Bot commented Jul 1, 2026

Copy link
Copy Markdown

@cubic-dev-ai Please review this PR.

@StreamDemon I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

22 issues found across 33 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread pnpm-workspace.yaml Outdated
Comment thread packages/rules/src/schema/skills.ts Outdated
Comment thread packages/rules/src/schema/combat.ts
Comment thread packages/rules/src/schema/combat.ts Outdated
Comment thread packages/rules/src/schema/combat.ts Outdated
Comment thread README.md
Comment thread packages/rules/src/content/skills/skills.json
Comment thread packages/rules/src/engine/combat.ts Outdated
Comment thread packages/rules/src/content/occ/ley-line-walker.json Outdated
Comment thread packages/rules/src/content/occ/ley-line-walker.json Outdated
StreamDemon and others added 2 commits July 1, 2026 23:59
Resolves all 22 findings from the Cubic review on PR #2.

Validation hardening (reject bad transcriptions at load):
- skills: baseSkill/baseSkill2/perLevel >= 0, maxPercent > 0
- combat: H2H level > 0; attack/action counts >= 0; type id/name non-empty;
  saveTarget must have exactly one of target/targetRange
- occ: P.P.E. recovery & supplemental values >= 0
- shared diceFormulaSchema — dice-string fields now validated at load, not at parse

Correctness / consistency:
- combat: hitPointsRange() honors perLevelStartsAt (was hardcoded to level 2)
- combat: unknown Hand-to-Hand id now throws instead of silently returning 1 attack
- LLW grants carry skillId/hthId + skillPrefix so they resolve by id, not fragile
  name matching; "Communications" category normalized to "Communication"

Housekeeping:
- remove broken root `dev` script (no website package)
- README describes RiftForge, not the generic Vite+ starter
- catalog @types/node ^24 -> ^22 to match engines >=22.18.0
- test the previously-unasserted poison save bonus

45 tests pass; `vp check` clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ur5Eu6dC17feVQH5smrFw
These were removed on main; a line-ending re-normalization accidentally
re-touched them here, causing a modify/delete conflict. Remove them so the
branch agrees with main.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ur5Eu6dC17feVQH5smrFw
@StreamDemon

Copy link
Copy Markdown
Owner Author

Addressed all 22 Cubic findings ✅ (commit 868e805)

Validated each — all were legitimate. Grouped fixes:

Schema validation hardening (reject bad transcriptions at load, not at parse):

  • skills: baseSkill/baseSkill2/perLevel ≥ 0, maxPercent > 0
  • combat: H2H level > 0, action-count fields ≥ 0, type id/name non-empty; saveTarget must have exactly one of target/targetRange
  • occ: P.P.E. recovery* and supplemental* ≥ 0
  • New shared diceFormulaSchema — all dice-string fields now validated (a malformed "3D6x" fails at load)

Correctness / consistency:

  • hitPointsRange() now honors perLevelStartsAt (was hardcoded to level 2) — matches rollHitPoints()
  • Unknown Hand-to-Hand id now throws instead of silently returning 1 attack
  • LLW grants carry skillId/hthId + skillPrefix so they resolve by id, not fragile name matching; "Communications""Communication"

Housekeeping:

  • removed broken root dev script (no website package)
  • README now describes RiftForge, not the Vite+ starter
  • catalog @types/node ^24^22 to match engines >=22.18.0
  • added the missing saveBonuses.poison assertion

45 tests pass; vp check (format + lint + typecheck) clean.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 13 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/rules/src/schema/combat.ts
…e aliases

- combat: saveTargetSchema now rejects an inverted targetRange (min > max)
- skills: add `aliases` to the catalog + `getSkillByName()` name resolver, so
  O.C.C. grants that use a book's alternate wording (e.g. "Lore: Demon & Monster",
  "Math: Basic") resolve to the catalog by name as well as by id.

48 tests pass; `vp check` clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ur5Eu6dC17feVQH5smrFw

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 6 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/rules/src/engine/skills.ts Outdated
Cubic flagged that the name index silently overwrote colliding normalized
keys, which could drop a skill from name-resolution unnoticed. Extract
buildSkillIndexes(): it throws on a duplicate id or on a name/alias that
normalizes to a key already owned by a different skill, instead of shadowing
it. Tests cover both collision cases and confirm the real catalog is clean.

51 tests pass; `vp check` clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ur5Eu6dC17feVQH5smrFw
@StreamDemon StreamDemon merged commit 8964e91 into main Jul 1, 2026
1 check passed
@StreamDemon StreamDemon deleted the feat/rules-engine-llw-slice branch July 1, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant