openclonk/docs/sdk/script/Funcs.xml

152 lines
11 KiB
XML

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE doc
SYSTEM '../../clonk.dtd'>
<?xml-stylesheet type="text/xsl" href="../../clonk.xsl"?>
<doc>
<title>Functions</title>
<h>Functions</h>
<part>
<text>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.</text>
<h>Parameters and Return Values</h>
<text>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 <funclink>return</funclink> statement.</text>
<h>Syntax</h>
<text>A simple function declaration could look like the following:</text>
<code>func MeineFunktion()
{
<funclink>Log</funclink>(&quot;Meine Funktion wurde aufgerufen!&quot;);
}</code>
<text>A function script is delimited by { } brackets. Preceding this script block is the <b>function declaration</b>. The declaration starts with "<code>func</code>", followed by the <b>function name</b> (here: "MeineFunktion"). In the ( ) brackets following the function name the <b>function parameters</b> can be declared (see below).</text>
<text>When calling this function the message "Meine Funktion wurde aufgerufen!" is displayed.</text>
<code>func ZeigeZahl(int zahl)
{
<funclink>Log</funclink>(&quot;ZeigeZahl wurde mit dem Parameter %d aufgerufen!&quot;, zahl);
}</code>
<text>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.</text>
<text>A call to the function "ZeigeZahl" could look like the following:</text>
<code>ZeigeZahl(42)</code>
<text>Performing this call example will have the message "ZeigeZahl wurde mit dem Parameter 42 aufgerufen!" displayed.</text>
<text>In this example, multiple parameters are declared:</text>
<code>func ZeigeSumme(zahl1, zahl2, zahl3, zahl4)
{
<funclink>Log</funclink>(&quot;Die Summe der ersten 4 Parameter ist %d.&quot;, zahl1 + zahl2 + zahl3 + zahl4);
}</code>
<text>There are four parameters with the names "zahl1" through "zahl4", separated by comma.</text>
<text>The message displays the sum of the four values passed. The call</text>
<code>ZeigeSumme(1, 2, 3, 4);</code>
<text>will result in the message "Die Summe der ersten 4 Parameter ist 10.".</text>
<h id="parametertypen">Parameter Types</h>
<text>You can specify the data type that is to be accepted for a given parameter. To do this, simply write the desired <emlink href="script/Typechecks.html">type name</emlink> before the parameter name:</text>
<code>func TypParameterFunktion(object Clonk, id def, int anzahl, string msg)
{
<emlink href="for.html">for</emlink>(var i = 0; i &lt; anzahl; i++)
<funclink>CreateContents</funclink>(def, Clonk);
Clonk-&gt;<funclink>Message</funclink>(msg);
}</code>
<text>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 <emlink href="script/Typechecks.html">Data Types</emlink>).</text>
<text>Making a call such as <code>TypParameterFunktion(1, Clonk, "Text", 5)</code> would cause a type checking error.</text>
<h id="spezial">Default Parameters</h>
<text>Unlike in other programming languages you can always pass fewer parameters than are declared in a function declaration.</text>
<text>The following calls to above function are perfectly legal:</text>
<code>ZeigeSumme(1, 2);
ZeigeSumme(1, 2, 3, 4, 5, 6);</code>
<text>In the first call, there are fewer parameters passed to the function than specified in the function declaration. The 'missing' parameters will simply contain <code>nil</code>.</text>
<text>If you leave out a parameter it will be the same as passing <code>nil</code>.</text>
<text>In the second call, on the other hand, there are <em>more</em> 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 <funclink>Par</funclink>() function.</text>
<h>Return Values</h>
<part>
<text>Every script function can pass a return value back to the caller. This is done using the <funclink>return</funclink>() function.</text>
<h>Example:</h>
<code>func Differenz(Zahl1, Zahl2)
{
<funclink>return</funclink>(<funclink>Abs</funclink>(Zahl1 - Zahl2));
}</code>
<text>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:</text>
<code>func ZeigeDifferenz(Zahl1, Zahl2)
{
<funclink>Log</funclink>(&quot;Die Differenz zwischen %d und %d beträgt %d!&quot;, Zahl1, Zahl2, Differenz(Zahl1, Zahl2));
} </code>
<text>The call "ZeigeDifferenz(5, 2)" will produce the message "Die Differenz zwischen 5 und 2 beträgt 3!".</text>
<text>If the function does not return a value, an implicit <code>return nil;</code> is implied.</text>
</part>
<!-- <h id="Aufrufb">Permissions</h>
<part>
<text>A function can have one of three levels of "calling permission". This will determine from where the function may be called:</text>
<text>
<table>
<row>
<col><code>public</code></col>
<col>may be called from the engine or any other script (default)</col>
</row>
<row>
<col><code>protected</code></col>
<col>may only be called from the engine or from within the same object script</col>
</row>
<row>
<col><code>private</code></col>
<col>may only be called from the same object script</col>
</row>
</table>
</text>
<text>The calling permissions are expected before the <code>func</code> marker:</text>
<code>private func PrivateFunktion()
{
// Diese Funktion darf nur im selben Script aufgerufen werden!
}</code>
<text>Calling this function from another object script will cause an error.</text>
<h>Remark</h>
<text>As in some cases it may seem necessary to call a protected function from another object script, there is a workaround through the <funclink>PrivateCall</funclink> and <funclink>ProtectedCall</funclink> functions.</text>
</part>-->
<h>Global Functions</h>
<part>
<text>A function is declared globally by placing the "<code>global</code>" keyword before the <code>func</code> marker.</text>
<text>A <code>global</code> 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.</text>
<h>Example:</h>
<code>global func CreateContents(id, obj, count)
{
var obj;
<emlink href="for.html">for</emlink>(var i = 0; i &lt; count; i++)
obj = <funclink>inherited</funclink>(id, obj);
return(obj);
}</code>
<text>This script redefines the engine function <funclink>CreateContents</funclink> while adding a new parameter declaration at the end of the parameter list which now allows to create multiple objects. Notice that <funclink>inherited</funclink> within this function refers to the overloaded engine function <funclink>CreateContents</funclink>.</text>
<h>Attention!</h>
<text>A global script function is executed with the context of the calling function. This means in particular that <funclink>this</funclink> is the calling object (if the global function was called from an object local scope), or <code>nil</code> (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:</text>
<code>local number;
func ObjektFunktion()
{
<funclink>Log</funclink>(&quot;ObjectFunktion: local number hat den Wert %d!&quot;, number);
}
global func GlobaleFunktion()
{
ObjectFunktion(); // Fehler!
number++; // Fehler!
}</code>
<text>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.</text>
<text>Notice: to call an object local function from a different context, use the syntax "<code>this()-&gt;function(...)</code>". This will execute the function in the specified object's context and only cause an error if the function really isn't available.</text>
</part>
<!-- <h id="referenzen">References</h>
<text>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.</text>
<text>Let's say we want to write a function returning the position (coordinates) of a player's highest ranking clonk. This cannot be done with a single return value, as we need to return an x and a y coordinate.</text>
<text>By using references as parameters this can be achieved:</text>
<code>func GetHiRankPosition(int plr, &amp;x, &amp;y)
{
var oHiRank = <funclink>GetHiRank</funclink>(plr);
x = <funclink>GetX</funclink>(oHiRank);
y = <funclink>GetY</funclink>(oHiRank);
}
func Aufruf()
{
var hiRankX, hiRankY;
GetHiRankPosition(0, hiRankX, hiRankY);
<funclink>Log</funclink>(&quot;Die Position des HiRanks von Spieler 1 ist: %d/%d&quot;, hiRankX, hiRankY);
}</code>
<text><code>x</code> and <code>y</code> in <code>GetHiRankPosition</code> are <strong>references</strong>, meaning when the called function modifies these values, the original variables (<code>hiRankX</code> and <code>hiRankY</code>) will be modified and the calling code will have the modified values. Notice, however, that you <em>have</em> to specify true variables as parameters for references. You cannot make a call such as "<code>GetHiRankPosition(0, hiRankX + 1, hiRankY)</code>" as in this case "<code>iHiRankX + 1</code>" is not a variable but a numeric result.</text>
<text>Notice that in C4Script "<code>&amp;</code>" is a data type of its own. You may not specify an extra data type with it, such as in "<code>int &amp;x</code>".</text>-->
</part>
<author>PeterW</author><date>2002-07</date>
<author>matthes</author><date>2004-06</date>
<author>Günther</author><date>2010-08</date>
</doc>