> ## Documentation Index
> Fetch the complete documentation index at: https://docs.humalike.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Runtime control

> Lease movement, animation, speech or perception of any active NPC for a bounded time.

Any resource can take over selected AI domains of any active NPC (static,
ambient, or a bound [external](/ai-npc/integrations/external-npcs) one).
Humalike stops acting in those domains until the lease ends. The NPC's
definition and entity are untouched.

All exports on this page return one result table:
`{ apiVersion = 1, ok = true, value = ... }` or
`{ apiVersion = 1, ok = false, error = code }`. They must be called from a
resource other than `humalike`, or they fail with `external_resource_required`.

## Acquire a lease

```lua theme={null}
local result = exports.humalike:AcquireNpcControl(npcId, {
    domains = { 'movement', 'animation' },
    ttlMs = 30000,
    reason = 'hostage_scenario',
})
if not result.ok then return print(result.error) end
local lease = result.value  -- { id, npcId, kind, ownerResource, domains, reason, expiresInMs }

exports.humalike:RenewNpcControl(lease.id, 30000)
exports.humalike:ReleaseNpcControl(lease.id)
```

| Option    | Description                                                                |
| --------- | -------------------------------------------------------------------------- |
| `domains` | 1 to 4 of `movement`, `animation`, `speech`, `perception`, or `all` alone. |
| `ttlMs`   | 1,000 to 300,000. Default 30,000.                                          |
| `reason`  | Optional string up to 128 characters, returned in the lease.               |

| Domain       | Effect while held                                                                                             |
| ------------ | ------------------------------------------------------------------------------------------------------------- |
| `movement`   | Movement actions are refused and Humalike stops pacing the ped.                                               |
| `animation`  | Animation actions are refused and the current pose is forgotten.                                              |
| `speech`     | The NPC does not speak. Voice targeting and labels show it as unavailable.                                    |
| `perception` | The NPC does not hear players and player events are not delivered to it. Server observations are still filed. |
| `all`        | All of the above. `aiEnabled` reports `false`.                                                                |

Acquiring a lease cancels the NPC's in-progress action in that domain. A
request that overlaps a held domain is refused as a whole.

| Error                                                               | Meaning                                          |
| ------------------------------------------------------------------- | ------------------------------------------------ |
| `npc_not_active`                                                    | The NPC has no live entity.                      |
| `invalid_domains`, `invalid_domain`, `all_domain_must_be_exclusive` | Bad `domains` list.                              |
| `invalid_ttl`, `invalid_reason`, `invalid_options`                  | Argument shape.                                  |
| `domain_conflict`                                                   | A requested domain is already leased.            |
| `lease_not_found`, `not_owner`                                      | Renew or release of an unknown or foreign lease. |

A lease ends at its TTL, when its owner resource stops, when the NPC's entity
disappears, or when an ambient NPC is re-assigned to another body.

## Runtime state

```lua theme={null}
local state = exports.humalike:GetNpcRuntimeState(npcId).value
local rows = exports.humalike:ListNpcRuntimeStates().value
```

| Field                                               | Description                                                                     |
| --------------------------------------------------- | ------------------------------------------------------------------------------- |
| `kind`                                              | `static`, `ambient` or `external`.                                              |
| `active`                                            | Whether a live entity exists.                                                   |
| `entity`, `networkId`, `routingBucket`, `modelHash` | Current entity. `entity` is a server handle; use `networkId` across boundaries. |
| `aiEnabled`                                         | `false` while every domain is leased.                                           |
| `controlledDomains`                                 | Map of domain to `{ leaseId, ownerResource, expiresInMs }`.                     |
| `entityOwner`                                       | `humalike`, `external` or `despawned`.                                          |
| `bindingId`, `despawnId`, `entityOwnerResource`     | Present when a resource owns the entity or the despawn.                         |

`ListNpcRuntimeStates` returns every roster NPC, including unbound external
ones, plus current ambient bodies, sorted by `npcId`, each with `name` and
`model`. `GetNpcRuntimeState` fails with `npc_not_found` for an id not on the
roster.

## Next

* [Bind your own ped to a character](/ai-npc/integrations/external-npcs).
* [Report facts about the NPC](/ai-npc/integrations/world-events#server-observations).
* [Compact export reference](/ai-npc/reference#server-exports).
