1. Architectural Role & Engine Purpose
The QSC ("Q Script Code") format is the high-level human-readable script source language used by Innerloop designers to script all gameplay behaviors, AI patrols, weapon mechanics, trigger volumes, and camera cuts. In retail shipments of Project I.G.I., only binary .qvm files were included.
Naming — read this carefully. QSC stands for "Q Script Code": the
Q is the bare C-style letter used throughout the Innerloop C++ codebase (cf. QSC,
QVM, .qsc). It is not "Quake Script" and not
"Quest Script" — neither name appears in any engine string, header, or tool in the retail files. The
Innerloop QVM bytecode VM was derived from / inspired by the Quake virtual machine,
but the two are not directly related: QVM has its own LOOP container, its own 49-opcode
instruction set, and its own registrar-based native bridging.
Through reverse-engineering and the development of project-igi-converter, QSC source code is
reconstructed via complete control-flow graph (CFG) analysis, basic-block restructuring, and Abstract Syntax Tree (AST) synthesis.
2. Script Compilation & Decompilation AST Pipeline Diagram
The QSC language pipeline maps bidirectionally between structured high-level scripts and raw VM v8.5 bytecode:
3. Engine Script Architecture & Task Scheduler Diagram
The Innerloop script engine executes QSC scripts concurrently using an internal cooperative task scheduler:
4. Language Grammar & Structural Constructs
QSC is a semicolon-terminated, function-call-based language. A QSC file consists of a sequence of top-level function calls separated by semicolons:
FunctionName(arg1, arg2, NestedFunc(innerArg), "string arg");
Argument types:
- String: Enclosed in double quotes (
"hello"). Supports\"escape sequences. - Number: Integer or floating-point (e.g.
42,-3.14,1e5). - Boolean:
TRUEorFALSE(case-sensitive). - Function: Nested function calls act as arguments (evaluated recursively).
Parser limits: MAX_QSC_FUNCS 4096 maximum function nodes;
MAX_QSC_ARGS 65536 maximum argument nodes.
Mission behavior entries such as magicobjconfig.qsc use this same grammar with
Task_New(-1, "MagicObjConfig", name, model_id, TASKTYPE_XXX) calls that bind
mesh sub-parts (ATTAs) to runtime behaviors (see QVM & MagicObjects).
Native engine routines in IGI.EXE are invoked through these script function calls.
5. QSC Script Example (Function-Call Syntax)
Task(1, "patrol",
StatusText(1, "Guard patrolling"),
AIGraph(1, "patrol_route_01"),
Loop(3,
Goto(100.0, 200.0, 50.0),
Wait(5.0)
)
);
MagicObject config example (magicobjconfig.qsc):
Task_New(-1, "MagicObjConfig",
"name",
"model_id",
TASKTYPE_XXX
);