Missions AI and Scripting - LordBlacksun/Starlancer-OSS GitHub Wiki

Missions, AI & Scripting (.DTE)

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.

.DTE file container

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↔.dte numbering, the variant/unused files) is in Campaign Mission Flow.

Trigger conditions β€” the TT_* set [verified]

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.

Trigger record (0x30 bytes) [verified]

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.

Scripting VM [verified]

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.

Outcomes [verified]

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).

Lifecycle & AI [verified]

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).

Credit

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.

⚠️ **GitHub.com Fallback** ⚠️