MISSION SCRIPTING

The world model

This page names the parts of a mission. Every other guide uses these words. Read it once before you write code.

The short version

A mission is an activity. The activity runs on one scenario. The scenario is split into bubbles. Each bubble has one or more states. The world is full of objects. Each object has slots. A script reads slots and sends requests to them. The client sends reports back. The host turns reports into events, and your script reacts to events.

Activity

An activity is one playable thing: a mission, a patrol zone, a social space, a raid encounter.

  • It has an internal name, for example mission_deadzone.
  • The runtime picks your script by that name. See Your first script.
  • Several activities can share one internal name. They then share one script.

Scenario

A scenario is the authored level data behind an activity. It has a tag such as 0x80B9AD31.

  • One generated Lua module exists per scenario, for example missions.mission_deadzone_80b9ad31.
  • The module lists every state, slot, squad and scene in that scenario.

Bubble, state and region

A bubble is one loaded area of the map. The client loads one bubble at a time.

A state is one authored layout of a bubble. A bubble can have several states, for example “cutscene” and “playable”.

A region is the number that names one state. It is what the client reports when it moves.

/* How the generator builds a region number. */
region_index = slice_set_index + state_ordinal;
  • Bubbles often step by 8, so regions look like 0, 8, 16, 24.
  • Two states of one bubble differ in the ordinal, for example 16 and 17.
  • context:select_state(state) asks the client to load one state.
  • initial_state in your program picks the state the player spawns into.

Object and slot

An object is one authored thing in the world: a door, a squad spawner, a trigger, a HUD sensor.

A slot is one controllable part of an object. Scripts talk to slots, never to objects.

Each slot has:

fieldmeaning
idstable text id, slot/<object tag>/<ordinal>/<slot index>/<slot type>
nameauthored name, for example pt_mines_start
typewhat the slot is; see the table below
indexthe slot’s index inside its object’s registry

The slot type decides which methods work. Calling a method on the wrong type is an error.

Slot types a script can drive

typewhat it iscommon name prefixmain methods
1squad spawnerSQ_assign_combat_objective (on the slot), place (on the squad)
2one combatant or actor in a squadSQ_<squad>_<name>run_atoms, play_actor_path, play_actor_action, play_sequence, retire_actor
3objectiveOBJ_reset_objectives, target of assign_combat_objective
4authored object (prop, pickup, chest)O_set_object_active, set_interactable_object
5authored sequenceSEQ_play_sequence
6cinematicvariesset_cinematic_active
11music sensorvariesset_music_section
20damage monitorvarieswatch_damage
23device (door, lift, lever, shield)D_transition, set_channel, applied
30player occupancy monitorPM_set_occupancy_condition
31player triggerPT_fire_trigger, disarm_trigger
34object filterOF_set_object_filter
35hard-wipe globals (darkness zone)variesset_darkness_zone
38task sensorvariesadvance_task
42performance sensor (NPC idle)..._IDLEplay_performance
43authored sceneSC_use context:scene(...)
47navigation markerAP_, LOOK_AT_used as navpoint in set_directive
53dialogue sensorM_DIALOG_SENSOR_...play_dialogue_cue
58actor pathvariesused as path in play_actor_path
60trigger volume (a box in the world)TV_used as a filter or waypoint
65Ghost link (scan)variesset_ghost_link, ghost_link
66spawn ruleSR_, ..._SPAWNRULEused as spawn_rule in place
68directive sensor (HUD objective)M_DIRECTIVE_SENSOR_...set_directive, clear_directives
70engagement sensorM_ENGAGEMENT_SENSOR_...used as audience in set_directive
71public event sensorM_PUBLIC_EVENT_SENSOR_...set_public_event_state

The prefixes are an authoring habit, not a rule. Always check the type field in the generated module. Slots with no authored name are called SLOT_<index>_<tag>.

Squad

A squad is a group of enemies or NPCs that spawn together.

  • A squad has members. Each member has a default count.
  • A squad belongs to a type-1 slot. mission.Squad.SQ_X and mission.Slot.SQ_X name the same squad. You need the squad to place it and the slot to give it an objective.
  • The members of a squad are type-2 slots, named after the squad, for example SQ_HAWTHORNE_HAWTHORNE.

Scene

A scene is a small authored script that the client runs, for example two NPCs talking, or enemies jumping down from a ledge.

  • context:scene(mission.Scene.X):activate{} starts it.
  • stop{} ends it and send_event{key = n} sends it a signal.

Directive and dialogue

  • A directive is the objective text on the HUD, with an optional map marker.
  • A dialogue cue is one voice line list inside a dialogue sensor.
  • The generated module lists both with their text, so you can search for a line.

Requests, reports and events

A script never changes the world directly. It makes requests. The native host sends them to the client. The client sends reports. The host turns reports into events.

/* The loop every mission runs. */
while (mission_running) {
    Event event = host_wait_for_client_report();
    Requests requests = script_callback(context, state, event);   /* your Lua */
    host_send_to_client(requests);
}
  • Every request returns a request key. The matching effect_result event carries the same key.
  • The host owns revisions, counters and delivery. A script never counts them.
  • A script reacts to what the client reports. It does not guess or resend on a timer.

Attempt

An attempt is one run of the mission from a start or a checkpoint.

  • context.attempt_generation names the current attempt.
  • A checkpoint restart starts a new attempt.
  • Timers are cleared when the attempt changes. Variables are kept.

Mission state

The host stores a small amount of state for your script. It survives a script reload and a client reconnect.

  • Variables: named scalar values. Up to 512.
  • Timers: named countdowns. Up to 32.
  • Phase: one integer.

Plain Lua values, such as a local table, do not survive a reload. Keep anything that matters in variables. See How a script runs.