TO:R Data Map

event_script: event script modules

Source
docs/formats/event_script.md
SHA-256
e0767c10…0a0036a9

A compiled event script: one or more scripts of stack-machine bytecode, each with its functions and jump targets, plus the module's integer and float constants, variables and the lists of functions its opcodes start on other scripts. The script VM in the executable runs it (Event scripts). Modules sit as pakd entries in event/scene/*.dat and event/event_data.dat; they have no text magic, only a header word 0x8000000C. The layout is Gibbed's (Gibbed.TacticsOgre.ScriptFormats, written for the PSP release), which every module fits. Terms are as in the glossary.

Based on Every script module in event/, in event/scene/*.dat and event/event_data.dat; Gibbed's ScriptFileHeader.cs, ScriptHeader.cs, FunctionHeader.cs, VariableHeader.cs, VariableFlags.cs, RequestHeader.cs and ScriptFile.cs in reference_tools/Gibbed.LetUsClingTogether/projects/Gibbed.TacticsOgre.ScriptFormats/ (checked 2026-10-11); the unpacked executable, SHA-256 7b0230a11498f40396c9048345e7cfe0ef442cb7ca8faffc6f197920d2669599.
Checked 2026-10-12
Method Single-file C# programs over the decrypted files (with the toolchain's Containers library): find every pakd entry starting 0x8000000C, check the header fields Gibbed requires, walk every script's code with Gibbed's instruction encoding; static analysis with Ghidra 12.1.4 of the loader (0x14034e780, 0x14034e9d0) and the interpreter (0x14034a1b0); the R31 review of names (2026-10-11). 2026-10-12 (R19): the round trip, tor round-trip local/game/Data/event --docs docs, decoded all 1,656 modules in 826 files with the layouts and opcode sizes below and rebuilt them from their rows (Rebuilding) byte for byte (826/826 files), with no decode problem reported; tor export and tor read-back over the same folder (826/826 same as the original); DuckDB over the decoded data (data/game/event/**/*.event_script/). 2026-10-13 (R36): the round trip again, tor round-trip local/game/Data/event local/game/Data/WarrenReport --docs docs --quiet, 1,656/1,656 modules byte-identical; the decode finds a module by its first word, 0x8000000C, and refuses one whose total_size doesn't fit its entry, whose table offsets aren't inside total_size, or whose scripts' code doesn't walk with the Opcodes sizes from code_offset for instruction_count instructions. DuckDB over the exported data (each module's header.jsonl and scripts.jsonl, each file's entries.jsonl, and the modules' bytes in local/bin/event/, all from tor export) for the facts that cite it.
Name from Ours: the event code (region event/eventdata.cpp, 0x14034faa0–0x14035b880) hands a scene file's module to the bytecode interpreter (0x1402d0600 → 0x14034e780); "event" from the game's source path Event\EventData.cpp and folder Data/event/, "script" the plain word for interpreted bytecode.

Where modules are

0x64 bytes. Offsets are from the start of the module, and every _offset field is an offset from the start of the module.

Offset Size Type Name Meaning Confidence Source
0x00 4 u32 magic 0x8000000C in every module. The game doesn't read it. likely The round trip (R36: the decode finds every module by it); not read by 0x14034e780 or 0x14034e9d0. Gibbed splits it into SignatureValue and ExpectedVersion 12.
0x04 4 u32 total_size The module's size; a multiple of 16 in every module. confirmed DuckDB (R36): its entry's size − 16 in every module.
0x08 4 u32 author_offset NUL-terminated name, by its look of the script's author (isobe, tatsuchi, mtanaka, …; empty in some). likely DuckDB over the modules' bytes (R36). Gibbed AuthorNameOffset (Shift-JIS).
0x0C 4 u32 source_offset NUL-terminated source file name, unique per module (1_0.src, …). likely DuckDB over the modules' bytes (R36). Gibbed SourceNameOffset.
0x10 4 u32 unk_0x10_offset Points at the string 0 in every module; never read. — DuckDB over the modules' bytes (R36). Gibbed DateOffset.
0x14 4 u32 unk_0x14_offset A u16 count, then u16s; the loader sums them into the context at +0x14. What the sum is isn't shown. — 0x14034e780. Gibbed ScriptCountTableOffset.
0x18 4 u32 script_table_offset Scripts: an s32 count, then 0x30-byte script records. One script in most modules, more in the rest. likely The round trip (R36: the decode walks every record and its code); DuckDB over scripts.jsonl (R36). Gibbed ScriptTableOffset.
0x1C 4 u32 unk_0x1C 0 in every module. — DuckDB over header.jsonl (R36). Gibbed requires 0.
0x20 4 u32 int_table_offset An s32 count, then s32 constants that push_int_table (78) pushes. likely 0x14034e780 keeps it at context +0x58; 0x14034a1b0 case 0x4E. Gibbed IntTableOffset.
0x24 4 u32 float_table_offset An s32 count, then f32 constants that push_float_table (80) pushes. likely 0x14034e780 (context +0x60); case 0x50. Gibbed FloatTableOffset.
0x28 4 u32 variable_table_offset Variables: an s32 count, then 8-byte records. likely 0x14034e780 (context +0x68), read by 0x14034d500. Gibbed VariableTableOffset.
0x2C 4 u32 unk_0x2C_offset A u32 count, then 12-byte records that opcodes 76 and 77 read; the count is 0 in every module. likely 0x14034a1b0 (cases 0x4C, 0x4D, through context +0x70); DuckDB over the modules' bytes (R36). Gibbed Unknown2COffset (count must be 0); FF12's "tag".
0x30 4 u32 unk_0x30_offset Lists of functions to start: an s32 count, then u32 offsets; 0–17 lists per module. likely 0x14034a1b0 cases 0x5F, 0x61, 0x63. Gibbed RequestTablesOffset.
0x34 4 u32 module_vars_size Size of the module's variable storage: 0 in most modules, else 4–124. likely DuckDB over header.jsonl (R36). Gibbed FrameDataSize.
0x38 4 u32 module_vars_offset The module's own variable storage (scope 1, module): the context points at it unless the caller gave one. likely 0x14034e9d0 (context +0x30). Gibbed FrameDataOffset.
0x3C 4 u32 unk_0x3C 0 in every module. — DuckDB over header.jsonl (R36). Gibbed requires 0.
0x40 4 u32 unk_0x40_offset Storage of scope-3 variables. Gibbed: module vars offset + 0, 0x40 or 0x80 by module_vars_size. — 0x14034d500 (scope 3), 0x14034e9d0. Gibbed Unknown40Offset.
0x44 4 u32 unk_0x44_offset Unknown. 0 in most modules; in the rest, often a value inside the header, so not always an offset. — DuckDB over header.jsonl (R36). Gibbed Unknown44Offset.
0x48 4 u32 unk_0x48_offset Unknown; the loader keeps it at context +0x40. — 0x14034e780. Gibbed Unknown48Offset.
0x4C 4 u32 string_table_offset Start of the script and function names; the last region in every module. likely DuckDB over header.jsonl (R36: no other offset is past it). Gibbed StringTableOffset.
0x50 2 s16 autostart_script −1 in every module. When 0 or more, the loader starts that script's functions listed at autostart_offset. likely 0x14034e9d0; DuckDB over header.jsonl (R36). Gibbed requires −1.
0x52 2 s16 unk_0x52 0 in every module. — DuckDB over header.jsonl (R36). Gibbed requires 0.
0x54 4 u32 autostart_offset A u16 count, then s16 function indexes to start (−1 skipped). likely 0x14034e9d0. Gibbed Unknown54Offset.
0x58 4 u32 unk_0x58 0 in every module. — DuckDB over header.jsonl (R36). Gibbed requires 0.
0x5C 4 u32 unk_0x5C_offset Points at two u32s, 1 and 0, in every module. — DuckDB over the modules' bytes (R36). Gibbed requires 1, 0.
0x60 4 f32 unk_0x60 0 in every module. — DuckDB over header.jsonl (R36). Gibbed requires 0.

Scripts

0x30 bytes each, after the table's s32 count.

Offset Size Type Name Meaning Confidence Source
0x00 4 u32 name_offset The script's name, from string_table_offset. likely DuckDB over scripts.jsonl (R36: every script's _name_offset is a name). Gibbed ScriptHeader.
0x04 2 u16 table_index Unknown; no reader found. guess Gibbed TableIndex.
0x06 2 u16 unk_0x06 255. — DuckDB over scripts.jsonl (R36). Gibbed requires 255.
0x08 4 u32 code_offset The script's bytecode. likely The round trip (R36: the decode walks every script from it). Gibbed.
0x0C 4 s32 instruction_count Number of instructions (not bytes). likely The round trip (R36: the decode walks that many). Gibbed code_count.
0x10 4 u32 function_table_offset An s32 count, then {u32 name_offset, u32 code_offset} per function; code offsets are from the script's code start. likely DuckDB over the modules' bytes (R36: every function's name_offset, from string_table_offset, points at a name). Gibbed FunctionHeader.
0x14 4 u32 jump_table_offset An s32 count, then u32 code offsets that the jump opcodes index. likely 0x14046c3b0 (jump target by index; cases 0x51–0x57, 0x5A–0x5C, 0x60).
0x18 4 u32 unk_0x18_offset A u16 count, then s16s, −1 or a function index; no reader found. — Gibbed EventTableOffset (one function per "event slot").
0x1C 4 u32 unk_0x1C_offset Unknown. — Gibbed FrameOffset.
0x20 2 u16 unk_0x20 0. — Gibbed requires 0.
0x22 2 u16 unk_0x22 Unknown. — Gibbed Index.
0x24 12 raw[12] unk_0x24 0. — Gibbed requires 0.

Variables

8 bytes each, after the table's s32 count.

Offset Size Type Name Meaning Confidence Source
0x00 4 u32 location Bits 0–23: byte offset of the variable in its scope's storage (for an array, the offset in the module of its array record). Bits 24–26: the scope, below. Bit 27: pushed as a float. Bits 28–31: the type, 0 byte, 1 signed byte, 2 short, 3 unsigned short, 4 int, 5 float. likely 0x14034d500. Gibbed VariableFlags, VariableType, StackType.
0x04 4 u32 init_offset 0, or the offset of the variable's initial value: {u16 script index, u16, u32 size, data}, which the loader copies into the variable's storage. likely 0x14034e9d0 (loops over the variable table). Gibbed VariableHeader.Unknown.

Scope

Bits 24–26 of location: where the variable's storage is (0x14034d500, 0x14034e780).

Value Meaning Notes
0 context likely: a context field (+0x38). Gibbed Global, but scopes 4 and 5 are the global blocks.
1 module likely: the module's variable storage (module_vars_offset, context +0x30). Gibbed File.
2 script likely: storage from a callback, per script. Gibbed Script.
3 unk_3 the region at unk_0x40_offset
4 block_f2c690 the global block at 0x140F2C690
5 block_f2c890 the global block at 0x140F2C890
7 array likely: an array record {u32 location, s32 rank, s32 length[2]} at the offset, indexed by values popped from the stack. Gibbed Array.

The unk_0x30_offset lists

At unk_0x30_offset: an s32 count of lists, then each list's u32 offset. Each list is a u32 count, then its items, below: the functions opcodes 95, 97 and 99 start on other scripts' threads (0x14034de80, 0x14034df10, not read). Likely; Gibbed RequestHeader.

Offset Size Type Name Meaning Confidence Source
0x00 2 s16 script_index A script of this module, by its place in the script table. likely DuckDB over the decoded data: every item names a script the module has (R19). Gibbed RequestHeader.
0x02 2 s16 function_index A function of that script, by its place in its function table; 1–23 in the data. guess Gibbed RequestHeader; DuckDB (R19).

Code

Opcodes

Size counts the opcode byte and its operand, as the interpreter steps by it: the size of each opcode's record at 0x140C9E300 (exe.script_opcodes). Operand names the u16 that follows (Gibbed's operand_kind in the same records, Event scripts); — for none. Opcodes 0–2 have size 0 and 71 has size 1 though the interpreter reads a u16 operand for every opcode above 0x46; no script uses any of them (the R19 decode). Confidence: likely, from the records; the round trip shows only that every script walks with these sizes.

