# Multi-Target Navigation & Dynamic Costs

***

## How Target Resolution Works

During each planning cycle, `AIBehavior.Plan()` calls `ComputeCost(behavior)` on every action that has `IsIncludeOnPlanning = true`. Override `ComputeCost` to call `SelectBestBinder()`, which:

1. If `_target` (the Inspector-assigned Transform) is already set — use it as-is
2. Otherwise — query `TargetBinderRegistry` for compatible binders (filtered by `TargetTag`), score each candidate, and lock the best available one

The selected binder is locked immediately (`IsAvailable = false`) so other behaviors in the same planning cycle cannot claim it. After planning, binders held by actions that were **not** selected into the final plan are released automatically.

```csharp
public override void ComputeCost(AIBehavior behavior)
{
    SelectBestBinder(); // queries TargetBinderRegistry; locks the winner

    if (Target != null)
    {
        float dist = Vector3.Distance(behavior.transform.position, Target.position);
        SetDynamicCost(_cost + dist * 0.1f); // farther = more expensive
    }
}
```

***

## Dynamic Action Costs

Override `ComputeCost()` to set context-sensitive costs before each A\* search:

| Method                       | Description                                                                                                                     |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `SetDynamicCost(float)`      | Sets the dynamic cost for the next planning cycle. Clamped to ≥ 0.01.                                                           |
| `ClearDynamicCost()`         | Reverts `Cost` to the static inspector value.                                                                                   |
| `SelectBestBinder(isRandom)` | Queries `TargetBinderRegistry` for a binder matching `TargetTag`; locks the nearest (or random) one. Call from `ComputeCost()`. |

`ComputeCost()` is called by `AIBehavior.Plan()` **before** the A\* search runs. If any action cost changed since the last plan, the plan cache is automatically invalidated.

***

## Target Selection Scoring

Each binder candidate is scored using:

```
score = distance / priority
```

Lower score wins. A binder with `Priority = 2` appears twice as close as a binder at the same distance with `Priority = 1`.

***

## Automatic Resource Locking

Resource locking is fully automatic:

| Event                                           | Behaviour                                                                             |
| ----------------------------------------------- | ------------------------------------------------------------------------------------- |
| `SelectBestBinder()` finds a binder             | Binder is locked immediately (`IsAvailable = false`)                                  |
| Action completes (`PostPerform` returns `true`) | Binder is released (`IsAvailable = true`, `_target` cleared)                          |
| Action is interrupted (`OnInterrupt`)           | Binder is released automatically (base implementation)                                |
| Action was not selected into the plan           | Binder is released in Phase 3 (async result consumed) after the plan queue is applied |
| Behavior re-enables with `Reset On Enable`      | All binders on all actions are released                                               |

To override binder release behaviour, override `OnInterrupt()` and call `base.OnInterrupt()`:

```csharp
public override void OnInterrupt()
{
    base.OnInterrupt(); // releases the locked TargetBinder
    // your cleanup here
}
```

***

## Target Wait Timeout

When `TargetWaitTimeout > 0` on an action and no binder is available at plan time, the behavior holds the dequeued action and polls each frame:

```
[Action dequeued — no binder available]
        │
        ▼  (each frame)
  Retry ResolveTarget()
        │
   ┌────┴────────────────────────────┐
   │ Binder found                    │ Timeout expired
   ▼                                 ▼
Start action normally        Skip goal → try next goal
```

Set **Target Wait Timeout** to `0` (default) to fail immediately when no binder is available.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://beelabs-dev.gitbook.io/beelabs-docs/goap-engine/multi-target-navigation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
