# CONTENT_SCHEMA Draft formats. Change this file together with JSON Schema and any validator. Ordinary cards are data + standard effects. `customEffect` is an escape hatch. ## Identity - `id`: stable string, unique in its catalog - `name`: display name - `tags`: string array, `kebab-case` ## Cards (`content/cards/*.json`) ```json { "id": "card.example.spark", "name": "Spark", "type": "Spell", "cost": 1, "tags": ["damage"], "effects": [ { "op": "Damage", "amount": 1, "target": "ChosenEnemy" } ] } ``` `type`: `Creature` | `Spell` | `Field`. Creatures/fields may add `attack`, `health`, `countdown`, `triggers`, `activate`. ### Activate ```json "activate": [{ "op": "TransferStatsThenDie" }], "activateNeedsFriendly": true ``` `activateNeedsEnemy` for targeted enemy activates. Default: once per own turn; usable the turn the creature enters. ### Play targeting flags `playNeedsFriendly`, `playNeedsEnemy` (e.g. Vile Fire needs both). ### Tags (v1, partial) Only these are recognized by rules/content checks. Extra kebab-case tags may exist as data and are ignored by the engine. `damage`, `heal`, `creature`, `field`, `supply`, `countdown` Do not grow this list unless a rule actually reads the new tag. ### Triggers `when`: `TurnStart` | `OnDestroyed`. Effects use the same `op` list as play effects. `effects` on a card are on-play / on-cast. Do not duplicate them as `OnEnter` yet. ## Standard `op` values `Damage`, `Heal`, `Draw`, `Discard`, `Destroy`, `Summon`, `MoveCard`, `ModifyStat`, `ModifyCountdown`, `AddKeyword`, `RemoveKeyword`, `GenerateEnergy`, `AddStatus`, `RemoveStatus`. Unknown `op` is a content error unless `customEffect` names a registered C# handler. ## Characters (`content/characters/*.json`) Each character is **starting deck + skill** (see `docs/DESIGN.md`). `coreActions` / `bridge` are design metadata. ```json { "id": "char.example.ash", "name": "Ash", "coreActions": ["Damage", "Heal"], "bridge": "Damage+Heal", "skill": { "id": "skill.ash.ember", "summary": "..." }, "startingDeck": ["card.example.spark"] } ``` ## Packs (`content/packs/*.json`) In-run reward pools. `base: true` is always available this run. Other packs unlock when **all** `allOf` conditions are true. Evaluation is live against current run stats and current owned cards (not sticky, not meta). ```json { "id": "pack.example.vitality", "name": "Vitality", "base": false, "coreActions": ["Heal"], "cards": ["card.example.salve"], "allOf": [{ "kind": "HealReceivedAtLeast", "amount": 2 }] } ``` `kind`: `HealReceivedAtLeast`, `AttacksAtLeast`, `FriendlyDestroyedAtLeast`, `FatigueAtLeast`, `DeckTagAtLeast` (+ `tag`), `KillTagAtLeast` (+ `tag`). World tags such as `cult` may appear in `KillTagAtLeast` without being v1 rules tags. ## Enemies / encounters Same effect language as cards where possible. AI weights live in enemy data (`docs/AI.md`), not in the engine. ## Validation (Phase G) Unique ids, existing references, required fields, numeric ranges, tag shape, effect arguments. PT report is optional and must not block load of contextual cards.