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() command.

Syntax

A simple function declaration could look like the following:
func MeineFunktion()
{
  Message("Meine Funktion wurde aufgerufen!");
}
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: "MeineFunktion"). In the ( ) brackets following the function name the function parameters can be declared (see below).
When calling this function the message "Meine Funktion wurde aufgerufen!" is displayed.
func ZeigeZahl(int zahl)
{
  Message("ZeigeZahl wurde mit dem Parameter %d aufgerufen!", 0, zahl);
}
Here, a parameter with the name "zahl" of type "int" is declared. When this function is called with a parameter, "zahl" will contain the value passed. In this example, the passed value is displayed within a message.
A call to the function "ZeigeZahl" could look like the following:
ZeigeZahl(42)
Performing this call example will have the message "ZeigeZahl wurde mit dem Parameter 42 aufgerufen!" displayed.
In this example, multiple parameters are declared:
func ZeigeSumme(zahl1, zahl2, zahl3, zahl4)
{
  Message("Die Summe der ersten 4 Parameter ist %d.", 0, zahl1 + zahl2 + zahl3 + zahl4);
}
There are four parameters with the names "zahl1" through "zahl4", separated by comma.
The message displays the sum of the four values passed. The call
ZeigeSumme(1, 2, 3, 4);
will result in the message "Die Summe der ersten 4 Parameter ist 10.".

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 TypParameterFunktion(object clnk, id def, int anzahl, string msg)
{
  for(var i = 0; i < anzahl; i++)
    CreateContents(def, clnk);
  Message(msg, clnk);
}
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 type checking).
Making a call such as TypParameterFunktion(1, CLNK, "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:
ZeigeSumme(1, 2);
ZeigeSumme(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 the value 0.
If you leave out a parameter it will be the same as passing the value 0.
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 Differenz(Zahl1, Zahl2)
{
  return(Abs(Zahl1 - Zahl2));
}
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 ZeigeDifferenz(Zahl1, Zahl2)
{
  Message("Die Differenz zwischen %d und %d beträgt %d!", Zahl1, Zahl2, Differenz(Zahl1, Zahl2));
}	
The call "ZeigeDifferenz(5, 2)" will produce the message "Die Differenz zwischen 5 und 2 beträgt 3!".

Permissions

A function can have one of three levels of "calling permission". This will determine from where the function may be called:
public may be called from the engine or any other script (default)
protected may only be called from the engine or from within the same object script
private may only be called from the same object script
The calling permissions are expected before the func marker:
private func PrivateFunktion()
{
  // Diese Funktion darf nur im selben Script aufgerufen werden!
}
Calling this function from another object script will cause an error.

Remark

As in some cases it may seem necessary to call a protected function from another object script, there is a workaround through the PrivateCall and ProtectedCall functions.

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, pObj, iCnt)
{
  var pObj;
  for(var i = 0; i < iCnt; i++)
    pObj = inherited(id, pObj);
  return(pObj);
}
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). 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 iNummer;
func ObjektFunktion()
{
  Log("ObjectFunktion: local iNummer hat den Wert %d!", iNummer);
}

global func GlobaleFunktion()
{
  ObjectFunktion(); // Fehler!
  iNummer++; // Fehler!
}
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.

References

In some cases, you don't want to pass the value of a variable as a parameter, but the "variable itself" so the function that is called can modify the original variable. This is done by passing a "reference" to the variable as parameter.
Let's say we want to write a function that returns the position (coordinates) of the player's clonk with the highest rank. This cannot be done with a single return value, as we need to return x and a coordinates.
By using references as parameters this can be achieved:
func GetHiRankPosition(int plr, &x, &y)
{
  var oHiRank = GetHiRank(plr);
  x = GetX(oHiRank);
  y = GetY(oHiRank);
}

func Aufruf()
{
  var iHiRankX, iHiRankY;
  GetHiRankPosition(0, iHiRankX, iHiRankY);
  Message("Die Position des HiRanks von Spieler 1 ist: %d/%d", 0, iHiRankX, iHiRankY);
}
x and y in GetHiRankPosition are references, meaning when the called function modifies these values, the original variables (iHiRankX and iHiRankY) will be modified and the calling code will have the modified values. Notice, however, that you have to specify true variables as parameters for references. You cannot make a call such as "GetHiRankPosition(0, iHiRankX + 1, iHiRankY)" as in this case "iHiRankX + 1" is not a variable but a numeric result!
Notice that in C4Script "&" is a data type of its own. You may not specify an extra data type with it, such as in "int &x"!
PeterW, Juli 2002
matthes, Juni 2004