Opcode Size Operand Type
0 0 — —
1 0 — —
2 0 — —
3 1 — —
4 1 — —
5 1 — —
6 1 — —
7 1 — —
8 1 — —
9 1 — —
10 1 — —
11 1 — —
12 1 — —
13 1 — —
14 1 — —
15 1 — —
16 1 — —
17 1 — —
18 1 — —
19 1 — —
20 1 — —
21 1 — —
22 1 — —
23 1 — —
24 1 — —
25 1 — —
26 1 — —
27 1 — —
28 1 — —
29 1 — —
30 1 — —
31 1 — —
32 1 — —
33 1 — —
34 1 — —
35 1 — —
36 1 — —
37 1 — —
38 1 — —
39 1 — —
40 1 — —
41 1 — —
42 1 — —
43 1 — —
44 1 — —
45 1 — —
46 1 — —
47 1 — —
48 1 — —
49 1 — —
50 1 — —
51 1 — —
52 1 — —
53 1 — —
54 1 — —
55 1 — —
56 1 — —
57 1 — —
58 1 — —
59 1 — —
60 1 — —
61 1 — —
62 1 — —
63 1 — —
64 1 — —
65 1 — —
66 1 — —
67 1 — —
68 1 — —
69 1 — —
70 1 — —
71 1 — —
72 3 variable u16
73 3 variable u16
74 3 variable u16
75 3 variable u16
76 3 tag_index u16
77 3 tag_index u16
78 3 int_index u16
79 3 value s16
80 3 float_index u16
81 3 jump u16
82 3 jump u16
83 3 jump u16
84 3 jump u16
85 3 jump u16
86 3 jump u16
87 3 jump u16
88 3 native u16
89 3 native u16
90 3 jump u16
91 3 jump u16
92 3 jump u16
93 3 native u16
94 3 native u16
95 3 list u16
96 3 jump u16
97 3 list u16
98 3 unk_operand u16
99 3 list u16

