SEQ — Cutscene Timeline (.SEQ)¶
SEQ files drive in-game cutscenes (mission briefings, death screens, campaign intros). Each file is a plain ASCII text timeline: a sequence of timestamped commands that trigger bitmaps, sounds, palette changes, and fades. FA_2.LIB carries 126 of them.
Tools¶
fx¶
fx seq dump <file.SEQ> # pretty-print events to stdout
fx seq unpack <file.SEQ> [-o out.txt] # write editable text
fx seq pack <in.txt> -o <out.SEQ> # write binary SEQ
Other Tools¶
SEQ files are plain ASCII — open and edit directly, no conversion step needed.
- VS Code — free; multi-file find/replace useful for batch renaming bitmap or sound references
- Notepad++ — free, Windows; column editing helps with tab-aligned time fields
- Notepad / TextEdit — free, built-in; sufficient for small edits
File Layout¶
Plain text; no binary fields.
; optional comment lines (or //)
[blank lines]
<INDENT><time>[ sync]<TAB><command>[<TAB><arg1> <arg2> ...]<CR><LF>
- A line is a comment when it opens with
;or//(SeqSkipComments, 0x445440). - An event line is indented with spaces or a tab — the engine skips both alike before the
content. 530 shipped events use a tab, and three (
UDEAD.SEQ,UWON.SEQ,ULOST.SEQ) indent their finalfadeoutwith six spaces.
fxused to require a tab, so it classified those three lines as comments and dropped the event — the fadeout vanished from the timeline. All three files still round-tripped byte-identically, because an unrecognised line is re-emitted verbatim. See #491.
- Lines may use
\r\nor\n— write\r\non output. - A trailing
0x1A(DOS EOF) is preserved verbatim; 7 shipped sequences carry one.
Time field¶
| Form | Meaning |
|---|---|
0 |
Absolute tick 0 |
5 |
Absolute tick 5 |
+23 |
Relative: 23 ticks after the previous event |
Trailing spaces after the time value (before the second tab) are legal and common.
Command and arguments¶
Arguments are space-separated on the same line, after the command:
- Quoted strings: "NAME" (filename references, no extension)
- Bare numbers / floats: 256, .5, 0
Commands — the symbol table is the vocabulary¶
A SEQ command is an import. _SeqContinue (0x445700) builds "_SEQ" + <command>, resolves
it with SMAddress, and calls whatever comes back — the same mechanism BRF's symbol
keyword uses (BRF.md). That is why fadeout appears nowhere in FA.EXE: the
string that exists is _SEQfadeout, in FA.SMS. A command that does not resolve simply
does nothing.
So the vocabulary is not a guess — it is whatever _SEQ* symbols the engine exports, and
tests/test_seq.cpp checks every command in every shipped sequence against db/symbols/.
| Command | Symbol | Typical args | Notes |
|---|---|---|---|
bitmap |
_SEQbitmap |
"NAME" x y flags width |
Display image at (x,y) |
palette |
_SEQpalette |
"NAME" |
Load a named palette |
font |
_SEQfont |
"NAME" |
Set current font |
video |
_SEQvideo |
"NAME" |
Play video clip |
sound |
_SEQsound |
"NAME" |
Play sound (quoted, no extension; ^ prefix = looping) |
fadein |
_SEQfadein |
seconds |
Fade to full brightness |
fadeout |
_SEQfadeout |
seconds |
Fade to black |
wait |
_SEQwait |
(none) | Pause until sound/video completes |
text |
_SEQtext |
— | Exported, unused by any shipped sequence |
music |
_SEQmusic |
— | Exported, unused — see MUS |
sndoff |
_SEQsndoff |
— | Exported, unused |
call |
_SEQcall |
— | Exported, unused |
run |
_SEQrun |
— | Exported, unused |
sync is not a command — it is a modifier that may precede one (+23 sync fadeout .5).
An earlier version of this table listed it as a command and omitted the five above.
Includes¶
include "NAME" is part of the language (SeqParseInclude, 0x4456B0), alongside macro
substitution (SeqSubstitute, 0x4454D0). No shipped sequence uses either, and fx does
not expand them.
Example¶
KDEAD.SEQ (92 bytes):
0 bitmap "KDEAD" 0 0 0 256
0 fadein .5
0 sound "^KDEAD.11K"
+23 sync fadeout .5
Round-Trip Notes¶
fx seq pack emits files byte-identical to the originals (tabs, trailing
spaces, CRLF); tests/test_seq.cpp asserts it, including comment and
blank-line preservation. Parsed event count for KDEAD.SEQ: 4 events.
tests/test_seq.cpp also runs a census over all 126 shipped sequences (under
FX_FA_ROOT): each round-trips, and every one of the 533 events decodes to a command that
resolves as a _SEQ* symbol in db/symbols/. The round-trip on its own proved none of that —
seq_serialize replays each line's own bytes, so a line it failed to understand round-tripped
exactly as well as one it did, which is how three events sat undecoded behind a green suite.
Census: 126 sequences, 533 events (3 space-indented, 166 sync, 62 relative);
bitmap=62 fadein=90 fadeout=175 font=28 palette=28 sound=45 video=103 wait=2
Related¶
Formats: 11K — the sound command plays PCM clips (^ prefix
= looping); MUS — the engine's _SEQmusic path triggers music
slots from sequence state.