# Interaction

> Add interaction prompts to objects, and use the built-in doors, switches, pickups, and carrying and throwing.

Source: https://feather-engine.com/docs/gameplay/interaction/

Interaction is how the player acts on the world with a single key. Any object can show an
interaction prompt and call your script when it is used. Feather also includes ready-made
interactions that need no script: doors that swing open and can be locked with a key item,
switches that open and close linked doors, item pickups, containers, and carrying and throwing
physics objects.

All of them use the **Interact** action (E by default; West on a gamepad), and their state is kept
in saves.

## What's included

- **Interaction prompts** on any object, with custom text, that call `on_interact(id)`.
- **Doors** that swing about a hinge, optionally locked with an item that can be used up.
- **Switches** — levers or buttons — that toggle doors and other switches.
- **Pickups** that put an item in the inventory and remove the object.
- **Containers** the player opens to take and put items.
- **Carrying and throwing** dynamic bodies, with thrown objects dealing blunt damage to enemies.

## Add an interaction prompt

1. Select the object.
2. In **Details → Tags & interaction**, turn on **Interactable (E)**.
3. Enter the **Prompt** text, for example "Read" or "Talk".
4. Handle the interaction in a world script:

```rust
fn on_interact(id) {
    if id == "27" {
        print("The note reads: meet me at the lighthouse.");
    }
}
```

The prompt appears when the player is within the interaction distance, set in
**Window → Game logic → Game settings → Interaction distance** (0.5–20 m, default 2.5 m). Scripts can
change a prompt at runtime with `set_interact(id, prompt)`.

## Doors

1. Select the door object and choose **Details → Add Component → Door**.
2. Set how far it **Swings**, where the **Hinge** sits, and how long it **Takes**.
3. To lock it, turn on **Locked** and choose the **Key item**. Turn on **Uses up the key** to take
   the key from the player when it unlocks.
4. Give the door a **Kinematic** body so it pushes things as it moves.

| Field | Description | Range | Default |
| --- | --- | --- | --- |
| `open_degrees` | How far it swings; negative swings the other way | −180 to 180° | 95° |
| `hinge` | Hinge in the object's local box; `[-0.5, 0, 0]` is the left edge | ±5 | [−0.5, 0, 0] |
| `seconds` | Time to open or close | 0.05–30 s | 0.7 s |
| `locked_with` | Item ID that unlocks it; `null` is never locked | — | None |
| `consume_key` | Unlocking uses the key up | On/off | Off |
| `starts_open` | Open when Play starts | On/off | Off |
| `sound` | Sound cue or sound played when it moves | — | Empty |

## Switches

1. Select the lever or button and choose **Details → Add Component → Switch**.
2. Under **Opens and closes**, choose **Add a door** for each door or switch it drives.
3. Set the **Prompt**, and whether it **Starts on** or works **Only once**.

| Field | Description | Range | Default |
| --- | --- | --- | --- |
| `targets` | Object IDs of the doors or switches it drives | Up to 32 | None |
| `prompt` | Prompt text | 1–80 characters | Pull |
| `once` | Can only be used once | On/off | Off |
| `starts_on` | On when Play starts | On/off | Off |
| `tilt` | Degrees the switch object tips when on; 0 keeps it still | −120 to 120° | 40° |
| `sound` | Sound played when used | — | Empty |

## Pickups and containers

A **Pickup** component puts its item in the inventory when the player interacts with it, and the
object disappears. A **Container** opens a screen to take and put items. Both are covered in
[Items and inventory](/docs/gameplay/items-and-inventory/#pickups-and-containers).

## Carrying and throwing

The player looks at a dynamic body and presses **Interact** to pick it up, and presses it again to
set it down. The **Throw** action (left mouse by default) hurls it. Heavier objects fly slower, and
thrown objects deal blunt damage to enemies they hit.

Configure it in **Window → World & terrain → Items → Carrying & throwing**.

| Setting | Field | Range | Default |
| --- | --- | --- | --- |
| Pick up physics objects | `carry` | On/off | On |
| Heaviest | `carry_max_mass` | 0–10,000 kg | 60 kg |
| Held at | `hold_distance` | 0.5–6 m in front of the camera | 1.8 m |
| Throw speed | `throw_speed` | 0–60 m/s for a light object | 13 m/s |
| Throw damage | `throw_damage` | 0–10 blunt damage per kg·m/s | 0.12 |
| Throw action | `throw_action` | An input action ID | `throw` |

Door, lever, pickup, chest and throw sounds can be replaced with your own cues in
**Built-in sounds** under the player's game feel settings; see
[Player and traversal](/docs/gameplay/player-and-traversal/).

## Extend it

| Function | Description |
| --- | --- |
| `use_object(id)` | Acts as if the player pressed Interact on the object: opens doors, pulls switches, takes pickups |
| `door_open(id)` | Whether a door is open |
| `carry_object(id)` | Picks up a dynamic body, including one that has settled at rest |
| `throw_carried()`, `drop_carried()` | Throws or sets down what the player carries |
| `carrying()` | The ID of the carried object, or `()` |
| `use_tool()` | Casts the worn tool where the camera aims |
| `set_interact(id, prompt)` | Changes an object's prompt |
| `tune("interaction", patch)` | Changes the carrying and throwing settings at runtime, for example a heavier `carry_max_mass` after an upgrade |

`on_interact(id)` still runs when the player uses a door, switch or pickup, so you can add
behaviour on top of the built-in one.

```rust
// A world script: react when the player pulls lever 40 and gate 41 opens.
fn on_interact(id) {
    if id == "40" && door_open(41) {
        print("The gate is open. Guards are coming.");
    }
}
```

## Limits

- A switch drives at most 32 targets.
- A door's hinge must be within ±5 of the object's local box.
- Only dynamic bodies up to `carry_max_mass` can be carried.

## Automate it

```bash
# Lock door 41 with the "key" item, used up on unlock
feather-cli --connect .feather-session.json command scene.update \
  --json '{"id":41,"patch":{"door":{"open_degrees":-100,"locked_with":"key","consume_key":true}}}'

# A lever (object 40) that opens door 41
feather-cli --connect .feather-session.json command scene.update \
  --json '{"id":40,"patch":{"switch":{"targets":[41],"prompt":"Pull lever"}}}'

# Let the player lift heavier objects
feather-cli --connect .feather-session.json command interaction.set \
  --json '{"patch":{"carry_max_mass":120,"throw_speed":16}}'
```

`interaction.get` lists the carrying settings and the level's doors, switches and pickups.