Operands: variable an index into the variable table; tag_index into the unk_0x2C_offset table; int_index and float_index into the int and float tables; value the signed value pushed; jump an index into the script's jump table; native a native's number; list an index into the unk_0x30_offset lists; unk_operand read by no code (98's record has operand_kind 0).

Decoded data

tor export writes each module as a folder <n>.event_script/ with one .jsonl per section (toolchain/README.md (../../toolchain/README.md#decoded-data)):

File Rows
header.jsonl One: every Header field.
scripts.jsonl One per script record; _name_offset is the script's name.
variables.jsonl One per variable record.
unk_0x30_offset.jsonl One per item of the lists: list (which list), then the item's fields.
code.jsonl One per instruction: script, step (from 0 in each script), opcode with its name in _opcode (Event scripts), then its operand, named as in Opcodes; a native's operand native has its name in _native, from names.jsonl (../../data/exe/names.jsonl) (null for natives 44, 162 and 166, which have no handler of their own).

The other regions (the int, float and string tables, the function and jump tables, unk_0x14, unk_0x40, unk_0x44, unk_0x48, unk_0x5C, the module variables and the variables' initial values) aren't decoded yet; they are kept as they are (Rebuilding) and are in the entry's .bin.

Rebuilding

A module is rebuilt in place: its original bytes, with each decoded section's records written over their own bytes. confirmed for unchanged rows: all 1,656 modules rebuild byte for byte from their rows (see Method).

  1. header: every Header field, at 0x00–0x63.
  2. scripts, variables and the list items: each row's fields over its record, in order; a section keeps its row count (a list, its item count).
  3. code: each script's instructions, in order, from its first instruction's offset: the opcode byte, then the operand as its type. A script keeps its instruction count and its code's length in bytes, so an opcode may change only to one of the same size.
  4. Every other byte is kept, the pakd padding after total_size included.

Rows that would add, remove or move a record or an instruction, or change a script's code length, are refused with an error: that needs the regions after it moved and every offset into them rewritten, which the toolchain doesn't do yet (lead below). Offsets in edited rows (code_offset, name_offset …) are written as given and not checked.

How the game reads it

Leads