Skip to content

feat(rules): character-sheet assembly — deriveSheet()#5

Merged
StreamDemon merged 2 commits into
mainfrom
feat/character-sheet
Jul 1, 2026
Merged

feat(rules): character-sheet assembly — deriveSheet()#5
StreamDemon merged 2 commits into
mainfrom
feat/character-sheet

Conversation

@StreamDemon

@StreamDemon StreamDemon commented Jul 1, 2026

Copy link
Copy Markdown
Owner

The pure character-assembly that turns a player's choices into a complete computed sheet — the culmination of the rules engine, and the function the Convex backend will serve.

What's included

  • schema/character.tsCharacter: the player's choices (O.C.C. id, level, 8 attributes, H2H type, skill picks + their bonuses, spell picks, optional recorded rolled H.P./S.D.C./P.P.E.). Derived stats are computed, never stored.
  • engine/character.tsderiveSheet(character): validates the character, then assembles:
    • identity (O.C.C. name/category) + attribute bonuses
    • combat profile: attacks/melee, strike, parry, dodge, damage bonus
    • vitals: H.P. & S.D.C. ranges (or the recorded roll) + coma/death floor
    • P.P.E. range + spell strength
    • a saves map combining attribute and O.C.C. bonuses with their d20 targets
    • resolved skill percentages and known spells

Pure and deterministic — dice rolls are inputs (character.rolled), not generated — so it runs anywhere.

Verification

  • vp run rules#test70 tests (9 new), asserting a full level-1 Ley Line Walker sheet (attacks 4, P.P.E. 64–214, spell strength 12, Wilderness Survival 44%, +4 vs Horror Factor, …)
  • vp run rules#check → clean

Next

This is the sheet the Convex backend will persist + serve. Convex setup needs an interactive npx convex dev login, so that lands in a follow-up once the deployment is provisioned.


Summary by cubic

Adds deriveSheet to compute a complete character sheet from a player's choices. Now level-aware P.P.E., psionics saves honor the character’s psychic class, and duplicate skills/spells are rejected.

  • New Features

    • Added engine/character.ts: deriveSheet(character) validates input and returns identity, attribute bonuses, combat profile, vitals, P.P.E./spell strength, saves, resolved skills, and known spells.
    • Added schema/character.ts: Character schema for choices (O.C.C., level, attributes, H2H, skills with bonuses, spellIds, optional rolled H.P./S.D.C./P.P.E., psychicClass with default "ordinary").
    • Exported new schema and engine from index.ts; tests assert a level‑1 Ley Line Walker sheet.
  • Bug Fixes

    • P.P.E. now uses a level-aware range (base plus per-level gains).
    • Psionics save target is derived from the character’s psychicClass.
    • Schema rejects duplicate skillId and spellId entries.

Written for commit efe3af0. Summary will update on new commits.

Review in cubic

The pure function that turns a character's choices into a complete computed
sheet, tying every subsystem together. Lives in the engine (no Convex/UI dep)
so it runs in tests, the backend, or the client.

- schema/character.ts — Character: the player's choices (occId, level, 8
  attributes, hthType, skill picks + bonuses, spell picks, optional rolled H.P./
  S.D.C./P.P.E.). Derived stats are computed, never stored.
- engine/character.ts — deriveSheet(character): validates, then returns identity,
  attribute bonuses, combat profile (attacks/strike/parry/dodge/damage), vitals
  (H.P./S.D.C. ranges + coma/death floor), P.P.E. range, spell strength, a saves
  map (attribute + O.C.C. bonuses, with targets), resolved skill %s, and known spells.

Tested end-to-end against a level-1 Ley Line Walker. 70 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.

4 issues found across 4 files

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

Re-trigger cubic

Comment thread packages/rules/src/engine/character.ts Outdated
Comment thread packages/rules/src/engine/character.ts Outdated
Comment thread packages/rules/src/schema/character.ts Outdated
Comment thread packages/rules/src/schema/character.ts Outdated
… skills/spells

- P.P.E.: add ppeRange(occ, pe, level) that includes per-level growth (was
  showing level-1 base for all levels); basePpeRange delegates to it. deriveSheet
  now uses the character's level.
- Psionics save target: carry `psychicClass` on the character (default "ordinary")
  and pass it to psionicsSaveTarget, instead of hardcoding "ordinary".
- Reject duplicate skillIds and spellIds via schema .refine() (can't take a skill
  or know a spell twice).
- deriveSheet accepts CharacterInput (z.input) so defaulted fields may be omitted.

73 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.

0 issues found across 4 files (changes from recent commits).

Requires human review: Core character sheet assembly function with complex derivation logic; requires domain expert review for correctness.

Re-trigger cubic

@StreamDemon StreamDemon merged commit f1ab24c into main Jul 1, 2026
2 checks passed
@StreamDemon StreamDemon deleted the feat/character-sheet branch July 1, 2026 18:15
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