# D&D 5th Edition

The `@randsum/games/fifth` subpath provides [Dungeons & Dragons 5th Edition](https://www.dndbeyond.com/) mechanics including ability checks, saving throws, and attack rolls with full support for advantage and disadvantage.

[Official Site &amp; SRD](https://www.dndbeyond.com/)

## Installation

<CodeExample lang="bash" code={`bun add @randsum/games`} />
  <CodeExample lang="bash" code={`npm install @randsum/games`} />
  ## Usage

<CodeExample code={`// Basic roll with modifier
const result = roll({ modifier: 5 })
// result.result: 6-25 (d20 + 5)`} />

<CodeExample code={`// Roll with advantage (2d20, keep highest, + modifier)
const result = roll({
  modifier: 5,
  rollingWith: 'Advantage'
})`} />

<CodeExample code={`// Roll with disadvantage (2d20, keep lowest, + modifier)
const result = roll({
  modifier: -2,
  rollingWith: 'Disadvantage'
})`} />

## API

### `roll(input?: { modifier?, rollingWith?, crit? })`

**Input:**

| Property | Type | Description |
|---|---|---|
| `modifier` | `number` (optional) | Ability/skill modifier (-30 to +30) |
| `rollingWith` | `'Advantage' \| 'Disadvantage' \| undefined` | Roll 2d20, keep highest or lowest |
| `crit` | `boolean` (optional) | When set, enables natural 1/20 detection in `details.criticals` |

**Returns:** `GameRollResult<FifthRollResult, FifthRollDetails>` with:

| Property | Type | Description |
|---|---|---|
| `result` | `FifthRollResult` (`number`) | Final total (d20 + modifier) |
| `total` | `number` | Same as result |
| `rolls` | `RollRecord[]` | Raw dice data from the core roller |
| `details` | `FifthRollDetails` | Contains `criticals` (see below) |

**`FifthRollDetails`:**

| Property | Type | Description |
|---|---|---|
| `criticals` | `{ isNatural1: boolean, isNatural20: boolean } \| undefined` | Present when `crit` input is set |

## Outcomes

- **Normal roll**: 1d20 + modifier
- **Advantage** (`'Advantage'`): Roll 2d20, drop lowest, + modifier (equivalent to `2d20L+modifier`)
- **Disadvantage** (`'Disadvantage'`): Roll 2d20, drop highest, + modifier (equivalent to `2d20H+modifier`)

The modifier is validated to be a finite number in the range -30 to +30.

## Common patterns

<CodeExample code={`// Attack roll with +5 to hit
roll({ modifier: 5 })

// Attack with advantage
roll({ modifier: 5, rollingWith: 'Advantage' })

// Saving throw with -1 penalty and disadvantage
roll({ modifier: -1, rollingWith: 'Disadvantage' })

// Perception check with +3 Wisdom
roll({ modifier: 3 })`} />

## Ability score generation

The `@randsum/games/fifth` package handles d20 action rolls. For ability score generation (4d6, drop lowest), use the core roller directly:

<CodeExample code={`// Generate one ability score: 4d6, drop lowest
const score = roll('4d6L')
console.log(score.total) // 3-18

// Generate all six scores
const scores = Array.from({ length: 6 }, () => roll('4d6L').total)
console.log(scores) // e.g. [14, 12, 15, 8, 10, 13]`} />

## Error handling

Game `roll()` can throw two types of errors:

- **`ValidationError`** (from `@randsum/roller`) -- numeric input out of range or not finite (e.g., `modifier: Infinity`)
- **`SchemaError`** (from `@randsum/games/fifth`) -- game-specific issues like invalid `rollingWith` values

<CodeExample code={`try {
  roll({ modifier: Infinity })
} catch (error) {
  if (error instanceof ValidationError) {
    // Non-finite modifier value
    console.log(error.code)    // 'VALIDATION_ERROR'
  } else if (error instanceof SchemaError) {
    // e.g., invalid rollingWith enum value
    console.log(error.code)    // 'INVALID_INPUT_TYPE'
  }
}`} />

## Types

<CodeExample code={``} />

## Schema

This game is powered by a `.randsum.json` spec that defines the d20 resolution, advantage/disadvantage, and modifier validation. The TypeScript code is generated from this spec at build time. See [Schema Overview](https://randsum.dev/games/schema/overview/) for how game specs work.

## Links

- [npm package](https://www.npmjs.com/package/@randsum/games)
- [Source code](https://github.com/RANDSUM/randsum/tree/main/packages/games)