MISSION SCRIPTING

Lua API reference

This is the full list of what a mission script can call and read. It matches the runtime in server/activity/mission/mission_script_lua_*.cpp. The live SDK views (context.sdk.catalog, world, manifest) have their own page, The live SDK views.

How to read this page

  • context:name(...) is a method. Call it with a colon.
  • context.name is a field. Read it with a dot.
  • Most requests take one table of named arguments: slot:transition{transition = t}.
  • An unknown key in that table is an error. A misspelled key never passes silently.
  • A request returns a RequestKey. See “Request keys”.
  • A 64-bit number is always a decimal string, because a Lua integer cannot hold every value.
  • “slot of type N” means the method errors on any other slot type.

Handles

Every object the API gives you is a locked handle. You cannot add fields to it, read its metatable, or build one yourself. A handle re-checks its row on every read. If the data changed under it, the read errors with “stale”.

handlehow you get it
contextfirst callback argument
statesecond callback argument
eventthird callback argument
slotcontext:slot(...), event.slot, context.sdk.slots:at(n)
squadcontext:squad(...), context.sdk.squads:at(n)
scenecontext:scene(...), context.sdk.authored_scenes:at(n)
request keyreturned by every request
cohortcontext:cohort{...}
lifetimecontext.lifetime

Context

The first argument of every callback.

Fields

fieldtypemeaning
sdkactivity viewthe live SDK; see The live SDK views
sdk_build_idstringsha256:<64 hex>
activity_idstringactivity id
activity_rowintegeractivity row
definition_hashintegeractivity hash
activity_rolestring"public" or "private"
player_keystringthe linked player’s key, decimal
attempt_generationstringcurrent attempt, decimal
mission_completebooleantrue after complete_mission was accepted in this attempt
lifetimelifetime handlesee “Lifetime”
peerspeer collectionsee “Peers”
timerstimer name collectionsee “Name references”
variablesvariable name collectionsee “Name references”

Lookups

methodreturnsnotes
context:slot(selector)slot handleselector is a mission.Slot id string or a slot row number
context:squad(selector)squad handleselector is a mission.Squad id string or a squad row number
context:scene(selector)scene handleselector is a mission.Scene id string or a scene row number
context:cohort{squads = list}cohort handlesee “Cohort”

An unknown selector is an error: “unknown or ambiguous activity slot”. Pass the id string, not a handle.

Mission state

methodreturnsnotes
context:set_variable(name, value)nothingvalue is a boolean, integer, finite number or string up to 127 bytes
context:clear_variable(name)booleantrue when the variable existed
context:start_timer(name, ms)stringthe timer sequence; replaces a timer with the same name
context:cancel_timer(name)booleantrue when the timer existed
context:set_phase(n)nothingn is 0 to 4294967295; a change raises phase_entered

A name is 1 to 63 bytes of letters, digits, _, -, . and /. nil is not a value; use clear_variable.

World requests

methodargumentsnotes
context:select_state(state, options)state: a mission.states row; options: see belowload another authored state; moves the player when needed
context:activate_objects{slots, active}slots: list of type-4 slots; active: default truereturns a list of request keys, one per object group
context:complete_mission{}nonecompletes this attempt; errors when already complete
context:hold_spawn{active}active: required booleanhold the player’s spawn, or release it
context:restart_checkpoint{region, spawn_set_hash, release_request}see belowwipe and restart the party

A held spawn keeps the roster’s spawn gate closed, so the player has no body yet. Use it when the mission opens on a cutscene. Release it with active = false when the player should arrive.

select_state options is either a plain list of type-4 slots to keep out of the seed, or a table with:

keytypemeaning
[1], [2], …slot idsobjects to keep out of the new state’s seed; up to 32
retire_placed_propsbooleanend the map props captured from the old state before the move

restart_checkpoint arguments:

keytypemeaning
regioninteger 0 to 1022the region the party is in
spawn_set_hashintegerthe authored spawn set to restart at
release_requeststringthe value of the arming request; releases the wipe

