Control Structures: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
(→‎<tt>[[while]]</tt>-Loop: clarified 0n & 1n diff. tween while & for loops)
m (Fix)
 
(30 intermediate revisions by 14 users not shown)
Line 1: Line 1:
{{TOC|side}}
'''Control Structures''' are [[Statement|statements]] which are used to control execution flow in the scripts. 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.
'''Control Structures''' are [[Statement|statements]] which are used to control execution flow in the scripts. 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.


''Note for advanced readers: in OFP/ArmA/VBS scripting language control structures are normal scripting commands, with no special handling compared to other commands. This is different from most imperative programming languages (like C), where control statements are implemented in the core language grammar. The "controlling" done by them is implemented by accepting [[Code|code]] as an argument. The complex control structures like "[[while]] ... [[do]] ..." are implemented using helper types, like [[While Type]].''
'''''Note for advanced readers:''' in the [[Virtual Reality]] scripting language control structures are normal scripting commands, with no special handling compared to other commands. This is different from most imperative programming languages (like C), where control statements are implemented in the core language grammar. The "controlling" done by them is implemented by accepting [[Code|code]] as an argument. The complex control structures like "[[while]] ... [[do]] ..." are implemented using helper types, like [[While Type]].''




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


* [[ArmA: Introduction to Scripting]]
* [[Introduction to Arma Scripting]]
* [[Variables]]
* [[Variables]]
* [[Operators]]
* [[Operators]]


== Conditional Structures ==
== Conditional Structures ==
Line 16: Line 18:
'''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.
'''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.


=== <tt>[[if]]</tt>-Statement ===
=== {{hl|[[if]]}}-Statement ===


The <tt>if</tt>-statement defines code that is only executed '''if''' a certain condition is met. The syntax of it looks like that:
The {{hl|if}}-statement defines code that is only executed '''if''' a certain condition is met. The syntax of it looks like that:


  if (CONDITION) then
  [[if]] (CONDITION) [[then]] {{cc|The round braces are optional}}
  {
  {
    STATEMENT;
STATEMENT;
    ...
...
  };
  };


* <tt>CONDITION</tt> is a [[Boolean]] [[Statement|statement]] or [[Variables|variable]] which returns either <tt>true</tt> or <tt>false</tt>. The code nested in the following [[Block|block]] is only executed if the condition is <tt>true</tt>, else ignored.
* {{hl|CONDITION}} is a [[Boolean]] [[Statement|statement]] or [[Variables|variable]] which returns either {{hl|true}} or {{hl|false}}. The code nested in the following [[Block|block]] is only executed if the condition is {{hl|true}}, else ignored.
* <tt>STATEMENT</tt> is a custom sequence of [[Statement|statements]]. That may be commands, assignments, control structures etc.
* {{hl|STATEMENT}} is a custom sequence of [[Statement|statements]]. That may be commands, assignments, control structures etc.


'''Example:'''
'''Example:'''
<sqf>
if (_temperature < 0) then
{
hint "Snow!";
};
</sqf>


[[if]] (_temperature < 0) [[then]]
In this example, first the value of {{hl|_temperature}} is checked:
{
    [[hint]] "Snow!"
};
 
 
In this example, first the value of <tt>_temperature</tt> is checked:
 
* If the value is 0 or greater than 0, the nested code is ignored.
* If the value is 0 or greater than 0, the nested code is ignored.
* If the value is less than 0, the command <tt>hint "Snow!";</tt> is executed.
* If the value is less than 0, the command {{hl|hint "Snow!";}} is executed.
 
==== Alternative Code ([[else]])====


You can also define ''alternative'' code that is executed, when the condition is ''not'' <tt>true</tt>.
==== Alternative Code ([[else]]) ====
You can also define ''alternative'' code that is executed, when the condition is ''not'' {{hl|true}}.


  if (CONDITION) then
  [[if]] (CONDITION) [[then]]
  {
  {
    STATEMENT;
STATEMENT1;
    ...
...
  }
  }
  else
  [[else]]
  {
  {
    STATEMENT;
STATEMENT2;
    ...
...
  };
  };


Here you have a second sequence of [[Statement|statements]] executed when <tt>CONDITION</tt> is <tt>false</tt>.
Another way of specifying an alternative code is done by feeding a 2-dimensional [[Array]] of [[Code]] into the [[then]] like this (but this alternative is CPU-heavier):
 
[[if]] (CONDITION) [[then]] [{STATEMENT1; ...}, {STATEMENT2; ...}];
 
