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

A setup page shown before a game starts. The player picks where the game's data is,
how it is drawn, and anything else the game asks. Play saves the choices, and later
runs start straight away with them.

    fields = [
      %{key: :dir, label: "Quake folder", kind: {:path, &MyGame.check_dir/1}, discover: &MyGame.find_dir/0},
      %{key: :skill, label: "Skill", kind: {:choice, [{0, "easy"}, {1, "normal"}, {2, "hard"}]}, default: 1},
      Cauldron2D.Drafter.Launcher.drawing_field()
    ]

    case Cauldron2D.Drafter.Launcher.choose(MyGame.Client, fields, overrides: %{skill: 2}, player: "ranger") do
      {:ok, values} -> start_the_game(values)
      :quit -> :ok
    end

A field is a map:

  * `:key` — the atom its value is kept under
  * `:label` — the text shown beside it
  * `:kind` — `{:path, check}`, a path the player types, where `check` takes it and
    answers `:ok` or `{:error, text}`; `{:choice, [{value, text}]}`, one of a list the
    player steps through; or `:text`, any text
  * `:default` — the value when nothing else gives one (optional)
  * `:discover` — a function answering a value or `nil`, tried when nothing is saved
    (optional; for finding a game's data in the usual places)
  * `:hint` — a line shown under the field (optional)

`choose/3` works out each value from the run's overrides (from command-line flags),
then what was saved, then `:discover`, then `:default`. It shows the page when nothing
has been saved yet, when a path does not pass its check, or when the option
`launcher: true` asks for it. Play saves the values under
`$XDG_CONFIG_HOME/<game>/launcher.config` (or `~/.config`), `<game>` named as
`Cauldron2D.Drafter.Client.Settings` names it. Overrides that skip the page are not
saved.

A field with key `:drawing` (`drawing_field/0`) is also written into the player's
settings (`Cauldron2D.Drafter.Client.Settings`'s `drawing`) when `:player` is given, so
the page and the game's own options change the same setting.

On the page, ↑ and ↓ move, ← and → change a choice, Enter edits a path or text or presses
Play or Quit, and Escape quits.

# `field`

```elixir
@type field() :: %{
  :key =&gt; atom(),
  :label =&gt; String.t(),
  :kind =&gt;
    {:path, (String.t() -&gt; :ok | {:error, String.t()})}
    | {:choice, [{term(), String.t()}]}
    | :text,
  optional(:default) =&gt; term(),
  optional(:discover) =&gt; (-&gt; term() | nil),
  optional(:hint) =&gt; String.t()
}
```

# `choose`

```elixir
@spec choose(module(), [field()], keyword()) :: {:ok, map()} | :quit
```

The values for `game`'s `fields`, showing the page when it is needed. Options:
`:overrides` (a map of values for this run), `:launcher` (`true` shows the page
whatever was saved), `:player` (the player whose settings get the `:drawing` field),
`:title` (the page's heading, default the game's title).

# `drawing_field`

```elixir
@spec drawing_field() :: field()
```

The field for how the game is drawn: automatically, in software, or on the graphics card in the terminal or a window.

# `keybindings`

# `load`

```elixir
@spec load(module()) :: map()
```

The values saved for `game`, or an empty map.

# `on_ready`

# `on_timer`

# `path`

```elixir
@spec path(module()) :: Path.t()
```

Where `game`'s launcher choices are kept.

# `save`

```elixir
@spec save(module(), map()) :: :ok
```

Saves `values` for `game`.

# `show`

```elixir
@spec show(String.t(), [field()], map()) :: {:ok, map()} | :quit
```

Shows the page with `values` filled in; answers the values on Play, or `:quit`.

# `steam_folders`

```elixir
@spec steam_folders(String.t()) :: [Path.t()]
```

The folders where Steam keeps the game folder `name` on this machine, the ones that
exist: Steam's own libraries on macOS, Linux (including Flatpak) and Windows, and
Steam in CrossOver bottles on macOS. For a field's `:discover`.

    Cauldron2D.Drafter.Launcher.steam_folders("Half-Life")

# `unmount`

---

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