Arming is refused unless the activity is private, the whole party is dead, the party is in region, and the spawn set exists. An accepted arm starts a new attempt. See “Wipe and restart at a checkpoint” in Recipes.

State

The second argument of every callback. Read-only.

memberreturnsnotes
state.phaseintegerincludes a set_phase made earlier in this callback
state.revisionstringthe committed state revision
state:variable(name)value or nilsees changes made earlier in this callback
state:has_variable(name)boolean
state:timer(name)string or nilthe timer’s deadline tick

Request keys

Every request returns a RequestKey.

membermeaning
key.valuethe key as a decimal string
key:matches(other)true when two keys are the same request

A key handle is lost on reload. Store key.value in a variable when you need to match the result later.

local key = context:select_state(mission.states.STATE_X)
context:set_variable("state_request", key.value)

Slot

Fields

fieldtypemeaning
rowintegerslot row in this activity
idstringsame as the mission.Slot value
namestringauthored name
object_idstringowning object id
object_tagintegerowning object tag
registry_keyintegerregistry key the client uses
slot_indexintegerindex in the registry
slot_typeintegerthe slot type
component_classintegercomponent class id
sense_schema, auth_schemaintegerreport and request schema ids
sense_schema_id, auth_schema_idstringthe same as text
auth_typestring or nilrequest type name, for example device_sensor
auth_min_bits, auth_max_bitsinteger or nilrequest body size
auth_component_offsetinteger or nil
auth_dynamic, auth_writableboolean or nil
flagsintegercatalog flags

Methods by slot type

Every method below returns a RequestKey unless the table says otherwise.

methodslot typearguments
set_object_active{active, with}4active default true; with: up to 63 more type-4 slots sent together
set_interactable_object{active, used, track_owner}4active default true; used default false; track_owner default false
watch_damage{target}20target: a type-4 slot handle
set_object_filter{players, target, inside, inside_any}34see below
set_occupancy_condition{value, filter}30value: int32; filter: optional slot handle
set_darkness_zone{enabled, wipe_seconds}35enabled default false; wipe_seconds -1 (none) to 3; a countdown needs enabled
set_music_section{section, enabled}11section 0 to 127; enabled default true
set_ghost_link{active}65active default true
ghost_link()65returns {generation, progress, active} or nil; not a request
transition{transition, snap}23transition from context.sdk.device_transitions; snap default false
set_channel{channel, value, snap}23channel from context.sdk.device_channels; value from context.sdk.unit(x)
applied{channel}23returns boolean; not a request
fire_trigger()31arms the trigger
disarm_trigger()31stops it reporting
set_directive{directive, state, navpoint, waypoint, audience}68see below
clear_directives()68hides the goal
set_public_event_state{area, leave_seconds, state, player}71see below
play_sequence()5plays the authored sequence
play_sequence{sequence}2plays an actor sequence; see “Actor sequences”
sequences()2returns the actor’s sequence collection; not a request
set_cinematic_active{active}6active default true
reset_objectives()3resets every task of the objective
advance_task()38advances the authored task bit
play_performance{state}42state: a mission.PerformanceState entry; may be left out when the target has one state
play_dialogue_cue{cue, filter}53cue 0 to 65535; filter: optional type-60 slot handle
assign_combat_objective{objective, task_group, reconsider, reserved, refresh_player_awareness}1see below
run_atoms{atoms, spawn}2see “Atom programs”
play_actor_path{path, spawn}2path: a type-58 slot on the same object
play_actor_action{ability, target, spawn}2one ability atom
retire_actor()2removes the actor
bind_combatant_to_squad()2arms the actor for its scene’s squad spawn

“Slot handle” means a value from context:slot(...), not an id string.

set_object_filter

keytypeadds this test
playersbooleanobjects that are players
targettype-4 slot handlethis one object
insidetype-60 slot handleobjects inside this volume
inside_anylist of 1 to 5 type-60 slot handlesobjects inside any of these volumes

set_directive