In fact the above syntax with the Array is the only possible syntax as [[else]] does nothing else than taking the code to its left and the one to its right and packs them both into an [[Array]] of [[Code]] which is then fed into the [[then]] operator. But using [[else]] is just as fine and in most cases better in case of readability of your code.<br>
Here you have a second sequence of [[Statement|statements]] executed when {{hl|CONDITION}} is {{hl|false}}.


==== Conditional assignments ====
==== Conditional assignments ====
If...then structures can also be used to assign conditional values to variables:
{{hl|if..then}} structures can also be used to assign conditional values to variables:
<code>_living = if (alive player) then {true} else {false};</code>
<sqf>_living = if (alive player) then { true } else { false };</sqf>
 


==== SQS syntax (deprecated) ====
==== SQS syntax (deprecated) ====
{{Feature|warning|[[SQS Syntax]] is deprecated; [[SQF Syntax]] should be used instead.}}
Within [[SQS Syntax]] the use of [[goto]] labels is a way to execute more than one statement within if...then structures.


Within [[SQS syntax]] the use of [[goto]] labels is a way to execute more than one statement within if...then structures.
  [[if]] (CONDITION) [[then]] { [[goto]] "label" }
 
  [[if]] (CONDITION) [[then]] {[[goto]] "label"}
  ... some other statements
  ... some other statements
  #label
  #label
Line 77: Line 81:


'''Example 1: (without [[else]])'''
'''Example 1: (without [[else]])'''
<sqs>
if (_temperature < 0) then { goto "Snow" }
; ... some other statements


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




'''Example 2: (with [[else]])'''
'''Example 2: (with [[else]])'''
<sqs>
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"


[[if]] (_temperature < 0) [[then]] {[[goto]] "Snow"} [[else]] {[[goto]] "Sunshine"}
#Sunshine
... some other statements
  hint "No Snow but sunshine!"
Goto "Continue"
  echo "There is no snow!"
