Skip to content

feat(rules): magic subsystem — spells, spell strength, LLW spell selection#4

Merged
StreamDemon merged 2 commits into
mainfrom
feat/magic-spells
Jul 1, 2026
Merged

feat(rules): magic subsystem — spells, spell strength, LLW spell selection#4
StreamDemon merged 2 commits into
mainfrom
feat/magic-spells

Conversation

@StreamDemon

@StreamDemon StreamDemon commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Adds the magic layer — the defining Ley Line Walker capability, and the last major LLW-specific subsystem.

What's included

  • schema/spells.ts + content/spells/spells.json29 spells across levels 1–4, transcribed from RUE Magic Spells (Range / Duration / Saving Throw / P.P.E. / effect), each page-stamped. Covers the iconic ones: Armor of Ithan (10 M.D.C./level), Energy Bolt (4D6, dodge 18+), Globe of Daylight, See the Invisible, Charismatic Aura, …
  • engine/spells.ts:
    • validated spell book with id + name indexes (collision-checked, same fail-fast pattern as skills)
    • spellsByLevel, canCast (P.P.E. affordability), getSpell/getSpellByName
    • Spell Strength (RUE p.187) — base 12, +1 at each O.C.C. increment level; the d20 a victim must beat to save vs the caster's magic
    • occSpellStrength() derives it from the LLW's own spellStrength bonus: 12 at L1 → 13/14/15/16 at L3/7/10/13
    • initialSpellChoices() realizes the LLW's "3 spells from each of levels 1–4" against the real spell list

Verification

  • vp run rules#test59 tests pass (8 new spell tests)
  • vp run rules#check → format + lint + typecheck clean

With this, the Ley Line Walker vertical slice is essentially complete end-to-end (attributes → O.C.C. → P.P.E. → combat/HP → skills → spells). Next up: the Convex backend to seed + serve the validated content and persist built characters.


Summary by cubic

Adds the magic subsystem for Ley Line Walkers: a validated spell book (29 spells, levels 1–4), Spell Strength, and initial spell selection (3 per level). Also fixes how flat O.C.C. Spell Strength bonuses are applied.

  • New Features

    • Content: 29 spells (levels 1–4) with Range/Duration/Saving Throw/P.P.E./page in content/spells/spells.json.
    • Schema: schema/spells.ts Zod types for spells/book, plus spellStrengthBase (12) and ritualSaveTarget (16).
    • Engine: engine/spells.ts with id/name indexes, getSpell/getSpellByName, spellsByLevel, canCast, Spell Strength via occSpellStrength (+1 at LLW 3/7/10/13), saveTargetVsSpell, and initialSpellChoices for "3 from each level 1–4".
    • Exports: index.ts exposes the schema and engine.
    • Tests: coverage for lookups, grouping, P.P.E. checks, Spell Strength, and LLW selection.
  • Bug Fixes

    • Correctly apply flat (non-level-gated) spellStrength bonuses using spellStrengthFromBonus; level-gated bonuses still increment per listed levels.

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

Review in cubic

…ction

Adds the magic layer that makes the Ley Line Walker a real caster.

- schema/spells.ts + content/spells/spells.json — 29 spells across levels 1-4,
  transcribed from RUE Magic Spells (Range/Duration/Saving Throw/P.P.E./effect),
  each page-stamped. Includes Armor of Ithan, Energy Bolt, Globe of Daylight, etc.
- engine/spells.ts — validated spell book with id/name indexes (collision-checked),
  spellsByLevel, canCast (P.P.E. affordability), and Spell Strength (RUE p.187:
  base 12, +1 at each O.C.C. increment level; the d20 a victim must beat to save).
- Integrates with the LLW: occSpellStrength() reads its spellStrength bonus
  (12 at L1 -> 16 by L13), and initialSpellChoices() realizes "3 spells from each
  of levels 1-4" against the actual spell list.

59 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 5 files

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

Re-trigger cubic

Comment thread packages/rules/src/engine/spells.ts Outdated
Cubic flagged that occSpellStrength ignored a spellStrength bonus that has a
`value` but no `atLevels` (base + 0*value). Extract spellStrengthFromBonus():
level-gated bonuses increment per level reached; a flat bonus (no atLevels) is
applied once at every level. Tests cover flat, level-gated, and no-bonus cases.

61 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 2 files (changes from recent commits).

Auto-approved: Adds new magic subsystem: spells schema/content (29 spells), spell strength calculus, and Ley Line Walker initial selection. Low-risk additive change with tests.

Re-trigger cubic

@StreamDemon StreamDemon merged commit b73b37e into main Jul 1, 2026
2 checks passed
@StreamDemon StreamDemon deleted the feat/magic-spells branch July 1, 2026 17:43
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