keytypemeaning
directivea mission.Directive entrythe goal to show; it must belong to this sensor
stateinteger 0 to 2directive state; default 0
navpointtype-47 slot handlemap marker target
waypointtype-60 slot handlevolume where the marker hides
audiencetype-70 slot handleengagement sensor for the mission banner

set_public_event_state

keytypemeaning
areaslot handlethe object whose zone bounds the event area; required
leave_secondsnumber 0 or moreseconds outside the area before the client reports it; required
stateint32shown by the HUD; default 0
playerdecimal stringthe watched player; default context.player_key

assign_combat_objective

Call it on the squad’s type-1 slot.

keytypemeaning
objectivetype-3 slot handlerequired; must be in the same registry as the squad
task_groupa mission.TaskGroup entrywhich task group to use; default none
reconsiderbooleanforce the squad to pick again; default false
reservedbooleanreservation flag; left out keeps the current reservation
refresh_player_awarenessbooleandefault false

Inside on_event_squad_state for the same squad, the request carries the reported objective revision, so the host can reject a stale change.

Squad

Fields and methods

memberreturnsmeaning
row, id, nameidentity
member_countintegermembers in the squad
default_countslistauthored count per member
anchorscollectionspawn points as world rows; see The live SDK views
counts()count vectora new vector filled with the defaults
place{counts, mode, spawn_rule, retire_on_return}RequestKeyspawn the squad
actor_command{command, value}RequestKeysend one command to every live member

place

keytypemeaning
countscount vector from this squadhow many of each member; default the authored counts
modefrom context.sdk.squad_modesreinforce (default), replace or reserve
spawn_ruletype-66 slot handlereplaces the authored spawn rule
retire_on_returnbooleanlet the host retire the squad’s old entities when the client returns them; default false

A count vector from another squad is an error.

Count vector

membermeaning
countnumber of members
capacity15
at(i)count of member i, from 1
set(i, n)set member i to n, 0 or more
local squad = context:squad(mission.Squad.SQ_GUARDS)
local counts = squad:counts()
counts:set(1, 3)
squad:place{counts = counts, mode = context.sdk.squad_modes.replace}

actor_command

keytypemeaning
commandintegera mission.ActorCommand value
valueint32the command value, for example a mission.Faction value

Scene

memberreturnsmeaning
row, ididentity
activate{spawn}RequestKeystart the scene; spawn = true also spawns its authored cast
stop{}RequestKeystop the running scene
send_event{key}RequestKeysend a signal; key is 1 to 4294967294

activate{spawn = true} errors when the scene has no single authored cast.

Cohort

A cohort is a read-only view of up to 64 squads.

local group = context:cohort{squads = {mission.Squad.SQ_A, mission.Squad.SQ_B}}
if group.cleared then
    -- every squad in the group is dead
end
fieldtypemeaning
alive_countinteger or niltotal alive; nil while any squad is unknown
observed_fullbooleanevery squad was seen at full strength
clearedbooleanseen full, and now all dead
sizeintegernumber of squads

A squad with a placement still in the queue counts as unknown. So cleared is false until the placement is delivered and the client has reported the squad.

Lifetime

context.lifetime:set{state = s} sets the activity lifetime state. s comes from context.sdk.lifetime_states:

membermeaning
at(n)state n, 0 to 10
defaultstate 3
count11

complete_mission sets state 6 for you. Prefer it.

Peers

context.peers lists the other sessions in this activity.

membermeaning
countnumber of peers
at(i)peer i, from 1

A peer has session_id, session_generation, member_key and join_identity, all decimal strings.

Name references

context.timers:resolve(name) and context.variables:resolve(name) check a name and return a handle with a name field. capacity gives the store size (32 and 512). They only check names; no request takes them yet.

Value types

makermakesused by
context.sdk.unit(x)a channel value with fields value, low (0), high (1)set_channel
context.sdk.position(x, y, z)a world position with fields x, y, z; all finitenothing yet
context.sdk.device_channels.position / .power / .locka channel with name and valueset_channel, applied
context.sdk.device_transitions.<name>a transition with name, channel, valuetransition
context.sdk.squad_modes.<name>a mode with name and valueplace

