Sanny Builder
In English
Search
K

Functions

First native support for functions in GTA was added in Liberty City Stories. The games prior to that only had limited subroutines invoked with the gosub command. Those subroutines allowed to avoid code duplication; however, they were operating on the same scope as the code invoking them. Any variables used in a subroutine would alter the state of the script.
CLEO Library brought support for functions (dubbed scm func) in early versions, and it became important part of the modern scripting techniques. An SCM Function has its own variable stack. You are given additional 16 or 32 variables (depending on the game), none of them would clash with the local variables of the script calling the functions. CLEO5 improved SCM Functions a lot by completely isolating script and function state, adding support for string arguments, and more.
Sanny Builder 4 adds new syntactic element to the language to easily create and use SCM functions in the code.

Syntax

To make a new function, use the function keyword.
function <signature>
<body>
end
signature defines function's input parameters and their type, and also an optional return type. body is the code that runs when you call the function. A function must end with the end keyword.

Example

function sum(a: int, b: int): int
int result = a + b
return true result
end

Signature

A function's signature defines what types of input arguments the function receives and what type of value it returns.
Input arguments may be a primitive type int, float, or a class, e.g. Car or Pickup. String type is not supported. If a function has string arguments, they must be declared as int, because they are passed as pointers.
function foo(s: int)
print_help_string s
end
Native opcodes do not work with pointers to strings. In order to use them with string arguments inside function..end convert the pointer to a string, first as so:
function foo(gxt: int)
string key
string_format key "%s"
print_help key
end
A function may have zero parameters. If it has parameters, they are listed between (). Each parameter has a name and a type, separated by a :. Parameter declaration syntax is similar to that of var..end. Each parameter can be used as a function's local variable in the function body.
If the function returns something, its type has to be defined after the list of parameters (or the function name, if there are no parameters). E.g.:
function foo: float
function bar(i: int): int

Body

A function's body include all instructions executed when the main code calls the function. The function may have zero instructions. Function parameters can be referenced in the body as local variables. The function may create extra local variables and even new functions, available only within this function:
int x
function mod
int x = 5
end
x = 10
mod()
// x is still equal to 10

Return From Function

Function ends at the end keyword. You may exit early using the return keyword.
The return keyword is similar to the return command used in the SCM code to leave the gosub subroutine, but it acts differently in the functions.
In functions the return keyword is always followed by true or false.
return true
return false
true and false set the script's condition result. It can be used with IF..THEN to check on the function result and act accordingly:
function isDefined(val: int)
if val <> 0
then return true
else return false
end
end
if isDefined(5)
then
// result is true
else
// result is false
end
The example above can also be written in a more concise way:
function isDefined(val: int)
return val <> 0
end

Returning Values

The function may return one or multiple values, using the return keyword.
To define a function that returns something, add a : and a type at the end of the function signature:
function maxItems: int
To return a value use return followed by true or false and a value:
return true 5
return false 5
To read the returned value, a caller must provide a variable:
int value = maxItems() // value is 5
It can also be used with IF..END:
int value
if
value = maxItems()
then
// function returned true and a value
else
// function returned false
end

Declaring functions

Functions must be known to the compiler before they are used in the code.
Functions whose body precedes any call don't need a declaration:
function foo
end
foo // compiles
If, however, the function implementation is located later in the code, it will produce a compilation error, as the function name cannot be resolved.
foo // error, foo is not defined
function foo
end
To solve it, declare a function upfront using a define keyword:
define function <name>(<input types>):<output types>

Example

define function foo
define function setPos(float, float, z: float)
define function bar(int, float): int

Rules

  • forward declaration starts with the word DEFINE. Same word is used to declare elements of SCM header.
  • <name> must be a valid identifier.
  • input arguments may omit names and only list types (float, float, float).
  • forward declaration must have the same number of input and output parameters as the actual implementation. Types of parameters must match too.
  • each function may have only one forward declaration.