Control Structures

From Bohemia Interactive Community
Revision as of 18:34, 1 January 2007 by Kronzky (talk | contribs) (endless loop)
Jump to navigation Jump to search

Control Structures are special statements. They are sequences of scripting code which help to control complex procedures. You can use control structures to define code which is only executed under certain conditions or repeated for a couple of times.

Requirements

To fully understand this article you should read the following articles:

Conditional Structures

Conditional structures help to define code which is only executed under certain circumstances. Often you will write code that depends on the game state, on other code or other conditions.

if-Statement

The if-statement defines code that is only executed if a certain condition is met. The syntax of it looks like that:

if (CONDITION) then
{
    STATEMENT;
    ...
};
  • CONDITION is a Boolean statement or variable which returns either true or false. The code nested in the following block is only executed if the condition is true, else ignored.
  • STATEMENT is a custom sequence of statements. That may be commands, assignments, control structures etc.

Example:

if (_temperature < 0) then
{
    hint "Snow!"
};


In this example, first the value of _temperature is checked:

  • If the value is greater than 0, the nested code is ignored.
  • If the value is 0 or less than 0, the command hint "Snow!"; is executed.

Alternative Code

You can also define alternative code that is executed, when the condition is not true.

if (CONDITION) then
{
    STATEMENT;
    ...
}
else
{
    STATEMENT;
    ...
};

Here you have a second sequence of statements executed when CONDITION is false.

More than one statement (SQS syntax - deprecated)

A good way in SQS syntax is the use of labels (goto) when you need to execute more than one statement within if-code or else-code.

if (CONDITION) then {goto "label"}
... some other statements
#label
  statement1
  statement2
  statement3


Example 1: (without else)

if (_temperature < 0) then {goto "Snow"}
... some other statements
#Snow
  hint "Snow!"
  echo "There is snow!"
  variable = text "Hey. Snow outside."


Example 2: (with else)

if (_temperature < 0) then {goto "Snow"} else {goto "Sunshine"}
... some other statements
Goto "Continue"
#Snow
  hint "Snow!"
  echo "There is snow!"
  variable = text "Hey. Snow outside."
  Goto "Continue"
#Sunshine
  hint "No Snow but sunshine!"
  echo "There is no snow!"
  variable = text "Hey. No snow outside."
  Goto "Continue"
#Continue
 ...

Nested if-Statements

Since the if-statement is itself a statement, you can also create nested if-statements.

Example:

if (alive player) then
{
    if (someAmmo player) then
    {
        hint "The player is alive and has ammo!";
    }
    else
    {
        hint "The player is out of ammo!";
    }
}
else
{
    hint "The player is dead!";
};

switch-Statement

(Armed Assault only)

In some cases you may want to check a variable for several values and execute different code depending on the value. With the above knowledge you could just write a sequence of if-statements.

if (_color == "blue") then
{
    hint "What a nice color";
}
else
{
    if (_color == "red") then
    {
        hint "Don't you get aggressive?";
    }
};

The more values you want to compare, the longer gets this sequence. That is why the simplified switch-statement was introduced.

The switch-statement compares a variable against different values:

switch (VARIABLE) do
{
    case VALUE1:
    {
        STATEMENT;
        ...
    };

    case VALUE2:
    {
        STATEMENT;
        ...
    };

    ...
};

The structure compares VARIABLE against all given values (VALUE1, VALUE2, ...). If any of the values matches, the corresponding block of statements is executed.

Example:

switch (_color) do
{
    case "blue":
    {
        hint "What a nice color";
    };

    case "red":
    {
        hint "Don't you get aggressive?";
    };
};

default-Block

In some cases you may want to define alternative code that is executed, when none of the values matches. You can write this code in a default-Block.

switch (VARIABLE) do
{
    case VALUE1:
    {
        STATEMENT;
        ...
    };

    case VALUE2:
    {
        STATEMENT;
        ...
    };

    ...

    default
    {
        STATEMENT;
        ...
    };
};

Loops

Loops are used to execute the same code block for a specific or unspecific number of times.

while-Loop

This loop repeats the same code block as long as a given Boolean condition is true.

While loops are limited to 10,000 cycles. After that the loop is exited, no matter what the looping condition. A workaround to this limitation is to use a non-incrementing for...do loop.

while {CONDITION} do
{
    STATEMENT;
    ...
};

Note the curled braces for the condition. The loop processes as follow:

  1. CONDITION is evaluated. If it is true, go on to 2., else skip the block and go on with the code following the loop.
  2. Execution of all nested statements. Go back to 1.

