Skip to content

GOAP: Goals & Actions ​

This is how you make an entity do things. You define goals (states the entity wants) and actions (atomic steps it can take). The planner chains actions to reach goals on its own. Read the GOAP system page first for how selection works; this page is the authoring format.

Goals ​

A goal is a desired world state with a priority. The planner tries to make the desiredState true.

json
{
  "name": "WANDER",
  "displayName": "Wandering",
  "description": "Drifts through the area when nothing else needs attention.",
  "internal": true,
  "basePriority": 0.01,
  "desiredState": {
    "IsWandering": { "label": "Wandering", "equals": true }
  },
  "metadata": {
    "CompletionDuration": 5.0,
    "CompletionDurationVariance": 3.0
  }
}

Goal fields ​

FieldMeaning
nameUnique goal id, used in planning and the priority panel.
displayNameShown in UI.
descriptionPlayer-facing explanation.
basePriorityStarting weight before calculators and player adjustment.
desiredStateThe condition the planner tries to satisfy.
metadataPresentation and timing (animations, completion pause).

Goal visibility flags ​

FlagEffect
internal: trueHidden from the player's goal-priority panel. Use for background goals and drama goals so the player cannot switch them off.
system: trueA system goal that outranks player goals (FIGHT, FLEE). Fires automatically when its state is met.

IMPORTANT

Player-tunable priority belongs on the goal's weight calculator, not inside desiredState. Changing a desired state can make a goal unreachable. See priority math.

desiredState operators ​

OperatorMeaning
equalsThe property must equal this value.
minThe property must be at least this value.
maxThe property must be at most this value.

Actions ​

An action is one atomic step. It declares what must be true to run (preconditions), what becomes true when it succeeds (postconditions), a cost, and the behaviorName that runs it.

json
{
  "name": "DO_WANDER",
  "preconditions": {},
  "postconditions": { "IsWandering": true },
  "cost": 1,
  "behaviorName": "street_bum_DO_WANDER",
  "metadata": {
    "ExecutionAnimation": "walk_down",
    "ExecutionDuration": 1.0,
    "CompletionAnimation": "idle_down"
  }
}

Action fields ​

FieldMeaning
nameUnique action id.
preconditionsState that must hold for the action to be eligible.
postconditionsState the action sets when it succeeds (its effect).
costPlanning cost. The planner prefers cheaper chains.
behaviorNameThe behavior that executes. Reuse a built-in one or register your own.
metadataAnimation and ExecutionDuration (timed dwell).

Reuse built-in behaviors ​

The fastest mods reuse behaviors that already exist, so you write no code:

behaviorNameDoes
Generic movementWalk to a target
Generic transactionExchange resources with another entity
Shared combat (flee, engage)Standard combat steps

A mod can also register its own named behavior in C#; see Services & C# API.

Actions apply their own effects ​

When an action succeeds, its postconditions are applied automatically. Do not also write the same change by hand inside the behavior, or the effect applies twice. Declare the effect in postconditions and let the framework apply it. Direct writes are only for things an action cannot express, like a cross-entity signal.

Movement targets ​

To make an action walk the pawn to another entity, add a movementTarget block. The framework handles pathfinding and target locking:

json
{
  "name": "FIND_BUYER",
  "preconditions": {},
  "postconditions": { "AtBuyer": true },
  "cost": 1,
  "behaviorName": "GENERIC_MOVEMENT",
  "movementTarget": {
    "entityType": "Addict",
    "selection": "nearest",
    "filterProperty": "WantsToBuy",
    "filterValue": true,
    "stopDistance": 55
  }
}
movementTarget fieldMeaning
entityTypeType to walk toward.
selectionHow to pick among candidates (for example nearest).
filterProperty / filterValueOnly consider targets matching this.
stopDistanceHow close to get before arriving.

Cross-entity handshakes ​

When two entities transact (a dealer hands off to a buyer), one side signals the other by setting a property on it. The passive side watches that flag, consumes it, and completes. Always clear such flags at the start of a new cycle so a stale signal does not complete the next run instantly.

Putting it together ​

You defineThe planner does
A goal with a desiredStateFinds actions whose postconditions reach it
Actions with pre/postconditionsChains them cheapest-first
behaviorName per actionRuns the behavior until it returns success

Next ​

Community documentation for BBox: Kingpin.