Missions AI and Scripting - LordBlacksun/Starlancer-OSS GitHub Wiki
Missions are data-driven .DTE files interpreted by an in-engine trigger/event VM. The
complete opcode / command / AI tables are on the
.DTE Scripting Reference page; this page covers the file format,
trigger system, lifecycle, and how the two reverse-engineering sources reconcile. All [verified]
unless noted.
This documentation fuses our static decompilation (addresses, struct layouts, the VM, per-command implementations) with the black-box research of Captain Foster / "Starlancer ME" (https://starlancerme.blogspot.com/, @CaptainFoster) β the numeric opcode/command/AI/ship tables and observed in-game semantics. Wherever the two overlap, they agree.
The HOG-stored file is RefPack / EA-"QFS" compressed (signature 10 FB, 3-byte big-endian
uncompressed size β the HOG itself is EA's BIGF format). FUN_0045A300 obtains the bytes (a loose
missions\%s.dte if present, else the HOG resource β a straight read, 0x1A EOF byte on loose
reads) and the RefPack stream decompresses into a fixed image (the β€ 0xFA000 buffer is sized
for it). FUN_00451D90 then resolves 27 sections in a fixed order via FUN_00452A20 β each an
8-byte descriptor { u16 count, relocation-flag bits @ 24-27, u32 offset } read from offset 0 of
the decompressed image and fixed up to a live pointer (0xFFFF = empty section).
Path format ..\missions\%s.dte (FUN_0044F3D0 is only the mission-select menu).
Verified section roles/strides:
| Section | Pointer | Stride |
|---|---|---|
| ship / flight-group array |
DAT_0052951C (count DAT_00529504) |
0x4C |
| globals / variables | DAT_005294F8 |
0x0C (u16 name-idx, u32 value) |
| objectives / operands | DAT_005267CC |
0x14 |
| trigger records | DAT_005294E0 |
0x30 |
| script bytecode base | DAT_00525F88 |
β |
| per-ship trigger index | DAT_005267C0 |
0x08 (+1 count, +2 u16 first-index) |
| per-bytecode-byte flag map | DAT_005294D8 |
1 |
[resolved] Decompressed, the 27Γ8 directory validates cleanly, and our section offsets match
Starlancer ME's black-box anchors to the byte β ships 0x30FF7, FG/objectives 0x3A7F7,
triggers 0x3BBF7, script 0x47BF7, target list 0x57BF7. The earlier "our copies differ /
offsets past EOF / inline name strings at 0xB6" puzzle was only the compression: our extracted
blob is the packed form, the blog worked from the expanded one β the two efforts now agree
completely. tools/dte_parse.py decodes all 44 missions (decode / sweep): a clean-room RefPack
decompressor + the directory + ship/objective/trigger/part records + a script disassembler that
follows control flow (rebuilt 2026-09-29; zero errors across all 44 missions).
Campaignβlevel view: how these missions are ordered, numbered, and branched (the progression rule, the inβgameβ
.dtenumbering, the variant/unused files) is in Campaign Mission Flow.
FUN_0045B330 holds the name array, indexed by value: 33 scriptable conditions, 0x00β0x20
(TT_SHOTAT=0 β¦ TT_BEING_CHASED=0x20) β identical to Starlancer ME's Triggers page. (The
condition-descriptor table DAT_0052952C has 35 slots; the 2 past 0x20 are internal.) Full list
on the Scripting Reference.
| Offset | Field |
|---|---|
+0x00 |
TT_* condition β the event type the trigger watches (0x00β0x1F in all 2,446 shipped triggers). A trigger holds no subject: it is implicit in the section-5 slice the record sits in. |
+0x01 |
repeat mode (0 one-shot, 2 repeat-N via +0x19) |
+0x02 |
u16 link β a halfword offset into section 6; the thread starts at script + link Γ 2 (0xFFFF = none) |
+0x14 |
armed flag |
+0x15 |
qualifier β the component of the subject watched, by index, or 0xFF for the subject itself (2,168 of 2,446) |
+0x16 |
byte passed to the thread starter (FUN_0045B8D0): whether the thread runs at once or from the scheduler |
+0x1C⦠|
operand array (stride 4) |
Dispatch: event β look up the subject's slice via DAT_005267C0 β FUN_0045CEA0 tests armed
(+0x14), condition (+0x00), qualifier (+0x15), link (+0x02 β 0xFFFF) + operands β fire-list DAT_0052ABE0 (stride 0x30, cap 1000) β action script. Proximity
(5/6) is polled in FUN_0045AF60.
A single bytecode stream (base DAT_00525F88) run by the interpreter FUN_0045C980:
fetch one opcode byte β index the 86-entry handler table DAT_004F6350 β advance IP β call
handler, until one returns 0. Script blocks are u16-length-prefixed; the per-byte flag array
DAT_005294D8 marks yield points. The VM is a stack machine: pushes of constants, strings,
globals and record pointers, compares, arithmetic and forward branches build the operand stack, and
commands (0x21 <index> β the catalogue at 0x4F0F50: 95 commands, each with its
implementation address and parameter count) pop their arguments from it. This resolves the previous open question of how the action opcodes were
enumerated: see the Scripting Reference for the full tables.
Outcome grade DAT_0052A428 selects from five tiers, 0β4: Failure, Partial Failure,
Partial Success, Success, Success + Bonus. A mission defaults to "Failure" and is
promoted by the script's win/lose flag (opcode 0x40 writes on the kill condition; 0x27 reads
at mission end).
| Addr | Role |
|---|---|
0x0045A4E0 / 0x0045A530 / 0x0045A570
|
mission init / destroy / process (per-frame). Guards DAT_005373E8 (active), DAT_005373E4 (fire count). |
0x00486830 |
objectives ("ERROR: No mission Objectives defβ¦"); SetObjective states 0/1/2. |
0x0048E140 |
dumps live mission state to c:\mission.txt (syncs, globals, ships). |
0x004924B0 |
mission-exit poll; manages outcome grade DAT_0052A428. |
0x00401000 |
multiplayer AI sync gate β per-ship bitmask entity + 0x710 + idx; proceeds only when all players are synced. Driven by MultiplayerScriptSync. |
0x0040D210 |
capital-ship / turret / ion-cannon AI (ship types 0x44/0x48/0xA5). |
The numeric trigger/command/AI/ship/pilot tables and observed runtime semantics are the work of
Captain Foster / Starlancer ME (https://starlancerme.blogspot.com/,
@CaptainFoster, email withheld), who also
maintains a Python "Mission Ship Editor". This page pairs that with our static decompilation.
Licence β this page is licensed CC BY 4.0: use it in any project, whatever that project's own licence, with attribution. Code and tools in Starlancer-OSS remain GPL-3.0-only, and the Game Reference pages are CC BY-SA 3.0, as they derive from the Starlancer Fandom Wiki. StarLancer, its code and its assets belong to their owners; no licence here covers them.