The six transitions:

namechannelvalue
openposition1
closeposition0
power_onpower1
power_offpower0
locklock1
unlocklock0

Actor sequences

slot:sequences() on a type-2 actor returns its sequence collection.

membermeaning
countnumber of sequences
at(n)sequence n, or nil
<SYMBOL>the sequence with that symbol, or nil
KEY_<8 hex>the sequence with that key hash, or nil

A sequence has id, name, symbol, source_path, key, kind, resource_tag, table_index, ordinal, source_offset and playable.

local actor = context:slot(mission.Slot.SQ_BOSS_BOSS)
local sequence = actor:sequences().BERSERK_ANIMATION
if sequence ~= nil and sequence.playable then
    actor:play_sequence{sequence = sequence}
end

Only a playable sequence of this same actor is accepted.

Atom programs

slot:run_atoms{atoms = list, spawn = flag} sends a small program to a type-2 actor. The list has 1 to 32 atoms. Each atom is a table with a kind. context.sdk.atom_kinds holds the kind names.

kindfieldsmeaning
facetarget, valueturn to a point of target
snap_totarget, valuejump to a point of target
move_totarget, value, enabledmove to a point of target
sequencevalueplay a sequence by number
sleepsecondswait
trivialnonean empty step
control_flagvalue 0 to 63set a control flag
set_temperamentvalue, enabledset a temperament
set_channelchannel, valueset an actor channel to a number
abilityability, targetuse a mission.ActorAbility entry of this actor
  • target is a slot handle. value on face, snap_to and move_to is an authored point number of that target, 0 to 255. An unknown point is an error.
  • An ability must belong to this actor. Its optional target must have an authored point 0.
  • Any atom may add quantized, 0 to 2047.
  • spawn = true creates the actor from its authored source first. It errors when the actor has no single authored source.

play_actor_action{ability, target, spawn} is a one-atom ability program. play_actor_path{path, spawn} sends the actor along an authored type-58 path that has a destination.

Events

Every event has these fields:

fieldtypemeaning
kindintegerthe EventKind number
sequencestringevent order number
source_generationstringclient generation that produced it
attempt_generationstringattempt it belongs to

Most events also have mission_sequence (string), the input order. Delivery events do not.

Slot identity

Events about one slot also have:

fieldtype
slotslot handle, or nil when the slot is not in this activity
registry_key, object_tag, slot_index, slot_typeinteger

To test an event against a slot:

local function is_slot(context, event, id)
    return event.slot ~= nil and event.slot.id == context:slot(id).id
end

Fields per event

A field that the report did not carry reads nil. The first column is the callback name without its on_event_ prefix.

