Script
Script
Table of Contents
User Manual 1
Comments 1
Variable Declarations 1
Constant Declarations 2
Text Labels 3
Enumerations 3
Flow Control 3
Expressions 5
Operator Precedence 5
Programming Manual 6
Index a
ii
1.2 Variable Declarations Rage Scripting Language
1 User Manual
The scripting language is based upon the Rockstar North GTA scripting language. It is a simple imperative language which
looks a lot like BASIC.
1.1 Comments
You can do comments to end-of-line with //. You can bracket multi-line comments in /* and */.
All variable declarations must start with a typename. The common typenames are:
Variables may be declared in a special GLOBALS / ENDGLOBALS block, in which case they are true global variables that
are shared amongst all scripts. There can only be one GLOBALS block per script; it is intended to be placed inside a USING
file so that all scripts can see the same master list of globals. In fact, there can only be a single GLOBALS block for all
scripts in the game; this keeps all globals in a central place and allows the compiler to still assign static addresses.
Any variable declared outside any blocks and also not within a GLOBALS / ENDGLOBALS block is shared amongst all
instances of that script; this is like a static member variable in C++.
All variables are initialized to zero on creation. You may explicitly initialize any local variable to any valid expression. You can
declare more than one variable at once by separating the names with commas.
INT A, B // Declare two local variables initialize to zero
FLOAT C = 1.23 // Declare a local variable and initialize it.
VECTOR Pos = << C+2, 5, 2 >> // Note the special syntax for vector literals
Global and static variables can be initialized as well, but only to constant expressions (if they are integers) or constant
numbers (if they are floating-point).
When you wish to change the value of a variable after its creation you just assign a new value:
A = A + 1
Pos.y = Pos.y + 9.8
You cannot assign directly between INT and FLOAT variables. To assign a FLOAT to an INT, call the CEIL, FLOOR, or
ROUND function. To assign an INT to a FLOAT, call the TO_FLOAT function.
1
1.5 Special Functions and Commands Rage Scripting Language
The ++, --, +=, -=, *=, and /= shortcuts from C are available, but they are treated as statements, not expressions. Therefore
there is no distinction between preincrement or postincrement (since it is impossible to reference the value in an outer
expression) and either form is accepted.
The purpose of the handle types is to protect you from passing in the wrong type of object into a command.
You can also declare multi-dimensional arrays of objects. Array elements are accessed starting at element zero. Arrays can
be useful for holding lists of data such as waypoints or item prices.
You can introduce new structures (like VECTOR already is) with:
STRUCT PlayerData
INT AttackState, Health
INT AMMO
FLOAT Chances[4]
ENDSTRUCT
Structures may contain basic types or even previously defined nested structures.
You cannot currently initialize a structure variable when it is first defined; it is zero-filled for you but you have to initialize it
field-by-field yourself. I added structures in anticipation of minigames being written in the scripting language; I didn't want to
see lots of parallel arrays being used everywhere.
The TIMESTEP variable is a special FLOAT function available to all scripts; it contains the last time step (typically one or two
vertical blanking intervals). The TIMESTEP variable is used by the special +@ and -@ operators which automatically
multiply the right-hand side by the frame time.
The WAIT command accepts a single int parameter which is the number of milliseconds to block the currently running script.
WAIT 0 will always block the script for the remainder of the current game frame.
2
1.8 Flow Control Rage Scripting Language
Currently the scripting system executes 1000 instructions per frame. If your script doesnt pause then it will run round and
round its main loop until these are all used up (so stopping any other scripts running until the next frame).
script
//Main loop
WHILE true
// Do My Stuff Please Mr Script Engine
WAIT 0
ENDWHILE
endscript
You can also wait at any other point in the script.
In order to use the TIMERA, TIMERB, SETTIMERA, SETTIMERB, and WAIT commands, you must have an appropriate
USING statement in your declaration section. For RDR2 this is
USING "../../scripting/builtins.sc"
As mentioned elsewhere, NULL is a special variable which is compatible with all handle types.
1.7 Enumerations
You can introduce new enumerants into the language (as typenames):
ENUM TypeFlag
TF_DISABLED,
TF_ENABLED,
TF_READY
ENDENUM
Enumerants are all at global scope, and are only assignment- compatible with themselves. This is particularly useful for
making command calls more type-safe. There are currently no implicit or explicit conversions between ENUM types and
other ENUM types or integer types.
Enumerants will usually be supplied by programmers and will match the internal C++ code values, but designers are free to
define their own enumerants for clarity as well (for example, for assigning meaningful names to states).
3
1.9 Procedures and Functions Rage Scripting Language
// if true
ENDIF
There are three different looping constructs:
WHILE expr
// do something while expression is true
ENDWHILE
Note that a WHILE statement may not execute even once if the initial value of the expression turns out to be false.
REPEAT count varname
// do something 'count ' times
ENDREPEAT
The REPEAT statement accepts count and a variable name. The variable is initialized to zero and counts up until it reaches
the value, which must be an integer literal or constant.
FOR varname = start TO finish
// do something
ENDFOR
The FOR statement assigns varname to the value of start. While start is less than or equal to finish, it runs the body of the
loop. After every iteration, it adds one to start and checks again. Note that finish is re-evaluated on every loop iteration so it
may lead to unexpected behavior if it depends on something changing in the loop itself.
FOR varname = start TO finish STEP value
// do something
ENDFOR
This form is similar, except that you can count by something other than one. You can also count backwards with a negative
STEP value, in which case the loop continues as long as varname is greater than or equal to finish. The step value must be
a nonzero constant integer.
The next flow control is the RETURN statement, which simply exits the current script or function, returning a value to the
caller:
RETURN N+1
The final flow control is the EXIT statement, which simply exits the current script or procedure. Internally, EXIT is
semantically identical to RETURN 0 but is a necessary distinction to avoid parsing ambiguity.
EXIT
4
1.12 Why a Custom Language? Rage Scripting Language
All commands require their parameter list to be enclosed in parentheses, even if they don't take any parameters. This is to
remind you that you're making a function call, because otherwise the syntax is indistiguishable from normal variable access.
FLOAT T = TIMESTEP()
FLOAT Angle = ATAN2(Y,X)
FLOAT Mag = SQRT (X*X + Y*Y + Z*Z)
CREATE_ACTOR(SomeActor,SomePosition)
1.10 Expressions
The usual arithmetic operators work: +, -, *, /. % is used for modulo.
Multiple conditions can be tested at once by using the NOT, AND, and OR operators. You can mix and match them at will,
but use parentheses for clarity.
All expressions are left-associative except for the unary operators, which are right-associative. From highest precedence to
lowest: (all operators on the same line have equal precedence)
5
2 Rage Scripting Language
2 Programming Manual
This section is intended for use by programmers who are adding new commands to the script language itself.
You declare new commands (where a command is either a function or a procedure) using the NATIVE directive.
NATIVE FUNC FLOAT ABS(FLOAT F)
NATIVE PROC PRINTSTRING(STRING S)
NATIVE FUNC FLOAT ATAN2(FLOAT Y,FLOAT X)
You can also introduce new handle types into the language with a variant of the NATIVE syntax:
NATIVE SPRITE
NATIVE FUNC SPRITE CREATE_SPRITE(STRING Filename)
The handle types are compatible only with themselves, and help catch more potential problems at compile time.
The function should be void, accepting a reference to a non-const scrThread::Info object. See the code for specific
details and examples, but you basically pull the Param values out of the array, operate on them, and then set the Return
value if necessary. You can also modify the state of the thread so that it will become blocked and return immediately to
higher-level code. A script that is blocked by a command will immediately re-execute that command the next time it gets
scheduled.
There are also some templated wrapper functions in wrapper.h that can simplify integration.
6
3 Rage Scripting Language
Index
A
Advanced Variable Declarations 2
C
Comments 1
Constant Declarations 2
E
Enumerations 3
Expressions 5
F
Flow Control 3
O
Operator Precedence 5
P
Procedures and Functions 4
Programming Manual 6
S
Special Functions and Commands 2
T
Text Labels 3
U
User Manual 1
V
Variable Declarations 1
W
Why a Custom Language? 5