
Hello, and welcome to the Introduction to Functions.

This is considered intermediate:

To use functions you need to be a competent scripter, understand local and global variables, and be familiar with most of the commands in the command reference and have a few missions under your belt.
You also need a good understanding of the different variable types available in OFP. 

Most important: You need OFP: Resistance (at least version 1.85) in order to use functions. 

Still here?  Excellent.


What are functions?
===================


Functions are custom commands.
A 'function' is simply a chunk of code that does something, and then returns a value back to whatever 'called' that function.
You could use the words 'function' and 'command' interchangably, because commands and functions:

1.  Are called from within your mission, either in scripts or in waypoints, triggers etc.

2.  Can return values (The command GetPos, for example, returns an array representing a
    position).

OFPEC has two references:

The command reference (containing functions written by BIS that came with the game), and the function library (containing functions written and submitted by the community).
You could theoretically combine the two references into one, but to save confusion we keep them seperate.

Behind all of the commands that come with the game (ie that are listed in the command reference), there is a function.
The command itself (GetPos, for example) simply represents the function name.

When you use the GetPos command, a function (which has been loaded into your computer's memory by OFP) is triggered, and that function calculates and then returns the exact position of whatever unit you passed to the GetPos command.

The concept may be difficult to grasp unless you have a basic knowledge of game programming. If you start a game of OFP right now, on desert island for example, you are seeing an illusion.
Although everything looks stable, the ground is solid and the sky is blue, it is really just a facade.
Behind the image you see on your computer monitor there are  thousand of calculations happening, trying desperately to hold that illusion together.

Now, in addition to simply presenting you with an illusion, OFP is waiting.
It is waiting for you - waiting indefinitely until you (the player) or you (the mission designer) make something happen.

When you stop staring at your computer monitor (lost in wonderment due to your sudden realisation that the Desert Isand is just smoke and mirrors), move the mouse.
As soon as you do this, an event handler is triggered, which (in a microsecond) calculates how much the mouse moved by and where the pointer should be as a result.

When you call the GetPos command in your mission, a similar thing happens.
OFP suddenly realises that you have used the GetPos command, which means something needs to happen!
But don't worry, OFP won't be caught with it's pants down.

When you first started your mission, OFP loaded all of the commands (and associated functions) that you might want to use into memory.
You wouldn't be able to read these commands, because they are in 1's and 0's (binary machine language).
But, suppose you could read these 1's and 0's.  You'd see something like this:


function GetPos (object)
	{
  		...do some calculations to find where object is in the world...
  		return the position...
	}

function SetPos (object)
	{
  		set the position of obect...
	}

function GetDir (object)
	{
  		...quick! find the direction of object!...
  		return the direction...
	}

... and so on.


So now you can see that our commands are simply the names of functions stored in memory.

This tutorial is going to teach you how to add new commands to this big list of functions that is floating around whenever you run OFP.
We are going to add new, custom commands that you are going to make yourself!

First off, let me say that functions are very similar to scripts.
The functions that you write will be in text files, and OFP will process these text files line by line in the same way as it does with scripts.


So why not just use scripts?


Reason number one:  Speed
-------------------------

Remember how I said that functions are stored in memory, and written in machine language? Well, the language your computer best understands is binary, and the fastest place it can read it from is Random Access Memory (RAM).

Lets consider scripts for a second.  You should have written one by now.
They are text files, sitting in your mission directory, that you execute using the 'exec' command.
When you execute a script, here is what happens:

1.  The script is loaded from your hard drive into memory.
2.  The script is interpreted.  This means that OFP reads your script line by line, and
    converts it to binary (because OFP doesn't read english, or even czech).
3.  The script is then run by OFP, and OFP pauses every now and then whilst running your
    script to go and make sure the rest of the mission is running smoothly.
4.  Once your script has ended, OFP dumps it and promptly forgets it ever existed.

All that loading and interpreting takes time, time that could be better spent by OFP improving your frame rate.

So, how are functions different?
Well, at a glance, they are not really all that different.
Your function will still be written in a text file which resides in your mission's directory.

However:

1.  The function will be loaded and interpreted by OFP right at the start of the mission
    (rather than when you need to use it).
2.  The function sits in memory as 1's and 0's (binary machine language), and takes pride of
    place with all of the other functions (GetPos, SetPos, GetDir etc.) in memory for the
    duration of the mission.
3.  When the function is called, OFP stops everything and pays full attention to the
    function.  It executes the function as fast as it can, and then gets the hell out of
    there.
4.  The function stays in memory until the mission ends.

Functions are therefore faster because they are read from the hard disk only once, are executed from memory and more processor power is made available for the function to use.

(Author's note:  Functions that are not loaded at the very start of the mission, and loaded as required (via the command loadFile during the mission for example) are no faster than scripts.  As such, this tutorial encourages the use of pre-loading functions, and other methods will not be discussed).


Reason number two:  Returning values
------------------------------------

I've mentioned returning up above.
Functions produce an output (eg the result of the function), and this output is returned to whereever the function was called.
GetPos returns a position, and GetDir returns a number (that represents the direction of an object).

Now, you know as well as I do that you can't do the following in a script:

MyRealName = [snYpir] exec "GetName.sqs"

That just doesn't work!  However, if GetName was a function:

MyRealName = [snYpir] call GetName

And that is ok.
Ignore the syntax (how the command is written) for now - just understand that in the first attempt we were executing a script, and in the second we were calling a function (or calling a command, in other words).

Now because functions return values, you can use them in some very cool places.
Suppose we had a function that calculated the direction two units were facing, and returned 'true' when the two units see each other.
You could put something like this in the 'Condition' field of a trigger:

[unit1,unit2] call DoVisibility

Or, if you were waiting for the two units to see each other in a script, you could use:

@[unit1,unit2] call DoVisibility


This sort of functionality allows you to break down huge, complicated scripts in smaller functions, easier to understand and debug.


Reason number three:  Structured expressions
--------------------------------------------

You can skip this part if you want - this will only be of interest to people who have done a bit of programming before.

If, like me, you cringe at 'goto' statements (because they create messy, unstructured code) then you'll understand why I like functions.
Functions can only use sequential structured expressions.
This keeps the code nice and orderly, and prevents messy, inefficent coding.

To count in a script, you can do something messy like this:

; say snYpir 10 times
_counter = 0
#loop
hint "snYpir"
_counter = _counter + 1
? _counter < 10 : goto "loop"

But, in a function, you have to use sexy C-like syntax:

// say snYpir 10 times
_counter = 0; while "_counter < 10" do { _counter = _counter + 1; hint "snYpir"; };

This can be daunting for non-programmers, however (and that is why writing functions is considered advanced).


So what is the downside of using functions?


Downside 1:  You are unable to pause execution in a function.

Because of the way OFP handles functions, once a function begins nothing can pause it or slow it down.
If you try and put a time-delay loop in your function, your system will lock up. 

This occurs because all of your system's resources go towards running functions when they are called.
You can't even use the 'time' command to measure the passage of time, because when functions run there is no such thing as time!
Your function runs so fast that OFP can't get a word in either way, or even spare a micron to check how much the clock has ticked over.

This is a major drawback to using functions, I suppose.
But really, if you could pause time during function execution then you would be contradicting their true purpose - to get something done, and done quickly.


Downside 2:  You are limited as to how long OFP will let your function run for.

Just in case you were thinking 'Well that's ok, I'll simply pause OFP by counting to a billion or something' you are out of luck.
The function will crash with a 'generic error in expression' error.

This means that your function cannot be large.
A good rule of thumb is one function for one purpose.
Don't go trying to solve equations involving nuclear physics because OFP doesn't care, even if you are Einstein.


--------------------------------------------------------------------------------


Using functions
===============

Before we get into making our own functions, lets look at how to implement functions that other people have made.  There are three steps to using a function made by someone else:

1.  Download and copy the function's .sqf file to your mission's directory.

2.  Preprocess the function (load it into memory) in your mission's init.sqs file.

3.  Call the function whenever you need to use it, in accordance with the instructions for
    that particular function.

An '.sqf file' is simply a text file containing a list of instructions that detail how the given function will behave.
The extension could be anything, really .sqf is used so everyone understands what files functions are contained in, as opposed to scripts (.sqs files).
All OFP editors know that .sqs files are used to store scripts, and .sqf files are used to store function definitions.

We are now going to practice installing and using a function.

You should know of the distance command.
It returns the distance between two objects.

But, suppose you want the distance between two positions.
The distancePos function allows you to do just that.

Start a new mission on Desert Island.
Save the mission as 'function_test'.
Put distancePos.sqf in the function_test.Intro directory.

Open up the function_test.Intro directory in windows.
Right click on the background of the window, select 'New', and then select and click on 'Text Document'.
Rename the new document to 'init.sqs'.
Make sure you are not hiding filename extensions!.
If you think your operating system is hiding filename extensions, go to folder options and deselect that check box.

Step 1 is complete!

Open init.sqs and distancePos.sqf in notepad (or any other text editor).
We need to put the following in init.sqs to initially load and compile the functions:

distancePos = preprocessFile "distancePos.sqf"

Step 2 is complete!

We will actually implement the function call.
In the mission editor, place two soldiers (one will be the player and the other will be AI).
Make a trigger that activates on Radio Alpha and put 'Get distance' in the 'Text' box.
In the 'on activation' field put:

hint format["%1",[getpos player,getpos dude] call distancePos]

Step 3 is complete!

When you preview the mission and hit radio alpha, the distance between the two positions passed to distancePos will be displayed.
The new 'distancePos' command is usable anywhere in your mission.

If you wanted to make some other variable equal to the distance, you could use:

_the_distance = [getpos player,getpos dude] call distancePos

Or, if you wanted to wait in a script until the distance closes to less than 10m, you could use:

@[getpos player,getpos dude] call distancePos < 10
hint "The two units are closer than 10m to each other!"
