# `Cauldron2D.Drafter.Client`
[🔗](https://github.com/jaman/cauldron/blob/v0.1.3/cauldron_2d_drafter/lib/cauldron_2d/drafter/client.ex#L1)

The drafter application that puts a `Cauldron2D.World` in front of one player.

Runs a game's client module — one implementing `Cauldron2D.Client.Game` —
through its screens: a title, a lobby listing the arenas, settings, the arena itself,
and a summary when the game's `outcome/1` says play is over for this player. It holds the player's input, their audio, and their connection to the world.

An arena whose `world` is `{module, opts}` is this player's alone: the client starts
a `Cauldron2D.World` for it when the player joins and stops it when they leave, and
`p` pauses and resumes it. A game whose `lobby?/0` is false goes from the title
straight into its first arena, and back to the title from it.

    Drafter.Server.start_ssh(Cauldron2D.Drafter.Client,
      auth: {:accounts, accounts},
      tunnel: true,
      mount_props: %{game: MyGame.Client, accounts: accounts}
    )

## Mount props

  * `:game` — the client module. Required
  * `:username` — the player's name, set by the ssh transport. Default `"player"`
  * `:sink` — a `TuningFork.Sink` module or `{module, opts}` this player's audio plays
    through. Default: the game's `sink/1` given all the mount props, else
    `TuningFork.Sink.Speaker` when that package is present, else silence
  * `:settings` — the map `Cauldron2D.Drafter.Client.Settings.to_props/1` produced,
    from the account props; a settings file for the player overrides it. Default: the
    game's first preset
  * `:accounts` — the `Drafter.Accounts` server settings are saved to. Default: none
  * `:kind` — the kind of client this is, the key its settings are kept under (see
    `Cauldron2D.Drafter.Client.Settings`). Default `:terminal`
  * `:start` — the first screen, `:title` or `:lobby`. Started at the lobby, the
    client has no title of its own: going back from the lobby (`Esc` or `q`) stops
    it, as quitting from the title does. Default `:title`

Every other mount prop is the game's, read by its `sink/1`, `pages/1` and `arenas/1`.

## Embedding

A game with screens of its own — its own title, a menu, pages that take input —
runs its own `Drafter.App` and drives this one from it: it keeps the client's state
from `mount/1` (with `start: :lobby`), and hands it its events, messages and timers
through `handle_event/2`, `handle_event/3`, `on_message/2` and `on_ready/1`, draws
`render/1`, and calls `unmount/1` when done. A `{:stop, reason}` from the client
is its wish to end: the game takes its screens back. The game's `use Drafter.App`
needs the same options this module's has — `key_release: true, cell_size: true,
frame_pacing: :always` — and its `refresh_rate/0` should be `refresh_rate/0` here.

## Tracing

With `CAULDRON_TRACE` set (see `Cauldron2D.Trace`), the client writes every key and
mouse event it steers with (`key`, `mouse`), every input it sends the world (`input`,
with the actions held and the aim in tiles) and every frame the world sends back
(`frame`, with its tick), so `mix cauldron.report --from mouse --to frame` measures
the way round.

## Keys

The client's own keys are `default_keys/0`, each replaceable or dropped by the game's
`client_keys/0`; what follows describes the defaults. In the arena `t` opens a line
to talk to everyone in it — `Enter` sends, `Esc` cancels, and no key steers while it
is open. `Esc` goes back: settings to where it was opened from, arena to lobby, lobby
to title, title out of the program. `q` quits the arena for the lobby too, and goes
to the title from the lobby. `^Q` and `^C` quit from anywhere. `?` shows the arena's key hints and hides
them again; held, it shows them until released. The `fps` key, bound only when the
game binds it, shows under the arena how many frames a second the world sends and
hides it again. `=` (or `+`) and `-` zoom the arena in and out through the levels
`Cauldron2D.Drafter.Surface.zoom_levels/2` gives for the display in use, the wheel
too (one step for the events a notch sends within 150 ms), and `0` puts the zoom
back; the zoom shows under the world while it is not
native. Watching (joined with `w`), the arrows and a drag with the left button pan
the view, the wheel zooms about the pointer, and `0` recentres; flying, the view
stays on the ship and the wheel zooms about it. A page the game adds (`pages/1`)
opens from the title on its key; `Esc` or `q` closes it.

Title: `Enter` plays, `s` opens settings, `h` the guide, `q` quits. Lobby: `↑`/`↓`
pick an arena, `t` a team where the arena has them, `Enter` joins, `w` watches, `s`
opens settings, `c` chats and `Enter` on an empty line leaves the chat. Settings: `↑`/`↓` move over
the items — preset, each action's binding, pointer steering, effects level, music
level, display (pixels where the terminal has them, braille, or glyphs), frame rate
(auto picks the terminal's best) — `←`/`→` change the item under the cursor, `Enter` on a binding then
a key or a mouse button adds it to the binding, `Backspace` removes the binding's last
key, `Esc` during a rebind cancels it. Arena: the game's bindings; `Tab`
opens settings without leaving the ship; the pointer steers only when pointer
steering is on, and a key bound to one of the game's `steering/0` actions takes over
from it until the pointer moves again.

# `arenas`

```elixir
@spec arenas(map()) :: [Cauldron2D.Client.Game.arena()]
```

The game's arenas, from its `arenas/1` given the mount props.

# `default_keys`

```elixir
@spec default_keys() :: %{required(atom()) =&gt; atom() | [atom()]}
```

The client's keys by action — a key, or a list of keys — before the game's `client_keys/0` is applied.

# `focus`

```elixir
@spec focus(map(), Cauldron2D.Client.Game.scene()) :: {number(), number()}
```

The point the arena is drawn around: the scene's focus moved by the pan.

# `follow`

```elixir
@spec follow(map(), Cauldron2D.Client.Game.scene()) :: map()
```

The state with its pan dropped when the scene's `:subject` is not the one the pan was taken on; a scene with no subject keeps the pan.

# `keybindings`

# `on_timer`

# `paused?`

```elixir
@spec paused?(map()) :: boolean()
```

Whether the player's own world is paused.

# `zoom_levels`

```elixir
@spec zoom_levels(map()) :: [number()]
```

The zoom levels this client steps through: `Cauldron2D.Drafter.Surface.zoom_levels/2` for the game's atlas and the display in use.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
