Scripting

TrackMania actually has an internal, custom scripting language. It appears to be used mostly for GUI purposes. So far, only two scripts have been found, in.

Scripts are stored in binary form in .gbx files of class CMwCmdBlockMain (0x01067000). They are quite easy to parse and decompile since they are not compiled to opcodes: instead, the AST (Abstract Syntax Tree) is serialized, preserving all the high-level programmatic structures like if, while... And not just that, even the original variable names are available in plain text.

If you haven't yet, read about the general .gbx file format first. Then you will have a much easier time understanding the rest of this article.

Features
Every CMwCmdBlockMain script operates in the context of a certain object instance (which we'll call the global instance), the type of which is stored in the script. It can use the fields and methods of this object to access and create other objects. However, there is no way to instantiate a class manually; creating objects has to happen through one of the provided methods.

The language itself is quite limited. It has basic programming constructs like //, variables and function calls. It supports working with integers, floating point numbers, vectors, matrices and strings. Math operators are however very limited (e.g. no modulo, let alone things like or ), and string functions are almost nonexistent. Also, loops can only work with steps of 1.

Terminology
TrackMania uses slightly weird naming conventions in its scripting system.
 * Instead of "setting" a variable, the variable is "affected".
 * Variables are in fact referred to as "idents", and a variable reference is known as an "ident interface".
 * A field or a method of an object is a "param". (So in other words, a "param" has nothing to do with function parameters.) A reference to one of these is a "param interface".
 * An access path starting at an object and going through a series of fields to reach a field or method is known as a "stack".
 * 4x3 transform matrices are known as "iso4"'s.
 * For some class names, the developers couldn't decide between English or French, so you'll see "CMwCmdExpNum" (clearly English since "number" is "nombre" in French), but also "CMwCmdExpInf" where Inf stands for "inférieur", French for "less".

Member IDs
The scripting language often makes use of member IDs. These are quite similar to chunk IDs: they are a 32-bit unsigned integer that indicates an engine, a class, and a part of that class. The difference is that the last three digits do not refer to a chunk but to a class member, which can be a field or a method.

The entire tree of engines and their classes has been extracted and is available on this wiki. All of the class members have *also* been extracted, however this results in a huge file which is too large for a wiki article. Instead, you can download it here.

Enumerations
Some class fields store an enumeration value. There is no separate definition of these enumerations; the possible enumeration values are stored together with the field information. Enumeration values are 0-based and are all named; see the class members download above.

Common structures
The following file structures occur quite commonly in scripts, so we list them first.

CBlockVariable
Like the name says, declares a variable in a code block.
 * string name
 * int32 ignored = 0
 * int32 type
 * if type is 4 or 5:
 * int32 classID

The type number is to be interpreted as follows:
 * 0: bool
 * 1: int32
 * 2: float
 * 3: string
 * 4: object reference
 * 5: weak object reference?
 * 6: vec2D
 * 7: vec3D
 * 8: iso4
 * 9: unknown

CMwCmdFunctionInterface
Not used in any known scripts, so the meaning of the fields is more of a guess.
 * int32 flag
 * if flag == 0:
 * noderef function
 * int32 numArgs
 * noderef args[numArgs]

CMwCmdIdentInterface
References a variable for reading or writing.
 * string varName

CMwCmdStack
Specifies an access path: a sequential series of fields, numerical array indices, and textual array indices. An important detail to note is that the access path is stored backwards. So for, the stack would contain ).
 * int32 numElems
 * int32 types[numElems]
 * for (i = 0 .. numElems - 1)
 * if types[i] == 0:
 * int32 memberID
 * else if types[i] == 1:
 * int32 numericalIndex
 * else if types[i] == 2:
 * int32 ignored = 0
 * string textualIndex

CMwCmdParamInterface
Specifies a base object, a number of CMwStacks for fixed access path parts, and a number of node references for dynamic path parts.

There are two versions available of this structure, 0 and 1. Which version is used is decided by the object that owns it.

Version 0:
 * int32 useGlobalInstance
 * if useGlobalInstance == 0:
 * string varName
 * int32 numIndexExprs
 * noderef indexExprs[numIndexExprs]
 * int32 numFixedIndexStacks
 * CMwStack fixedIndexStacks[numFixedIndexStacks]

