# Salvage Union

The `@randsum/games/salvageunion` subpath provides mechanics for [Salvage Union](https://leyline.press/pages/salvage-union), a post-apocalyptic mech-based tabletop RPG that uses table-based d20 mechanics.

[Official Site](https://leyline.press/pages/salvage-union)

## Installation

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

<CodeExample code={`// Roll on the Core Mechanic table
const result = roll('Core Mechanic')`} />

<CodeExample code={`// Roll on a different table
const result = roll('Morale')`} />

<CodeExample code={`const { result } = roll('Core Mechanic')
const { label, description, roll: rollValue } = result

console.log(\`\${rollValue} - \${label}\`)
// e.g., "16 - Success"
console.log(description)
// e.g., "You have achieved your goal without any compromises."`} />

<CodeExample code={`const { result } = roll('Core Mechanic')

// Access structured result data
switch (result.key) {
  case 'nailed_it':
    // Roll of 20 - exceptional success
    break
  case 'success':
    // Roll of 11-19 - standard success
    break
  case 'tough_choice':
    // Roll of 6-10 - success with complications
    break
}`} />

## API

### `roll(tableName: string)`

**Input:**

| Parameter | Type | Description |
|---|---|---|
| `tableName` | `string` | Table to roll on (must be a valid table name from `VALID_TABLE_NAMES`) |

**Returns:** `GameRollResult` with:

| Property | Type | Description |
|---|---|---|
| `result` | `SalvageunionRollResult` | Table result with metadata |
| `total` | `number` | D20 roll result (1-20) |
| `rolls` | `RollRecord[]` | Raw dice data from the core roller |

### Result structure

The `SalvageunionRollResult` interface includes:

| Property | Type | Description |
|---|---|---|
| `key` | `string` | Internal result identifier |
| `label` | `string` | Human-readable result label |
| `description` | `string` | Detailed result description |
| `table` | `Record<string, unknown>` | Full table data |
| `tableName` | `string` | Name of the table rolled |
| `roll` | `number` | D20 roll result (1-20) |

## Core Mechanic table

The default Core Mechanic table uses these result tiers:

| Roll | Result |
|---|---|
| 20 | Nailed It -- exceptional success |
| 11-19 | Success -- goal achieved without compromise |
| 6-10 | Tough Choice -- success with complications |
| 2-5 | Failure |
| 1 | Cascade Failure -- critical failure |

:::note
Other tables in Salvage Union have different result tiers and descriptions. The package includes all official tables from the Salvage Union reference.
:::

## Table names

Use the `VALID_TABLE_NAMES` const tuple to get all available table names. This is generated from the spec at build time.

<CodeExample code={`// VALID_TABLE_NAMES is a readonly tuple of all valid table name strings
// e.g. ['Core Mechanic', 'Group Initiative', 'Critical Injury', ...]`} />

## Error handling

Passing an invalid table name throws a `SchemaError`:

<CodeExample code={`try {
  roll('Not A Real Table')
} catch (error) {
  if (error instanceof SchemaError) {
    console.log(error.code)    // 'NO_TABLE_MATCH'
    console.log(error.message) // 'Invalid Salvage Union table name: "Not A Real Table"'
  }
}`} />

## Types

<CodeExample code={``} />

## Schema

This game is powered by a `.randsum.json` spec that defines the d20 resolution, outcome tables, and table lookup logic. 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)