feat(rules): Rifts rules engine — attributes, dice, LLW O.C.C., combat, skills#2
Conversation
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
|
@cubic-dev-ai Please review this PR. |
@StreamDemon I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
22 issues found across 33 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
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
Addressed all 22 Cubic findings ✅ (commit
|
There was a problem hiding this comment.
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
…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
There was a problem hiding this comment.
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
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
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 extractionsrc/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
3D6*10+20), min/max/average3D6×10+20 + P.E.), level-gated bonuses, abilities, skill grants, moneycombatProfile()resolveSkill(): base% + O.C.C./I.Q./per-level bonuses, 98% cap; the LLW's full skill list resolvesVerification
vp run rules#test→ 44 tests passvp run rules#check→ format + lint + typecheck cleanNotes
docs/rules/PAGE_MAP.mdindexes it.