If CONDITION is false from the beginning on, the statements within the block of the loop will never be executed.

Example:

_counter = 0;

while {_counter < 10} do
{
    _counter = _counter + 1;
};

for-Loop

(Armed Assault only)

The for-loop repeats the same code block for a specific number of times.

for [{BEGIN}, {CONDITION}, {STEP}] do
{
    STATEMENT;
    ...
};
  • BEGIN is a number of statements executed before the loop starts
  • CONDITION is a Boolean condition evaluated before each loop
  • STEP is a number of statements executed after each loop

The loop processes as follows:

  1. BEGIN is executed
  2. CONDITION is evaluated. If it is true, go on to 3., else skip the block and go on with the code following the loop.
  3. The statements in the code block are executed
  4. STEP is executed, go on to 2.

If CONDITION is false from the beginning on, the code block will never be executed.

Example:

// a loop repeating 10 times
for [{_i=0}, {_i<10}, {_i=_i+1}] do
{
    player globalChat _i;
};

will display

0
1
2
3
4
5
6
7
8
9

Description:

  1. The variable _i is set to 0
  2. The condition _i<10 is evaluated, which is true until _i surpasses 9.
  3. The code player globalChat _i; is executed
  4. The variable _i is incremented by 1, back to step 2.

for-from-to-Loop

There exists an alternate syntax of the for-loop, which simplifies the last example a bit.

for "VARNAME" from STARTVALUE to ENDVALUE do
{
    STATEMENT;
    ...
};
  • VARNAME is any name given to the variable used to count the loop
  • STARTVALUE is a Number value given to the counter variable before the loop starts
  • ENDVALUE is a Number value until which the counter is incremented/decremented

The loop processes as follows:

  1. A variable with the name VARNAME is initialized with STARTVALUE
  2. If VARNAME is not equal to ENDVALUE, the code block is executed
    1. If ENDVALUE is greater than STARTVALUE, the variable VARNAME is incremented by 1
    2. If ENDVALUE is less than STARTVALUE, the variable VARNAME is decremented by 1
  3. Go back to step 2

The following example is semantically equal to the last example.

Example:

// a loop repeating 10 times
for "_i" from 0 to 9 do
{
    player globalChat _i;
};

Description:

  1. _i is set to 0
  2. player globalChat 0 is executed
  3. _i is incremented by 1 => _i is now 1
  4. Back to step 2

for-from-to-Loop with custom step

The default step to increment the variable in for-from-to-Loops is 1. You can set a custom step though using this syntax:

for "VARNAME" from STARTVALUE to ENDVALUE step STEP do
{
    STATEMENT;
    ...
};
  • STEP is a Number which defines the step by which the variable is incremented every loop

The rest is equal to the above section.

Example:

// a loop repeating 5 times
for "_i" from 0 to 9 step 2 do
{
    player globalChat _i;
};

Description:

  1. _i is set to 0
  2. player globalChat 0 is executed
  3. _i is incremented by 2 => _i is now 2
  4. Back to step 2

Endless for-do Loop

To overcome the limitation of 10,000 cycles within while loops, you can use a non-incrementing for...do loop like this:

for [{_loop=0}, {_loop<1}, {_loop=_loop}] do
{
   sleep 0.001;
   STATEMENT;
   if (your_exit_condition) then {_loop=1;};
};

forEach-Loop

You will often use the for-loop to increment over arrays.

_array = [unit1, unit2, unit3];

for [{_i=0}, {_i < count _array}, {_i=_i+1}] do
{
    (_array select _i) setDamage 1;
};

The forEach-loop does exactly that: It repeats the same code block for every item in an array.

{
    STATEMENT;
    ...
}
forEach ARRAY;

The code block is executed exactly (count ARRAY) times.

You may use the magic variable _x within the code block, which always references to the current item of the array.

Example:

_array = [unit1, unit2, unit3];

{
    _x setDamage 1;
}
forEach _array;

Description:

  1. In the first loop, the statement unit1 setDamage 1; is executed
  2. In the second loop, the statement unit2 setDamage 1; is executed
  3. In the third loop, the statement unit3 setDamage 1; is executed

Return Values

Control structures always return the last expression evaluated within the structure. Note that there must not be a semicolon (;) after this value, otherwise Nothing is returned.

Correct example:

if (myCondition) then {myValueA} else {myValueB};

=> returns myValueA or myValueB

Incorrect example:

if (myCondition) then {myValueA;} else {myValueB;};

=> returns Nothing

See also