Interrupts
An interrupt takes an agent off what it is doing, runs a short reaction, and puts the agent back on the step it left. A passer-by stops to watch a street performer and then carries on to work. A shopkeeper leaves the shelves to serve someone at the counter and then goes back to the same shelf.
Two features are built on interrupts:
- Interest Spots, where passing agents may stop to look at something
- Service Points, where staff come to serve whoever is waiting
Nothing on this page runs until you set it up. A scene with no interrupt kinds, interest spots or service points behaves as it always has.
The short version
- Create an Interrupt Kind asset. It names the interrupt, such as
WatchPerformer. - Author the reaction for that kind in the Behaviour Tree Editor, either as a reaction in the Reactive tree or as an event duty inside a job.
- Place something in the scene that offers the kind: an Interest Spot or a Service Point.
The kind is the link between the two. The scene component offers it, and the tree holds what an agent does about it.
Interrupt kinds
Create/BardTreeLtd/Civil AI/Interrupt/Interrupt Kind
| Field | What it does |
|---|---|
| Display Name | The name shown in the Behaviour Tree Editor. Leave empty to use the asset name |
| Default Tier | How forcefully the interrupt may cut short what the agent is doing. See Tiers |
| Default Weight | How strongly the interrupt competes with the agent's work and needs. See Weight |
| Agent Cooldown Seconds | How long before the same agent accepts this kind again. 0 means no cooldown |
| Source Cooldown Seconds | An extra wait before the same agent accepts this kind from the same place again. 0 means none |
The agent cooldown starts whenever an interrupt of that kind ends, whether the agent finished the reaction or not.
Tiers
The tier decides what an interrupt is allowed to cut short.
| Tier | Cuts short | Refused when |
|---|---|---|
Polite | An agent walking to something, before it has started what it went there to do | The agent has arrived and is already performing, plus everything Firm refuses |
Firm | Also an agent that has arrived and is part way through its animation | The agent is seated, picking up or dropping off an item, in a custom action, idle, waiting, or following a route |
Urgent | Anything. A seated agent is stood up without its dismount animation | Never |
An agent with no action at all can always be interrupted.
Interest spots always offer at Polite and service points always offer at Firm, whatever the kind says. The kind's Default Tier applies to interrupts you offer from your own code.
Weight
An accepted interrupt competes with the agent's other behaviours in the usual way, and the highest weight wins. So a kind's weight only means something next to the weights it is up against:
| Behaviour | Default weight |
|---|---|
| Work, during the shift | 0.7 |
| Work, outside the shift | 0.3 |
| A need | Whatever its curve gives, 0 to 1 |
The figure that matters most is the default work weight of 0.7. Wherever these guides say an interrupt has to beat work, that is the number it has to beat. It is not a property of interrupts.
A kind whose weight equals the work weight never beats an agent at work. On a tie, work wins. With the default work weight of 0.7, use 0.72 or higher for anything a working agent should stop for.
Authoring the reaction
A reaction is ordinary behaviour tree content, authored in BardTreeLtd/Civil AI/Behaviour Tree Editor. It usually ends in one action set up like this:
| Field | Set to |
|---|---|
| Action | Go to Interrupt Target. The agent walks to the place the interrupt gave it |
| Look | FACE_INTERRUPT_TARGET. The agent faces the way its own standing place points |
| Endpoint behaviour | The animation to play on arrival, or a fixed length. This sets how long the agent stays |
An action with no endpoint behaviour has no length, so the agent walks over and leaves straight away.
There are two places a reaction can live.
In the Reactive tree
Use this for reactions any agent might have, whatever its job.
- Switch the Behaviour Tree Editor's Mode to
REACTIVE. - Add a Reaction node and set its Kind.
- Add a Step beneath it, and the action beneath that.
- Save the tree. It is stored under
Resources/CIVIL-AI-SYSTEM/BehaviourTree/Reactive/. - Open
BardTreeLtd/Civil AI/Module Settingsand choose the tree in the Reactive dropdown, beside the work and need trees.
With Reactive set to None, agents have no reactive tree and only event duties can handle interrupts.
In a job or a need
Use this when the reaction belongs to a role. Only shopkeepers serve customers.
In WORK mode, add a duty to the job and set its Event Kind. In NEED mode the same field is on a method. The node's title then shows the kind, such as Serve customer [on Serve customer].
A node with an Event Kind:
- is skipped when the job runs through its duties in order
- runs only when a matching interrupt is accepted
- hands the job back on the step it interrupted. That step starts again from its beginning, so a shopkeeper who was walking to a shelf sets off for that shelf again
A job only takes interrupts while the agent is at work. Off shift, the offer is turned down, and the end of a shift cancels a reaction that is still running.
While a job's reaction is waiting or running, work competes at whichever is higher, its own weight (0.7 by default) or the interrupt's. That is how a kind with a weight of 0.95 brings a shopkeeper back from lunch.
Which one is used
When an agent is offered an interrupt, its job is checked first, then its needs, then the Reactive tree. The first with a reaction for the kind takes it.
Marks
A mark is a place for an agent to stand, with a direction to face. A Mark Group holds a list of them: the audience around a performer, or the staff side of a counter.
Add the MarkGroup component to an object, create a child transform for each mark, and add them to the Marks list. An agent stands at the transform's position and faces along its forward axis.
| Field | What it does |
|---|---|
| Marks | One transform for each standing place |
| Goal Item | Optional. The item the visiting agent's action is treated as using, so an animation set up on that item's POIs plays |
Each mark is held by one agent at a time, and an agent is given the nearest free one. Disabling the group frees every mark, and agents still walking to one give up and go back to what they were doing.
In the Scene view a free mark is green, a held mark is yellow, and the marks of a disabled group are grey.
Marks are not seats. The agent is not parented to anything and no transition animation plays. For sitting, see Mounts and Seats.
When an agent says no
An agent turns an interrupt down when:
- interrupts are switched off in module settings
- the agent is paused, for example while in a conversation
- the agent is already handling another interrupt. One interrupt never replaces another
- the kind is still on cooldown for that agent
- no tree the agent uses has a reaction for the kind
- the reaction is on the agent's job and the agent is off shift
- the tier does not allow cutting short what the agent is doing
- the limit on agents being interrupted at once has been reached
Accepting does not stop the agent on the spot. It drops its current action on its next update, and the reaction starts once the interrupt wins against the agent's other behaviours.
Module settings
The Interrupts section of BardTreeLtd/Civil AI/Module Settings.
| Setting | Default | What it does |
|---|---|---|
| Enabled | On | The master switch. Off, no agent is ever interrupted |
| Auto Attach Receivers | On | Makes every agent able to be interrupted as it starts. Off, only agents with an AgentInterruptReceiver on their prefab are |
| Max Concurrent Interrupts | 16 | How many agents may be handling an interrupt at once across the scene. 0 means no limit |
| Debug Ring Buffer Size | 64 | How many recent offers and results are kept for debugging |
| Log Interrupts | Off | Writes every offer and its result to the Console |
| Draw Gizmos | On | Reserved. Marks are always drawn, and volumes are drawn when selected |
The player is never interrupted.
Reading interrupts from requirements
Each agent's blackboard records its interrupts, so a requirement on a tree connection can read them.
| Key | Type | Value |
|---|---|---|
interrupt.active | Bool | True while the agent is handling an interrupt |
interrupt.kind | String | The asset name of the kind being handled. Removed when it ends |
interrupt.last | String | The asset name of the last kind that ended |
interrupt.count.<kind> | Number | How many interrupts of that kind have ended for this agent |
Saving
An interrupt in progress is not saved. An agent saved part way through a reaction loads back on its ordinary work or need. The last kind and the counts are saved with the blackboard. Cooldowns are not.
Common problems
Turn on Log Interrupts first. Each offer is written to the Console with its result, and the reason usually says what is wrong.
| Symptom | Cause |
|---|---|
| Nothing is logged at all | Nothing is offering. Check the source's collider is a trigger with a kinematic Rigidbody, and that agents actually walk through it |
Declined with NoHandlerForKind | No reaction has this kind. Check the Reaction's Kind, that Reactive in module settings is not None, or the job's Event Kind |
Declined with HostUnavailable | The reaction is on the agent's job and the agent is off shift |
Declined with AbandonRefused | The agent is seated, picking something up, or, for a Polite interrupt, has already started its animation |
Declined with OnCooldown | The kind's Agent Cooldown Seconds has not run out for that agent |
Declined with GlobalCapReached | Max Concurrent Interrupts has been reached |
| Accepted, but the agent carries on working | The kind's weight does not beat the work weight, 0.7 by default. See Weight |
| The agent walks over and leaves at once | The reaction's action has no endpoint behaviour |
| Every agent in the audience faces the same way | Look is not FACE_INTERRUPT_TARGET, or the marks all point the same way |
Limits
- An agent handles one interrupt at a time.
- Seated agents are only interrupted at the
Urgenttier. - The step an agent returns to starts again from its beginning.
Next step
Continue to Interest Spots to have passers-by stop and look at something, or Service Points to have staff serve at a counter. The Interrupt Scene in Example Scenes shows both working. To offer interrupts from your own code, see the Interrupt Service.