Skip to main content
Version: 0.15.0

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:

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​

  1. Create an Interrupt Kind asset. It names the interrupt, such as WatchPerformer.
  2. 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.
  3. 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
FieldWhat it does
Display NameThe name shown in the Behaviour Tree Editor. Leave empty to use the asset name
Default TierHow forcefully the interrupt may cut short what the agent is doing. See Tiers
Default WeightHow strongly the interrupt competes with the agent's work and needs. See Weight
Agent Cooldown SecondsHow long before the same agent accepts this kind again. 0 means no cooldown
Source Cooldown SecondsAn 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.

TierCuts shortRefused when
PoliteAn agent walking to something, before it has started what it went there to doThe agent has arrived and is already performing, plus everything Firm refuses
FirmAlso an agent that has arrived and is part way through its animationThe agent is seated, picking up or dropping off an item, in a custom action, idle, waiting, or following a route
UrgentAnything. A seated agent is stood up without its dismount animationNever

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:

BehaviourDefault weight
Work, during the shift0.7
Work, outside the shift0.3
A needWhatever 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.

warning

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:

FieldSet to
ActionGo to Interrupt Target. The agent walks to the place the interrupt gave it
LookFACE_INTERRUPT_TARGET. The agent faces the way its own standing place points
Endpoint behaviourThe animation to play on arrival, or a fixed length. This sets how long the agent stays
note

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.

  1. Switch the Behaviour Tree Editor's Mode to REACTIVE.
  2. Add a Reaction node and set its Kind.
  3. Add a Step beneath it, and the action beneath that.
  4. Save the tree. It is stored under Resources/CIVIL-AI-SYSTEM/BehaviourTree/Reactive/.
  5. Open BardTreeLtd/Civil AI/Module Settings and 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.

FieldWhat it does
MarksOne transform for each standing place
Goal ItemOptional. 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.

SettingDefaultWhat it does
EnabledOnThe master switch. Off, no agent is ever interrupted
Auto Attach ReceiversOnMakes every agent able to be interrupted as it starts. Off, only agents with an AgentInterruptReceiver on their prefab are
Max Concurrent Interrupts16How many agents may be handling an interrupt at once across the scene. 0 means no limit
Debug Ring Buffer Size64How many recent offers and results are kept for debugging
Log InterruptsOffWrites every offer and its result to the Console
Draw GizmosOnReserved. 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.

KeyTypeValue
interrupt.activeBoolTrue while the agent is handling an interrupt
interrupt.kindStringThe asset name of the kind being handled. Removed when it ends
interrupt.lastStringThe asset name of the last kind that ended
interrupt.count.<kind>NumberHow 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.

SymptomCause
Nothing is logged at allNothing is offering. Check the source's collider is a trigger with a kinematic Rigidbody, and that agents actually walk through it
Declined with NoHandlerForKindNo 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 HostUnavailableThe reaction is on the agent's job and the agent is off shift
Declined with AbandonRefusedThe agent is seated, picking something up, or, for a Polite interrupt, has already started its animation
Declined with OnCooldownThe kind's Agent Cooldown Seconds has not run out for that agent
Declined with GlobalCapReachedMax Concurrent Interrupts has been reached
Accepted, but the agent carries on workingThe kind's weight does not beat the work weight, 0.7 by default. See Weight
The agent walks over and leaves at onceThe reaction's action has no endpoint behaviour
Every agent in the audience faces the same wayLook 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 Urgent tier.
  • 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.