#Snow
  variable = text "Hey. No snow outside."
  [[hint]] "Snow!"
  goto "Continue"
  [[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 <tt>if</tt>-Statements ====
#Continue
; ...
</sqs>


Since the <tt>if</tt>-statement is itself a [[Statement|statement]], you can also create '''nested <tt>if</tt>-statements'''.
==== Nested {{hl|[[if]]}}-Statements ====
Since the {{hl|if}}-statement is itself a [[Statement|statement]], you can also create '''nested {{hl|if}}-statements'''.


'''Example:'''
'''Example:'''
<sqf>
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!";
};
</sqf>


if ([[alive]] [[player]]) then
{{ArgTitle|3|{{hl|[[switch]]}}-Statement|{{GVI|arma1|1.00}}}}
{
    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!";
};
 
=== <tt>[[switch]]</tt>-Statement ===
 
([[Armed Assault]] only)
 
In some cases you may want to check a [[Variables|variable]] for several values and execute different code depending on the value. With the above knowledge you could just write a sequence of <tt>if</tt>-statements.


if (_color == "blue") then
In some cases you may want to check a [[Variables|variable]] for several values and execute different code depending on the value.
{
With the above knowledge you could just write a sequence of {{hl|if}}-statements.
    hint "What a nice color";
<sqf>
}
if (_color == "blue") then
else
{
{
hint "What a nice color";
    if (_color == "red") then
}
    {
else
        hint "Don't you get aggressive?";
{
    }
if (_color == "red") then
};
{
hint "Don't you get aggressive?";
}
};
</sqf>


The more values you want to compare, the longer gets this sequence. That is why the simplified <tt>switch</tt>-statement was introduced.
The more values you want to compare, the longer gets this sequence. That is why the simplified {{hl|switch}}-statement was introduced.


The <tt>switch</tt>-statement compares a variable against different values:
The {{hl|switch}}-statement compares a variable against different values:


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


The structure compares <tt>VARIABLE</tt> against all given values (<tt>VALUE1</tt>, <tt>VALUE2</tt>, ...). If any of the values matches, the corresponding block of statements is executed.
The structure compares {{hl|VARIABLE}} against all given values ({{hl|VALUE1}}, {{hl|VALUE2}}, ...). If any of the values matches, the corresponding block of statements is executed.


'''Example:'''
'''Example:'''
<sqf>
[switch (_color) do
{
case "blue":
{
hint "What a nice color";
};
case "red":
{
hint "Don't you get aggressive?";
};
};
</sqf>


switch (_color) do
==== {{hl|[[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 {{hl|default}}-Block.
    case "blue":
    {
        hint "What a nice color";
    };
    case "red":
    {
        hint "Don't you get aggressive?";
    };
};
 
==== <tt>default</tt>-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 <tt>default</tt>-Block. Note that there is '''no colon''' after the <tt>default</tt> tag!
  [[switch]] (VARIABLE) [[do]]
 
  switch (VARIABLE) do
  {
  {
    case VALUE1:
[[case]] VALUE1:
    {
{
        STATEMENT;
STATEMENT;
        ...
...
    };
};
[[case]] VALUE2:
    case VALUE2:
{
    {
STATEMENT;
        STATEMENT;
...
        ...
};
    };
...
[[default]] {{cc|No colon behind '''default'''}}
    ...
{
STATEMENT;
    default
...
    {
};
        STATEMENT;
        ...
    };
  };
  };


==== variable assignments ====
==== Variable Assignments ====
Switch can be used to assign different values to a variable:
Switch can be used to assign different values to a variable:
<code>_color=switch (side player) do {case west: {"ColorGreen"}; case east: {"ColorRed"}; };</code>
<sqf>
private _color = switch (side player) do
{
case west: { "ColorGreen" };
case east: { "ColorRed" };
};
</sqf>
 


== Loops ==
== Loops ==
'''Loops''' are used to execute the same [[Block|code block]] for a specific or unspecific number of times.
'''Loops''' are used to execute the same [[Block|code block]] for a specific or unspecific number of times.


=== <tt>[[while]]</tt>-Loop ===
=== {{hl|[[while]]}}-Loop ===
This loop repeats the same code block as long as a given [[boolean]] condition is <tt>true</tt>.
 
This loop repeats the same code block as long as a given [[Boolean]] condition is {{hl|true}}.


  while {CONDITION} do
  [[while]] {CONDITION} [[do]] {{cc|Note the curly braces}}
  {
  {
    STATEMENT;
STATEMENT;
    ...
...
  };
  };


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


# <tt>CONDITION</tt> is evaluated. If it is <tt>true</tt>, go on to 2., else skip the block and go on with the code following the loop.
# {{hl|CONDITION}} is evaluated. If it is {{hl|true}}, go on to 2., else skip the block and go on with the code following the loop.
# Execution of all nested [[Statement|statements]]. Go back to 1.
# Execution of all nested [[Statement|statements]]. Go back to 1.


If <tt>CONDITION</tt> is <tt>false</tt> from the beginning on, the statements within the block of the loop will never be executed.
If {{hl|CONDITION}} is {{hl|false}} from the beginning on, the statements within the block of the loop will never be executed.


Because the test of the while expression takes place before each execution of the loop, a while loop executes zero or more times. This differs from the for loop, which executes one or more times.  
Because the test of the while expression takes place before each execution of the loop, a while loop executes zero or more times.


'''Example:'''
'''Example:'''
<sqf>
private _counter = 0;


_counter = 0;
while { _counter < 10 } do
{
while {_counter < 10} do
_counter = _counter + 1;
{
};
    _counter = _counter + 1;
</sqf>
};
 
=== <tt>[[for]]</tt>-Loop ===


(not available in [[OFP]])
{{ArgTitle|3|{{hl|[[for]]}}-Loop|{{GVI|arma1|1.00}}}}


The <tt>for</tt>-loop repeats the same code block for a specific number of times.
The {{hl|for}}-loop repeats the same code block for a specific number of times.


  for [{BEGIN}, {CONDITION}, {STEP}] do
  [[for]] [{BEGIN}, {CONDITION}, {STEP}] [[do]]
  {
  {
    STATEMENT;
STATEMENT;
    ...
...
  };
  };


* <tt>BEGIN</tt> is a number of [[Statement|statements]] executed ''before'' the loop starts
* {{hl|BEGIN}} is a number of [[Statement|statements]] executed ''before'' the loop starts
* <tt>CONDITION</tt> is a [[Boolean]] [[condition]] evaluated ''before'' each loop
* {{hl|CONDITION}} is a [[Boolean]] condition evaluated ''before'' each loop
* <tt>STEP</tt> is a number of statements executed ''after'' each loop
* {{hl|STEP}} is a number of statements executed ''after'' each loop


The loop processes as follows:
The loop processes as follows:


# <tt>BEGIN</tt> is executed
# {{hl|BEGIN}} is executed
# <tt>CONDITION</tt> is evaluated. If it is <tt>true</tt>, go on to 3., else skip the block and go on with the code following the loop.
# {{hl|CONDITION}} is evaluated. If it is {{hl|true}}, go on to 3., else skip the block and go on with the code following the loop.
# The statements in the code block are executed
# The statements in the code block are executed
# <tt>STEP</tt> is executed, go on to 2.
# {{hl|STEP}} is executed, go on to 2.


If <tt>CONDITION</tt> is <tt>false</tt> from the beginning on, the code block will never be executed.
If {{hl|CONDITION}} is {{hl|false}} from the beginning on, the code block will never be executed.


'''Example:'''
'''Example:'''
 
<sqf>
// a loop repeating 10 times
for [{ _i = 0 }, { _i < 10 }, { _i = _i + 1 }] do // a loop repeating 10 times
for [{_i=0}, {_i<10}, {_i=_i+1}] do
{
{
player globalChat format ["%1", _i];
    player globalChat format<nowiki>[</nowiki>"%1",_i<nowiki>]</nowiki>;
};
};
</sqf>
 
will display "0" then "1" then "2" then "3" then "4" then "5" then "6" then "7" then "8" then "9".
will display
 
0
1
2
3
4
5
6
7
8
9


'''Description:'''
'''Description:'''
# The variable {{hl|_i}} is set to 0
# The condition {{hl|_i < 10}} is evaluated, which is {{hl|true}} until {{hl|_i}} surpasses 9.
# The code {{hl|player globalChat _i;}} is executed
# The variable {{hl|_i}} is incremented by 1, back to step 2.


# The variable <tt>_i</tt> is set to 0
==== {{hl|[[for]]}}-{{hl|[[from]]}}-{{hl|[[to]]}}-Loop ====
# The condition <tt>_i<10</tt> is evaluated, which is <tt>true</tt> until <tt>_i</tt> surpasses 9.
There exists an alternate syntax of the {{hl|for}}-loop, which simplifies the last example a bit.
# The code <tt>player globalChat _i;</tt> is executed
# The variable <tt>_i</tt> is incremented by 1, back to step 2.
 
==== <tt>for</tt>-<tt>from</tt>-<tt>to</tt>-Loop ====
 
There exists an alternate syntax of the <tt>for</tt>-loop, which simplifies the last example a bit.


  for "VARNAME" from STARTVALUE to ENDVALUE do
  [[for]] "VARNAME" [[from]] STARTVALUE [[to]] ENDVALUE [[do]]
  {
  {
    STATEMENT;
STATEMENT;
    ...
...
  };
  };


* <tt>VARNAME</tt> is any name given to the variable used to count the loop
* {{hl|VARNAME}} is any name given to the variable used to count the loop
* <tt>STARTVALUE</tt> is a [[Number]] value given to the counter variable before the loop starts
* {{hl|STARTVALUE}} is a [[Number]] value given to the counter variable before the loop starts
* <tt>ENDVALUE</tt> is a [[Number]] value until which the counter is incremented/decremented
* {{hl|ENDVALUE}} is a [[Number]] value until which the counter is incremented
{{Feature|important| Note: Unless using a custom [[step]] as seen below, ENDVALUE must be greater than STARTVALUE for the loop to execute}}


The loop processes as follows:
The loop processes as follows:


#A variable with the name <tt>VARNAME</tt> is initialized with <tt>STARTVALUE</tt>
#A variable with the name {{hl|VARNAME}} is initialized with {{hl|STARTVALUE}}
#If <tt>VARNAME</tt> is not equal to <tt>ENDVALUE</tt>, the code block is executed
#If {{hl|VARNAME}} does not exceed {{hl|ENDVALUE}}, the code block will be executed.
#
#The variable {{hl|VARNAME}} is incremented by 1
##If <tt>ENDVALUE</tt> is greater than <tt>STARTVALUE</tt>, the variable <tt>VARNAME</tt> is incremented by 1
##If <tt>ENDVALUE</tt> is less than <tt>STARTVALUE</tt>, the variable <tt>VARNAME</tt> is decremented by 1
#Go back to step 2
#Go back to step 2


Line 322: Line 318:


'''Example:'''
'''Example:'''
 
<sqf>
// a loop repeating 10 times
for "_i" from 0 to 9 do // a loop repeating 10 times
for "_i" from 0 to 9 do
{
{
player globalChat format ["%1", _i];
    player globalChat format<nowiki>[</nowiki>"%1",_i<nowiki>]</nowiki>;
};
};
</sqf>


'''Description:'''
'''Description:'''
# {{hl|_i}} is set to 0
# {{hl|player globalChat 0}} is executed
# {{hl|_i}} is incremented by 1 => {{hl|_i}} is now 1
# Back to step 2


#<tt>_i</tt> is set to 0
==== {{hl|[[for]]}}-{{hl|[[from]]}}-{{hl|[[to]]}}-Loop with custom {{hl|[[step]]}} ====
#<tt>player globalChat 0</tt> is executed
The default step to increment the variable in {{hl|for}}-{{hl|from}}-{{hl|to}}-Loops is 1. You can set a custom step though using this syntax:
#<tt>_i</tt> is incremented by 1 => <tt>_i</tt> is now 1
#Back to step 2
 
==== <tt>for</tt>-<tt>from</tt>-<tt>to</tt>-Loop with custom <tt>step</tt> ====


The default step to increment the variable in <tt>for</tt>-<tt>from</tt>-<tt>to</tt>-Loops is 1. You can set a custom step though using this syntax:
  [[for]] "VARNAME" [[from]] STARTVALUE [[to]] ENDVALUE [[step]] STEP [[do]]
 
  for "VARNAME" from STARTVALUE to ENDVALUE step STEP do
  {
  {
    STATEMENT;
STATEMENT;
    ...
...
  };
  };


* <tt>STEP</tt> is a [[Number]] which defines the step by which the variable is incremented every loop
* {{hl|STEP}} is a [[Number]] which defines the step by which the variable is incremented every loop
{{Feature|important| Note: Utilizing this method, you can perform loops where VARNAME decrements by using a negative [[step]] value combined with a STARTVALUE that is greater than ENDVALUE}}


The rest is equal to the above section.
The rest is equal to the above section.


'''Example:'''
'''Example:'''
 
<sqf>
// a loop repeating 5 times
for "_i" from 0 to 9 step 2 do // a loop repeating 5 times
for "_i" from 0 to 9 step 2 do
{
{
player globalChat format ["%1", _i];
    player globalChat format<nowiki>[</nowiki>"%1",_i<nowiki>]</nowiki>;
};
};
</sqf>


'''Description:'''
'''Description:'''


#<tt>_i</tt> is set to 0
# {{hl|_i}} is set to 0
#<tt>player globalChat 0</tt> is executed
# {{hl|player globalChat 0}} is executed
#<tt>_i</tt> is incremented by 2 => <tt>_i</tt> is now 2
# {{hl|_i}} is incremented by 2 => {{hl|_i}} is now 2
#Back to step 2
# Back to step 2
 
=== <tt>[[forEach]]</tt>-Loop ===
 
You will often use the <tt>for</tt>-loop to increment over [[Array|arrays]].


_array = [unit1, unit2, unit3];
=== {{hl|[[forEach]]}}-Loop ===
for [{_i=0}, {_i < count _array}, {_i=_i+1}] do
{
    (_array select _i) setDamage 1;
};


The <tt>forEach</tt>-loop does exactly that: It repeats the same code block for every item in an array.
You will often use the {{hl|forEach}}-loop to increment over [[Array|arrays]].
It repeats the same code block for every item in an array.


  {
  {
    STATEMENT;
STATEMENT;
    ...
...
  }
  } [[forEach]] ARRAY;
forEach ARRAY;


The code block is executed exactly <tt>([[count]] ARRAY)</tt> times.
The code block is executed exactly {{hl|([[count]] ARRAY)}} times.


You may use the [[Magic Variables|magic variable]] <tt>_x</tt> within the code block, which always references to the current item of the array.
You may use the [[Magic Variables|magic variable]] {{hl|_x}} within the code block, which always references to the current item of the array.
Magic variable {{hl|_foreachindex}} contains current index of the _x element in ARRAY.


'''Example:'''
'''Example:'''
<sqf>
private _array = [unit1, unit2, unit3];


_array = [unit1, unit2, unit3];
{
_x setDamage 1;
{
}
    _x setDamage 1;
forEach _array;
}
</sqf>
forEach _array;


'''Description:'''
'''Description:'''
# In the first loop, the statement {{hl|unit1 setDamage 1;}} is executed
# In the second loop, the statement {{hl|unit2 setDamage 1;}} is executed
# In the third loop, the statement {{hl|unit3 setDamage 1;}} is executed
{{Feature|warning|Each iteration will be executed within one frame, even if it consists of multiple instructions. So be aware of large and/or complex code blocks!}}


# In the first loop, the statement <tt>unit1 setDamage 1;</tt> is executed
# In the second loop, the statement <tt>unit2 setDamage 1;</tt> is executed
# In the third loop, the statement <tt>unit3 setDamage 1;</tt> is executed


== Return Values ==
== 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.
Control structures always return the '''last [[expression]] evaluated''' within the structure.


'''Correct example:'''
'''Example:'''
<sqf>if (myCondition) then { myValueA; } else { myValueB; }; // returns myValueA or myValueB</sqf>


if (myCondition) then {myValueA} else {myValueB};
=> returns myValueA or myValueB


'''Incorrect example:'''
== See Also ==
 
if (myCondition) then {myValueA;} else {myValueB;};
=> returns [[Nothing]]
 
== See also ==


* [[:Category:Command Group: Program Flow|Command Group: Program Flow]]
* [[Statement]]
* [[Statement]]
* [[Expression]]
* [[Expression]]


[[Category: Syntax]]
[[Category: Syntax]]
[[Category: Scripting_Topics ]]
[[Category:Command_Group:_Program_Flow|{{uc:{{PAGENAME}}}}]]

Latest revision as of 22:29, 25 April 2024

Control Structures are statements which are used to control execution flow in the scripts. 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.

Note for advanced readers: in the Virtual Reality scripting language control structures are normal scripting commands, with no special handling compared to other commands. This is different from most imperative programming languages (like C), where control statements are implemented in the core language grammar. The "controlling" done by them is implemented by accepting code as an argument. The complex control structures like "while ... do ..." are implemented using helper types, like While Type.


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 // The round braces are optional
{
	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 0 or greater than 0, the nested code is ignored.
  • If the value is less than 0, the command hint "Snow!"; is executed.

Alternative Code (else)

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

if (CONDITION) then
{
	STATEMENT1;
	...
}
else
{
	STATEMENT2;
	...
};

Another way of specifying an alternative code is done by feeding a 2-dimensional Array of Code into the then like this (but this alternative is CPU-heavier):

if (CONDITION) then [{STATEMENT1; ...}, {STATEMENT2; ...}];

In fact the above syntax with the Array is the only possible syntax as else does nothing else than taking the code to its left and the one to its right and packs them both into an Array of Code which is then fed into the then operator. But using else is just as fine and in most cases better in case of readability of your code.
Here you have a second sequence of statements executed when CONDITION is false.

Conditional assignments

if..then structures can also be used to assign conditional values to variables:

_living = if (alive player) then { true } else { false };

SQS syntax (deprecated)

SQS Syntax is deprecated; SQF Syntax should be used instead.

Within SQS Syntax the use of goto labels is a way to execute more than one statement within if...then structures.

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

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 // No colon behind default
	{
		STATEMENT;
		...
	};
};

Variable Assignments

Switch can be used to assign different values to a variable:

private _color = switch (side player) do { case west: { "ColorGreen" }; case east: { "ColorRed" }; };


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 {CONDITION} do // Note the curly braces
{
	STATEMENT;
	...
};

Description:

  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.

Because the test of the while expression takes place before each execution of the loop, a while loop executes zero or more times.

Example:

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

for-Loop

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:

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

will display "0" then "1" then "2" then "3" then "4" then "5" then "6" then "7" then "8" then "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
Note: Unless using a custom step as seen below, ENDVALUE must be greater than STARTVALUE for the loop to execute

The loop processes as follows:

  1. A variable with the name VARNAME is initialized with STARTVALUE
  2. If VARNAME does not exceed ENDVALUE, the code block will be executed.
  3. The variable VARNAME is incremented by 1
  4. Go back to step 2

The following example is semantically equal to the last example.

Example:

for "_i" from 0 to 9 do // a loop repeating 10 times { player globalChat format ["%1", _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
Note: Utilizing this method, you can perform loops where VARNAME decrements by using a negative step value combined with a STARTVALUE that is greater than ENDVALUE

The rest is equal to the above section.

Example:

for "_i" from 0 to 9 step 2 do // a loop repeating 5 times { player globalChat format ["%1", _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

forEach-Loop

You will often use the forEach-loop to increment over arrays. 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. Magic variable _foreachindex contains current index of the _x element in ARRAY.

Example:

private _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
Each iteration will be executed within one frame, even if it consists of multiple instructions. So be aware of large and/or complex code blocks!


Return Values

Control structures always return the last expression evaluated within the structure.

Example:

if (myCondition) then { myValueA; } else { myValueB; }; // returns myValueA or myValueB


See Also