# BusHoldBroken

> Talos next · Since 0.6

Payload of the engine-published `"hold-broken"` event: a hold made with {@link WorldQuery.hold | ctx.world.hold} has ended, for any reason.

One event per hold that ends, raised with the physics events (after the solver, before behaviours' `update`): a break on the tick the solver broke it, a `release` or despawn a behaviour made on the tick after. `by` is null. Like `"ui-activated"` it reaches {@link Behavior.onEvent} as well as `on`/`once`, and `GET /events?filter=hold-broken` lists it. A hold replaced by another `hold` of the same body — a hand-over, a new offset — has not ended and raises nothing. `heldBy(target)` is already null when this arrives. `ts ctx.events.on("hold-broken", (ev) => { if (ev.data.holder === ctx.entity.id && ev.data.reason === "distance") ctx.audio.play("drop") }) ```

## Signature

```ts
export interface BusHoldBroken {
  /** Id of the entity that was holding. */
  holder: string
  /** Id of the entity that was held. `""` only for one despawned on the very tick it was grabbed. */
  target: string
  /**
   * Why it ended:
   * - `"distance"`: the body fell more than `breakDistance` behind its hold point and kept falling
   *   behind — carried into a wall the holder walked away from.
   * - `"mass"`: the body was rebuilt (a hot reload) heavier than the hold's `maxMass`.
   * - `"released"`: {@link WorldQuery.release | ctx.world.release} let it go, thrown or not.
   * - `"despawned"`: the holder or the held entity was despawned, or the held body was removed or
   *   rebuilt as something that cannot be carried.
   */
  reason: "distance" | "mass" | "released" | "despawned"
}
```

Import: `import type { BusHoldBroken } from "@argus/api"`

## Members

| Member | Signature | Description |
|---|---|---|
| `holder` | `holder: string` | Id of the entity that was holding. |
| `target` | `target: string` | Id of the entity that was held. `""` only for one despawned on the very tick it was grabbed. |
| `reason` | `reason: "distance" \| "mass" \| "released" \| "despawned"` | Why it ended: - `"distance"`: the body fell more than `breakDistance` behind its hold point and kept falling   behind — carried into a wall the holder walked away from. - `"mass"`: the body was rebuilt (a hot reload) heavier than the hold's `maxMass`. - `"released"`: {@link WorldQuery.release \| ctx.world.release} let it go, thrown or not. - `"despawned"`: the holder or the held entity was despawned, or the held body was removed or   rebuilt as something that cannot be carried. |

## Example

The tested fixture `fixtures/app/agent.ts`.

```ts
import type { Behavior } from "@argus/api"

// Sends a nav agent to `props.target` once, then reports arrival through ctx.state so the
// test can read it without polling the crowd directly.
export default {
  init(ctx) {
    ctx.state.arrived = false
    ctx.nav?.goTo(ctx.props.target as [number, number, number])
  },
  update(ctx) {
    if (ctx.nav?.arrived) ctx.state.arrived = true
  },
} satisfies Behavior
```