Version 1:
 * int32 ignored = 0
 * int32 useGlobalInstance
 * if useGlobalInstance == 0:
 * string varName
 * noderef instance
 * int32 numIndexExprs
 * noderef indexExprs[numIndexExprs]
 * int32 numFixedIndexStacks
 * CMwStack fixedIndexStacks[numFixedIndexStacks]

The base object is determined as follows:
 * If useGlobalInstance is 1, the global instance is used
 * Otherwise, if the "instance" field is not null, it is used
 * Otherwise, the variable named "varName" is used.

The complete access path can be reconstructed with the following algorithm: string result = baseObject.ToString; for (int i = 0; i < numFixedIndexStacks; i++) {    for (int j = fixedIndexStacks[i].Items.Count - 1; j >= 0; j--)   // Stack items are stored backwards! {        if (j == 0 && i < numIndexExprs && indexExprs[i] != null) {            result += "[" + indexExprs[i].ToString + "]";     // index expr can be a number or a string }        else {            result += fixedIndexStacks[i].Items[j].ToString; }    } }

CMwCmdBlockMain (01067000)
The main script block, derived from CMwCmdBlock.

Chunk005
 * lookbackstring name?
 * int32 globalInstClassID
 * int32 numNodes1
 * noderef nodes1[numNodes1]
 * int32 numNodes2
 * noderef nodes2[numNodes2]
 * int32 numNodes3
 * noderef nodes3[numNodes3]

CMwCmdBlock (01030000)
A block of code (e.g. { ... } in C++ or C#).

Chunk004
 * int32 numStatements
 * noderef statements[numStatements]
 * int32 numDummyVars
 * CBlockVariable dummyVars[numDummyVars]
 * int32 numVars
 * CBlockVariable vars[numVars]

CMwCmdAffectIdent (01032000)
Assigns a value to a variable.

Chunk000
 * CMwCmdIdentInterface variable
 * noderef value
 * int32 isConst (0 or 1)

CMwCmdAffectIdentBool (01071000)
Simply derives from CMwCmdAffectIdent.

CMwCmdAffectIdentClass (01072000)
Simply derives from CMwCmdAffectIdent.

CMwCmdAffectIdentEnum (010A5000)
Simply derives from CMwCmdAffectIdent.

CMwCmdAffectIdentIso4 (01073000)
Simply derives from CMwCmdAffectIdent.

CMwCmdAffectIdentNum (01074000)
Derives from CMwCmdAffectIdent, but in addition:

Chunk000
 * int32 index

When assigning to a scalar variable, index is -1. For a 2D or 3D vector, indices 0, 1 and 2 mean the x, y and z component of the vector. For an iso4 (4x3 matrix), the index is the row-major index of the matrix field.

CMwCmdAffectIdentString (01075000)
Simply derives from CMwCmdAffectIdent.

CMwCmdAffectIdentVec2 (01076000)
Simply derives from CMwCmdAffectIdent.

CMwCmdAffectIdentVec3 (01077000)
Simply derives from CMwCmdAffectIdent.

CMwCmdAffectParam (01033000)
Assigns a value to a field of an object.

Chunk001
 * CMwCmdParamInterface1 paramInterface
 * noderef value
 * int32
 * int32

CMwCmdAffectParamBool (01078000)
Simply derives from CMwCmdAffectParam.

CMwCmdAffectParamClass (01079000)
Simply derives from CMwCmdAffectParam.

CMwCmdAffectParamEnum (0107A000)
Simply derives from CMwCmdAffectParam.

CMwCmdAffectParamIso4 (0107B000)
Simply derives from CMwCmdAffectParam.

CMwCmdAffectParamNum (0107C000)
Simply derives from CMwCmdAffectParam.

CMwCmdAffectParamString (0107D000)
Simply derives from CMwCmdAffectParam.

CMwCmdAffectParamVec2 (0107E000)
Simply derives from CMwCmdAffectParam.

CMwCmdAffectParamVec3 (0107F000)
Simply derives from CMwCmdAffectParam.

CMwCmdArrayAdd (010A0000)
Adds an element to an array.

Chunk001
 * CMwCmdParamInterface1 paramInterface
 * noderef element

CMwCmdArrayRemove (010A1000)
Removes an element from an array.

Chunk001
 * CMwCmdParamInterface1 paramInterface
 * noderef element

CMwCmdBlockCast (01065000)
Functionally identical to CMwCmdBlock.

Chunk000
 * string
 * int32

CMwCmdBlockFunction (01099000)
Simply derives from CMwCmdBlockProcedure.

CMwCmdBlockProcedure (01098000)
Appears to be unused in existing scripts, workings unknown.


 * int32 numNodes
 * noderef nodes[numNodes]

CMwCmdBreak (01095000)
Breaks out of a loop. Not found in existing scripts, meaning of fields unknown.

Chunk000
 * noderef

CMwCmdCall (01034000)
Calls a parameterless method on an object.

Chunk001
 * CMwCmdParamInterface1 paramInterface (refers to the method)

CMwCmdContinue (01096000)
Jumps to the next iteration of a loop. Not found in existing scripts, meaning of fields unknown.

Chunk000
 * noderef

CMwCmdExp (01038000)
Base class for expressions, contains no fields.

CMwCmdExpAdd (01039000)
Simply derives from CMwCmdExpNumBin.

CMwCmdExpAnd (0103A000)
Boolean "and" (&&) operator.

Chunk000
 * noderef value1 (CMwCmdExpBool or derived)
 * noderef value2 (CMwCmdExpBool or derived)

CMwCmdExpBool (0103B000)
A constant boolean value.

Chunk000
 * int32 value (0 = false, 1 = true)

CMwCmdExpBoolBin (01054000)
Base class for binary boolean operators.

Chunk0103B000

empty, overrides CMwCmdExpBool's chunk

Chunk000
 * noderef value1
 * noderef value2

CMwCmdExpBoolFunction (0109A000)
A function call with a boolean as result.

Chunk000
 * CMwCmdFunctionInterface funcInterface

CMwCmdExpBoolIdent (0103C000)
The value of a boolean-typed variable.

Chunk0103B000

empty, overrides CMwCmdExpBool's chunk

Chunk000
 * CMwCmdIdentInterface identInterface

CMwCmdExpBoolParam (0103D000)
The value of a boolean-typed object field.

Chunk0103B000

empty, overrides CMwCmdExpBool's chunk

Chunk000
 * CMwCmdParamInterface0 paramInterface

CMwCmdExpClass (01056000)
A null pointer of a specific class. Also serves as the base class for all expressions that return an object pointer, and stores their class type.

Chunk000
 * int32 classID

CMwCmdExpClassFunction (0109B000)
A function call that returns an object pointer.

Chunk01056000

empty

Chunk000
 * CMwCmdFunctionInterface funcInterface

CMwCmdExpClassIdent (01057000)
The value of a variable containing an object pointer.

Chunk000
 * CMwCmdIdentInterface identInterface

CMwCmdExpClassParam (01058000)
The value of an object field containing an object pointer.

Chunk001
 * CMwCmdParamInterface1 paramInterface

CMwCmdExpClassThis (010A2000)
The global instance pointer. No chunks.

CMwCmdExpDiff (0103E000)
The != operator (différent = not equal).

Chunk000
 * noderef value1
 * noderef value2

CMwCmdExpDiv (0103F000)
The division operator. Inherits from CMwCmdExpNumBin.

CMwCmdExpEgal (01040000)
The == operator (egal = equal).

Chunk000
 * noderef value1
 * noderef value2

CMwCmdExpEnum (01059000)
A value from an enumeration.

Chunk000
 * int32 value
 * int32 enumMemberID

CMwCmdExpEnumCastedNum (010A9000)
Casts a numerical expression to an enumeration value. Inherits from CMwCmdExpEnum.

Chunk000
 * noderef value (CMwCmdExpNum or derived)

CMwCmdExpEnumIdent (010A4000)
The value of a variable containing an enumeration value.

Chunk000
 * CMwCmdIdentInterface identInterface

CMwCmdExpEnumParam (0105A000)
The value of an object field containing an enumeration value.

Chunk001
 * CMwCmdParamInterface1 paramInterface

CMwCmdExpInf (01041000)
The < operator (inférieur = less). Inherits from CMwCmdExpBoolBin.

CMwCmdExpInfEgal (01042000)
The <= operator (inférieur = less, egal = equal). Inherits from CMwCmdExpBoolBin.

CMwCmdExpIso4 (01062000)
A 4x3 transform matrix.

Chunk000
 * noderef rotX (CMwCmdExpVec3 or derived)
 * noderef rotY (CMwCmdExpVec3 or derived)
 * noderef rotZ (CMwCmdExpVec3 or derived)
 * noderef pos  (CMwCmdExpVec3 or derived)

CMwCmdExpIso4Function (0109C000)
A function call that returns a 4x3 transform matrix.

ChunkChunk01062000

empty

Chunk000
 * CMwCmdFunctionInterface funcInterface

CMwCmdExpIso4Ident (01063000)
The value of a variable containing a 4x3 transform matrix.

ChunkChunk01062000

empty

Chunk000
 * CMwCmdIdentInterface identInterface

CMwCmdExpIso4Inverse (01090000)
Inverts a 4x3 transform matrix.

ChunkChunk01062000

empty

Chunk01063000
 * CMwCmdExpIso4 inputMatrix

CMwCmdExpIso4Mult (0108F000)
Multiplies two 4x3 transform matrices.

Chunk01062000

empty

Chunk01063000
 * noderef matrix1 (CMwCmdExpIso4 or derived)
 * noderef matrix2 (CMwCmdExpIso4 or derived)

CMwCmdExpIso4Param (01064000)
The value of an object field containing a 4x3 transform matrix.

Chunk001
 * CMwCmdParamInterface paramInterface

CMwCmdExpMult (01043000)
Multiplies two numbers. Derived from CMwCmdExpNumBin.

CMwCmdExpNeg (01044000)
Changes the sign of a number.

Chunk000
 * noderef inputNum (CMwCmdExpNum or derived)

CMwCmdExpNot (01045000)
Inverts a boolean value.

Chunk000
 * noderef inputBool (CMwCmdExpBool or derived)

CMwCmdExpNum (01046000)
A constant number.

Chunk000
 * int32 isFloat
 * if isFloat == 0:
 * int32 intValue
 * else:
 * float floatValue

CMwCmdExpNumBin (01053000)
Base class for binary operations on two numbers.

Chunk01046000
 * int32 isFloat

Chunk0000
 * noderef value1
 * noderef value2

CMwCmdExpNumCastedEnum (010A8000)
Casts an enumeration value to a number.

Chunk01046000
 * int32 isFloat

Chunk000
 * noderef enumValue (CMwCmdExpEnum or derived)

CMwCmdExpNumDotProduct2 (01091000)
The dot product of two 2D vectors.

Chunk01046000
 * int32 isFloat

Chunk01055000
 * noderef vec1 (CMwCmdExpVec2 or derived)
 * noderef vec2 (CMwCmdExpVec2 or derived)

CMwCmdExpNumDotProduct3 (01092000)
The dot product of two 3D vectors.

Chunk01046000
 * int32 isFloat

Chunk01055000
 * noderef vec1 (CMwCmdExpVec3 or derived)
 * noderef vec2 (CMwCmdExpVec3 or derived)

CMwCmdExpNumFunction (01055000)
The result of a function call that returns a number.

Chunk01046000
 * int32 isFloat

Chunk000
 * noderef numExpr (CMwCmdExpNum or derived)
 * int32 version
 * if version == 11:
 * CMwCmdFunctionInterface funcInterface

At the moment it seems that version is 10, and instead of a function call, an expression is referenced that does the calculation.

CMwCmdExpNumIdent (01047000)
The value of a variable containing a number.

Chunk01046000
 * int32 isFloat

Chunk001
 * CMwCmdIdentInterface identInterface
 * int32 index

When reading from a scalar variable, index is -1. For a 2D or 3D vector, index -1 resolves to the vector's length, and indices 0, 1 and 2 mean the x, y and z component of the vector. For an iso4 (4x3 matrix), the index is the row-major index of the matrix field.

CMwCmdExpNumParam (01048000)
The value of an object field containing a number.

Chunk01046000
 * int32 isFloat

Chunk001
 * CMwCmdParamInterface paramInterface
 * int32

CMwCmdExpOr (01049000)
The logical or (||) operator.

Chunk000
 * noderef value1 (CMwCmdExpBool or derived)
 * noderef value2 (CMwCmdExpBool or derived)

CMwCmdExpPower (0104A000)
Derived from CMwCmdExpNumBin. Calculates value1 to the power of value2.

CMwCmdExpString (0104E000)
A string literal.

Chunk000
 * string value

CMwCmdExpStringConcat (00105100)
Concatenates two values, resulting in a string. The input values don't have to be strings themselves.

Chunk0104E000

empty

Chunk100
 * noderef value1
 * noderef value2

CMwCmdExpStringFunction (0109D000)
The result of a function call that returns a string.

Chunk0104E000

empty

Chunk000
 * CMwCmdFunctionInterface funcInterface

CMwCmdExpStringIdent (0104F000)
The value of a variable containing a string.

Chunk0104E000

empty

Chunk000
 * CMwCmdIdentInterface identInterface

CMwCmdExpStringParam (01050000)
The value of an object field containing a string.

Chunk0104E000

empty

Chunk002
 * CMwCmdParamInterface paramInterface
 * int32

CMwCmdExpStringTrunc (010A3000)
Finds the first occurrence of a search string in an input string, then returns the input string reduced to everything left or right of this found searching string, including or excluding the search string itself.

Chunk0104E000

empty

Chunk000
 * noderef inputString (CMwCmdExpString or derived)
 * noderef searchString (CMwCmdExpString or derived)
 * noderef includeSearchString (CMwCmdExpBool or derived)
 * int32 left (1 = left, 0 = right)

CMwCmdExpStringUpDownCase (010A7000)
Converts a string to upper or lower case.

Chunk0104E000

empty

Chunk000
 * noderef inputString (CMwCmdExpString or derived)
 * int32 upper (1 = upper case, 0 = lower case)

CMwCmdExpSub (0104B000)
Derived from CMwCmdExpNumBin. Subtracts value2 from value1.

CMwCmdExpSup (0104C000)
The > operator (supérieur = greater). Derived from CMwCmdExpBoolBin.

CMwCmdExpSupEgal (0104D000)
The >= operator (supérieur = greater, egal = equal). Derived from CMwCmdExpBoolBin.

CMwCmdExpVec2 (0105C000)
Creates a 2D vector.

Chunk000
 * noderef x (CMwCmdExpNum or derived)
 * noderef y (CMwCmdExpNum or derived)

CMwCmdExpVec2Add (01085000)
Adds two 2D vectors.

Chunk0105C000

empty

Chunk000
 * noderef vec1 (CMwCmdExpVec2 or derived)
 * noderef vec2 (CMwCmdExpVec2 or derived)

CMwCmdExpVec2Function (0109E000)
The result of a function call that returns a 2D vector.

Chunk0105C000

empty

Chunk000
 * CMwCmdFunctionInterface funcInterface

CMwCmdExpVec2Ident (0105D000)
The value of a variable containing a 2D vector.

Chunk0105C000

empty

Chunk000
 * CMwCmdIdentInterface identInterface

CMwCmdExpVec2Mult (01088000)
Multiplies a 2D vector by a scalar factor.

Chunk0105C000

empty

Chunk000
 * noderef factor (CMwCmdExpNum or derived)
 * noderef vec (CMwCmdExpVec2 or derived)

CMwCmdExpVec2Neg (01087000)
Inverts the sign of all components of a 2D vector.

Chunk0105C000

empty

Chunk000
 * noderef vec (CMwCmdExpVec2 or derived)

CMwCmdExpVec2Param (0105E000)
The value of an object field containing a 2D vector.

Chunk0105C000

empty

Chunk001
 * CMwCmdParamInterface1 paramInterface

CMwCmdExpVec2Sub (01086000)
Subtracts vec2 from vec1.

Chunk0105C000

empty

Chunk000
 * noderef vec1 (CMwCmdExpVec2 or derived)
 * noderef vec2 (CMwCmdExpVec2 or derived)

CMwCmdExpVec3 (0105F000)
Creates a 3D vector.

Chunk000
 * noderef x (CMwCmdExpNum or derived)
 * noderef y (CMwCmdExpNum or derived)
 * noderef z (CMwCmdExpNum or derived)

CMwCmdExpVec3Add (01089000)
Adds two 3D vectors.

Chunk0105F000

empty

Chunk000
 * noderef vec1 (CMwCmdExpVec3 or derived)
 * noderef vec2 (CMwCmdExpVec3 or derived)

CMwCmdExpVec3Function (0109F000)
The result of a function call that returns a 3D vector.

Chunk0105F000

empty

Chunk000
 * CMwCmdFunctionInterface funcInterface

CMwCmdExpVec3Ident (01060000)
The value of a variable containing a 3D vector.

Chunk0105F000

empty

Chunk000
 * CMwCmdIdentInterface identInterface

CMwCmdExpVec3Mult (0108C000)
Multiplies a 3D vector with a scalar number.

Chunk0105F000

empty

Chunk000
 * noderef factor (CMwCmdExpNum or derived)
 * noderef vec (CMwCmdExpVec3 or derived)

CMwCmdExpVec3MultIso (0108D000)
Multiplies a 4x3 transform matrix with a 3D vector.

Chunk0105F000

empty

Chunk000
 * noderef vec (CMwCmdExpVec3 or derived)
 * noderef matrix (CMwCmdExpIso4 or derived)

CMwCmdExpVec3Neg (0108B000)
Inverts the sign of the components of a 3D vector.

Chunk0105F000

empty

Chunk000
 * noderef vec (CMwCmdExpVec3 or derived)

CMwCmdExpVec3Param (01061000)
The value of an object field containing a 3D vector.

Chunk0105F000

empty

Chunk001
 * CMwCmdParamInterface1 paramInterface

CMwCmdExpVec3Product (0108E000)
The cross product of two 3D vectors.

Chunk0105F000

empty

Chunk000
 * noderef vec1 (CMwCmdExpVec3 or derived)
 * noderef vec2 (CMwCmdExpVec3 or derived)

CMwCmdExpVec3Sub (0108A000)
Subtracts two 3D vectors.

Chunk0105F000

empty

Chunk000
 * noderef vec1 (CMwCmdExpVec3 or derived)
 * noderef vec2 (CMwCmdExpVec3 or derived)

CMwCmdFor (01035000)
A (very simple) loop. Loops an iterator variable from a start value up to and including an end value (the end value can be higher or lower than the start value). Only increments (or decrements) of 1 are supported.

Chunk000
 * string iteratorVarName (a variable reference, not a declaration; the declaration happens in the regular way, with a CBlockVariable, in the loop's body block)
 * noderef startValue (CMwCmdExpNum or derived)
 * noderef endValue (CMwCmdExpNum or derived)
 * noderef body (CMwCmdBlock)

CMwCmdIf (01036000)
A regular construct.

Chunk000
 * noderef condition (CMwCmdExpBool or derived)
 * noderef ifBlock (CMwCmdBlock)
 * noderef elseBlock (CMwCmdBlock; can be null)

CMwCmdLog (01084000)
Logs a debug string.

Chunk000
 * noderef text (CMwCmdExpString or derived)

CMwCmdProc (01097000)
A function call to an external function.

Chunk002
 * CMwCmdParamInterface methodParamInterface
 * int32 numArguments
 * noderef arguments[numArguments]
 * noderef

CMwCmdReturn (01094000)
Returns from a function.

Chunk000
 * noderef returnValue

CMwCmdSleep (01082000)
Pauses the script for a certain amount of time (probably in milliseconds).

Chunk000
 * noderef time (CMwCmdExpNum or derived)

CMwCmdSwitch (0105B000)
Performs an action depending on an enumeration value. Only enumerations are supported; numbers or strings are not. If the enumeration value is less than numCases and caseBlocks[value] is not null, that case is run. Otherwise, defaultBlock is run (if it is not null).

Chunk000
 * noderef enumValue (CMwCmdExpEnum or derived)
 * int32 numCases
 * noderef caseBlocks[numCases] (CMwCmdBlock)
 * noderef defaultBlock (CMwCmdBlock)

CMwCmdSwitchType (01066000)
Performs an action depending on the class type of a variable holding an object pointer. The case block corresponding to the first class ID that matches the object pointer's class (or one of its ancestor classes) is run. Otherwise, if no match is found, defaultBlock is run (if it is not null).

Chunk000
 * string varName
 * int32 numClassIDs
 * int32 classIDs[numClassIDs]
 * int32 numCases
 * noderef caseBlocks[numCases] (CMwCmdBlock)
 * noderef defaultBlock (CMwCmdBlock)

CMwCmdWait (01083000)
Halts the script until the next frame if the condition is true?

Chunk000
 * noderef condition (CMwCmdExpBool or derived)

CMwCmdWhile (01037000)
A regular loop. Keeps running the body block until the condition becomes false.

Chunk000
 * noderef condition (CMwCmdExpBool or derived)
 * noderef body (CMwCmdBlock)

Tools

 * TMPakTool is an open source tool that can read scripts from .pak files and decompile them to readable source code.