eventfields beyond the common ones
region_changedregion_index; previous_region_index (nil the first time)
client_state_changedclient_message_sequence, payload_bytes, activity_state_revision, membership_revision, region_index, current_region_index, held_region_index, region_slice_set_hash, spawn_state, teleport_state, teleport_slice_set_index, teleport_slice_set_hash, entered
player_triggerslot identity; volume_registry_key, volume_slot_type, volume_slot_index, resolved_object_id
trigger_entered, trigger_exitedslot identity; member_count, value, all_inside
squad_stateslot identity; alive_count, previous_alive_count, removal_flag, slot_counts (list); methods task_cost{group}, task_group{objective}
entity_spawnedslot identity; member_slot, count, previous_count
entity_diedslot identity; alive_count, previous_alive_count
squad_provokedregistry_key, slot_type, slot_index; no slot
damage_stateslot identity; health, shield, revision
object_state, object_interactedslot identity; generation, present, alive (same as present), interaction_open, owner_known, has_owner, owner_key
device_stateslot identity; position, power, lock, position_sequence, power_sequence, lock_sequence, first_report, reset; method applied_request{channel}
ghost_link_stateslot identity; generation, progress, active
actor_path_stateslot identity; generation, revision, path_state, delivery_revision, delivery_state, suppressed
scene_finishedslot identity; activation_token
objective_progressslot identity; objective, task, task_count, previous_task_count
cinematic_started, cinematic_terminated, cinematic_skip_requestedslot identity; runtime_object_id (string), event_value
fireteam_statealive_count, dead_count, unknown_count
session_joinedsession_id, session_generation, member_key, joined_revision
session_leftsession_id, session_generation, member_key
timer_elapsedtimer_name, timer_deadline_tick, timer_sequence
phase_enteredphase, previous_phase, state_revision
effect_resultrequest_key, effect, outcome, outcome_code
entity_slots_requestedrequested_count
sensor_sense_updatedclient_message_sequence, payload_bytes, state_revision, peer_heard_mask, objects_decoded, groups_decoded; slot identity of the first object, when there is one
incident_receivedclient_message_sequence, payload_bytes, incident_target, incident_extra_targets, incident_selector_bytes, incident_payload_bytes
client_message_receivedclient_message_sequence, payload_bytes, peer_heard_mask, state_revision, message_type, message_status, message_name, message
scriptable_override_transport_stagedscriptable_revision; no mission_sequence

client_state_changed in detail

The client sends state reports often, also while it loads. Most carry no change.

fieldpresent when
enteredtrue only on the host’s arrival answer; nil otherwise
held_region_indexthe host knows which region the client holds
region_indexthe report names a region leg
current_region_indexthe report names the current region
spawn_statethe report carries a spawn byte
teleport_statethe report carries a teleport byte; context.sdk.client_teleport_reset (0) marks a finished spawn

Use region_changed to react to movement. Use client_state_changed with entered == true to react to the first arrival.

squad_state methods

methodreturns
event:task_cost{group = g}cost (number or nil) and known (boolean) for a mission.TaskGroup entry
event:task_group{objective = slot}the current group (compares equal to a mission.TaskGroup entry) or nil, and assigned (boolean)

device_state:applied_request

event:applied_request{channel = c} returns the RequestKey that this report satisfied on channel c, or nil.

effect_result

fieldmeaning
request_keythe key of the request
effectthe request name from the list below, or nil for any other request
outcometransport_staged, refused, expired or canceled
outcome_code0 to 3 in the same order

effect names: squad.place, scene.activate, scene.stop, scene.send_event, slot.set_object_active, slot.set_channel, slot.run_atoms, slot.retire_actor, slot.set_interactable_object, slot.set_ghost_link, slot.watch_damage, slot.assign_combat_objective, lifetime.set, mission.restart_checkpoint, slot.fire_trigger, slot.play_sequence, slot.set_cinematic_active, slot.play_performance, slot.reset_objectives, slot.advance_task, slot.play_dialogue_cue, mission.select_state, mission.hold_spawn.

client_message_received

fieldmeaning
message_typethe message id
message_statusunclassified, decoded, decoded_partial, prefix_only, opaque, outer_decoded, prepared, prepare_refused, malformed or quarantined
message_namethe catalog name, or nil
messagethe catalog message row, or nil; see The live SDK views

A message row’s matches{event = e} tells whether an event is that message.

Errors you will see

messagecause
effect argument is not declareda misspelled or extra key in the argument table
effect arguments must be one tableyou passed a value that is not a table
<key> must be a <type>wrong type for a named argument
unknown or ambiguous activity slotthe id is not in this activity
activity slot is not an exact type-N ...the method does not fit this slot type
activity slot is stalethe data changed under a handle you kept
mission variable name is invalidempty, too long, or a bad character
mission variable value is not a bounded scalarnil, a table, a non-finite number or a long string
mission variable capacity exceededmore than 512 variables
mission timer capacity exceededmore than 32 timers
directive does not belong to this slotthe directive comes from another sensor
squad counts were minted by another squada count vector from a different squad
mission attempt is already completecomplete_mission called twice
instruction_budgetthe callback ran too long