Functions

A script function represents a length of script code which can be called (or executed) from the engine or from other places in script. Basically, all scripting of a scenario or object is organized in functions.

Parameters and Return Values

Up to ten parameters can be passed in a function call. These are values which can then be used inside function execution. On completion, a function can pass a single value (the return value) back to the caller using the return statement.

Syntax

A simple function declaration could look like the following:
func MyFunction()
{
  Log("My function has been called!");
}
A function script is delimited by { } brackets. Preceding this script block is the function declaration. The declaration starts with "func", followed by the function name (here: "MyFunction"). In the ( ) brackets following the function name the function parameters can be declared (see below).
When calling this function the message "My function has been called!" is displayed.
func ShowNumber(int number)
{
  Log("ShowNumber has been called with parameter %d!", number);
}
Here, a parameter with the name "number" of type "int" is declared. When this function is called with a parameter, "number" will contain the value passed. In this example, the passed value is displayed within a message.
A call to the function "ShowNumber" could look like the following:
ShowNumber(42);
Performing this call example will have the message "ShowNumber has been called with parameter 42!" displayed.
In this example, multiple parameters are declared:
func ShowSum(number1, number2, number3, number4)
{
  Log("The sum of the first four parameters is %d.", number1 + number2 + number3 + number4);
}
There are four parameters with the names "number1" through "number4", separated by comma.
The message displays the sum of the four values passed. The call
ShowSum(1, 2, 3, 4);
will result in the message "The sum of the first four parameters is 10.".
All functions also have a hidden parameter called this. When calling a function in another proplist (which can be an object, a definition, or any other type of proplist) with p -> Foo(); or p ->~ Foo();, the function Foo gets the proplist p as this.
func Foo(proplist self) {
	Log("this == self: %v", this == self);
}
func Bar() {
	var p = { Baz = this.Foo };
	p->Baz(p);
	p->Baz("not p");
	Foo(this);
}
Calling Bar in this script results in this output:
this == self: true
this == self: false
this == self: true
The last call to Foo shows the reason for this: Most of the functions in an object need that object to do something with it, and passing the object to every function would result in a lot of repetitive code.
Note for everyone familiar with previous versions of C4Script: When calling a function in a definition like Flint->Hit();, the definition is returned from this. In the Flint->Hit(); example, that will probably result in an error message from the engine like "passed proplist, but expected object", because the Hit function of the Flint is not designed to be called like that.

Parameter Types

You can specify the data type that is to be accepted for a given parameter. To do this, simply write the desired type name before the parameter name:
func TypeParameterFunction(object myClonk, id def, int count, string msg)
{
  for(var i = 0; i < count; i++)
    CreateContents(def, myClonk);
  myClonk->Message(msg);
}
This functions creates a given number of a given type of objects inside the specified clonk and displays a variable message above his head. The function declaration ensures that only those values will be accepted that can be converted to the declared parameter types (see also Data Types).
Making a call such as TypeParameterFunction(1, Clonk, "Text", 5) would cause a type checking error.

Default Parameters

Unlike in other programming languages you can always pass fewer parameters than are declared in a function declaration.
The following calls to above function are perfectly legal:
ShowSum(1, 2);
ShowSum(1, 2, 3, 4, 5, 6);
In the first call, there are fewer parameters passed to the function than specified in the function declaration. The 'missing' parameters will simply contain nil.
If you leave out a parameter it will be the same as passing nil.
In the second call, on the other hand, there are more parameters passed than specified. These are simply not used during function execution. However, a function is still able to access these extra parameters even if they weren't declared in the function declaration: to do this, you can use the Par() function.

Return Values

Every script function can pass a return value back to the caller. This is done using the return() function.

Example:

func Difference(number1, number2)
{
  return(Abs(number1 - number2));
}
Here the difference of the two passed parameters is calculated and the result is "returned". The calling script could now use this function to calculate the difference of any two numbers:
func ShowDifference(number1, number2)
{
  Log("The difference between %d and %d is %d!", number1, number2, Difference(number1, number2));
}	
The call "ShowDifference(5, 2)" will produce the message "The difference between 5 and 2 is 3!".
If the function does not return a value, an implicit return nil; is implied.

Global Functions

A function is declared globally by placing the "global" keyword before the func marker.
A global function can be called from any script. Its scope corresponds to that of the predefined engine functions. Global script functions can also be used to overload predefined engine functions in order to change their behaviour.

Example:

global func CreateContents(id, obj, count)
{
  var obj;
  for(var i = 0; i < count; i++)
    obj = inherited(id, obj);
  return obj;
}
This script redefines the engine function CreateContents while adding a new parameter declaration at the end of the parameter list which now allows to create multiple objects. Notice that inherited within this function refers to the overloaded engine function CreateContents.

Attention!

A global script function is executed with the context of the calling function. This means in particular that this is the calling object (if the global function was called from an object local scope), or nil (if called from a scenario script). Because of this, a global function may not use any object local variables or try to call any object local function. The following object script is illegal:
local number;
func ObjectFunction()
{
  Log("ObjectFunction: local number has the value %d!", number);
}

global func GlobalFunction()
{
  ObjectFunction(); // Error!
  number++; // Error!!
}
Both attempts to access the object local elements will fail. This is understandable because the globally declared function may have been called from any script, even from a scenario script or the script of another object. It will thus not know the declared variable or object function. As the calling context can't be safely known, the engine will throw an error.
Notice: to call an object local function from a different context, use the syntax "this->function(...)". This will execute the function in the specified object's context and only cause an error if the function really isn't available.
PeterW, 2002-07
matthes, 2004-06
Günther, 2010-08