# Quick start

This page loads the 5E SRD pack, computes a character's sheet, changes the character and
rolls an attack. The other guides explain each step in depth.

## Install

```sh
npm install @opencharacter/engine @opencharacter/5e-srd-5.1
```

- `@opencharacter/engine` is the TypeScript reference engine. It has no runtime dependencies
  on Node, so it runs in browsers, servers and workers. It ships as TypeScript source, so use a
  runner or bundler that compiles TypeScript (tsx, Vite, Bun, Deno).
- `@opencharacter/5e-srd-5.1` is one content pack: its rules, content and English text.

## Load, compute, change, roll

```ts
import { applyChanges, computeSheet, loadRuleset, startAction } from '@opencharacter/engine';
import type { CharacterFile } from '@opencharacter/engine';
import srd from '@opencharacter/5e-srd-5.1';
import en from '@opencharacter/5e-srd-5.1/i18n/en';

// 1. Load the packs into a ruleset. Do this once and keep the result.
const loaded = loadRuleset([srd]);
if (!loaded.ok) throw new Error(JSON.stringify(loaded.errors));
const { ruleset } = loaded;

// 2. A character file holds only base state: inputs, owned items, picks. The CharacterFile type
//    catches a misspelled or missing property before anything runs.
let character: CharacterFile = {
  specVersion: '0.1.0',
  id: 'quick-start',
  packs: [{ id: '5e-srd-5.1', version: '0.1.0' }],
  values: {
    '5e-srd-5.1:abilities.str.base': 16,
    '5e-srd-5.1:abilities.dex.base': 12,
  },
  inventory: [{ id: 'sword', item: '5e-srd-5.1:weapons.longsword', equipped: true }],
};

// 3. Compute the sheet. Every value is derived here, never saved.
const sheet = computeSheet(ruleset, character);
const mod = sheet.values['5e-srd-5.1:abilities.str.mod'];
console.log(en['fields.abilities.str.mod.name'], mod?.value); // Strength modifier 3

// 4. Change the character through the engine, never by editing the file.
const result = applyChanges(ruleset, character, [
  { type: 'set', field: '5e-srd-5.1:abilities.str.base', value: 18 },
]);
if (!result.ok) throw new Error(JSON.stringify(result.errors));
character = result.character; // save this

// 5. Roll an attack with the sword. The engine rolls the dice itself by default.
const attack = startAction(ruleset, character, {
  action: { id: '5e-srd-5.1:weapon-attack', entry: 'sword' },
  params: { targetAc: 13 },
});
if ('status' in attack && attack.status === 'finished') {
  console.log(attack.outcome); // e.g. { result: 'hit', data: { critical: false, attack: 17 } }
  console.log(attack.proposedChanges); // damage for the target, for your app to apply
}
```

What happened:

1. **`loadRuleset`** merged the pack, resolved every reference and checked every formula. The
   ruleset is plain JSON; cache it.
2. **The character** is a plain object in the
   [character file format](https://opencharacterformat.org/spec/characters/). Every ID in it is qualified
   with its pack (`5e-srd-5.1:…`).
3. **`computeSheet`** returned the Strength modifier (and every other value) with a breakdown of
   where it came from. It also listed the actions the character can take now, including
   `weapon-attack` on the equipped sword.
4. **`applyChanges`** returned a new character. It never changes the one you pass in, so the old
   one is still there for undo.
5. **`startAction`** built the attack roll, rolled it, decided hit or miss and proposed damage
   for the target. Applying the damage is up to your app ([Other characters](https://opencharacterformat.org/guides/other-characters/)).

The text came from the pack's English file, by key. The engine never returns display text
([Text and translation](https://opencharacterformat.org/guides/text-and-translation/)).

## Test data

The example characters in [`examples/characters/`](https://github.com/pixelqueue/opencharacter/tree/main/examples/characters/) are good test
data: `5e-tamsin.yaml` exercises effects, templates, competing options and Bless, and
`5e-goblin.yaml` is a monster.

## Next

- [Implementing OCF](https://opencharacterformat.org/guides/implementing/): how much of OCF your app needs, and where the engine
  runs.
- [Packs and rulesets](https://opencharacterformat.org/guides/packs-and-rulesets/): getting packs and loading them properly.
- [Storing characters](https://opencharacterformat.org/guides/storing-characters/): what to save and how.
