====== OFP Variables & Arrays ======
[[https://www.pmctactical.org/forum/viewforum.php?f=43|OFP Forum]], [[:ofp|OFP Home]], [[ofp:file_formats|OFP File Formats]], [[ofp:tools|OFP Tools]], [[ofp:missions|OFP Missions]], [[ofp:modeling|OFP 3D Modeling]], [[ofp:terrain|OFP Terrain]]
**Operation Flashpoint (OFP)** aka ArmA: Cold War Assault (CWA)
**Variables & Arrays** by Dinger
A variable can take the place of an absolute value in an expression and in effect refers to a value.
Since this signified value can vary, we call it a variable.
For example, 2 is an absolute value (numeric).
We can have the expression:
~2
to wait two seconds.
Now, we can set a variable, named A to the value 2:
A=2
~A
Unlike 2, which stays at the value 2, the value associated with variable A can change.
Fair enough. You knew that already.
====== Variables ======
Variables come in two flavors:
Local and Global.
**Local** variables are set apart by being preceded with an underline.
_variable
**Global** variables have no underline
variable
As the names imply, Local Variables are only accessible within the script in which they appear. Several scripts can use the same named local variables without interference. Global Variables are accessible throughout the mission, in all scripts and in the mission editor (for triggers, waypoints and such).
The Multiplayer engine does not automatically share variable values with other machines.
So, some Global Variables (numbers, booleans, units) can be shared across several computers in a multiplayer mission by using the PublicVariable command, with the syntax:
publicVariable "VariableName";
OFP admits of several types of variables, they are as follows:
**Numeric**
A floating point number
Format: A=0
Transformations to String: Format ["%1", NumericVariable]
Null Value: Nothing
Reserved Numeric Variables: (not a complete list)
Pi PI (3.14159)
time time since game started
_time time since script started
daytime time of day (in hours)
**String**
A series of characters, strings are case sensitive.
Format: A = "Hello There"
Null Value: ""
Transformations: Use the ForEach command.
e.g., TransString = "321"
"Numeric = " + TransString Foreach [0]
**Object/Unit**
An object, unit, GameLogic or Trigger in OFP.\\
Last I checked (this may be different for 1.75, in fact it probably is), you can't enter the absolute value of an object/or unit, (e.g., WEST:Alpha Black 1).\\
You can, via the editor, assign it an object name variable (in the name field).\\
Format: A = player\\
null Value: ObjNull\\
Transformations to string: Format ["%1", UnitVariable]\\
To Group: Group UnitVariable\\
**Reserved Object/Unit Names**:
Player: The current player\\
this: In the init field of a unit (or a waypoint), the name of the unit whose init field it is (or -- I think -- the group name for the waypoint).
**Group**
The group a unit belongs to.\\
Again, you can't get at this info directly (at least I don't think you can).\\
Format: A = group player\\
Transformations to string: Format ["%1", GroupVariable]\\
To an Array of Units: units GroupVariable\\
**Boolean**
True or False values\\
Format: A = False\\
nullvalue: none\\
**Other Variable Types**:
Markers\\
Sides
====== Some words on using variables ======
Any Boolean conditional on an undefined value will result false, so for example if you haven't defined UndefinedVariable, both:
Not (UndefinedVariable)
and
UndefinedVariable
will result FALSE.
For objects and groups, you can use IsNull to determine if the object/unit or group exists. All variables can be destroyed by being set to Nil
e.g.:
A = nil
will destroy variable A
====== Arrays ======
Arrays in OFP consist of a series of values assigned to one variable name.\\
Format: A = [value1, value2, value3...]\\
Transformations to string: Format ["%1", ArrayName]\\
Null value: NullArray = []
The elements in an array can be of any value type described above, including other arrays.
For example, you could have:
SampleArray = [52, "Barney", player, ["bite me", nearestbuilding getpos player]]
**Extracting values from an array**
You can get a single value out of an array using SELECT.
The format is:
Array Select PositionInArray
Array positions begin with zero. So in the samplearray above if we called:
B = SampleArray select 1
the value of B would be "Barney" and not 52.
You can get the size of an array by using COUNT:
Count SampleArray
This, for example, would return a value of 4
You can check for a value in an array by using IN:
"Barney" in SAmpleArray
Would return TRUE
Note: This doesn't work too well for nested arrays, so
"bite me" in sampleArray
would return FALSE
You can also count the number of occurrences of a given condition by using a variation of the COUNT command (See below: Actions on elements in arrays).
**Setting Values in an array**
First, an array has to be initialized. It can be done in one of three ways:
MyArray = []
MyArray = [value1, value2, value3]
MyArray = +MyOtherArray
I don't know if (and don't think) this is still the case, but the documentation tells us that if we set one variable to be equal to another array variable, both variables will refer to the same array.
In theory, this would mean:
a = []
b = []
a = b
b = [barney1, barney2]
would result in variable a being equal to [barney1, barney2] as well.
For this reason + forces OFP to make a copy of the array.
**Adding Values to an array**
You can add a value to the end of an array by using +. You can only add arrays to arrays.
So,
MyArray = [Barney1, Barney2]
MyArray = MyArray + [Barney3]
NOT
MyArray = MyArray + Barney3
**Subtracting Values from an array**
You can subtract a value from an array by using -. Note that every instance of that value will be deleted.
So,
[Barney1, Barney2, Barney1] - [Barney1]
will equal
[Barney2]
You can work around this using the Set command (See below).
**Resizing an array**
You can change the size of an array by using the Resize command.
MyArray Resize 5
If MyArray was [1,2,3,4,5,6], MyArray will now be [1,2,3,4,5]
If MyArray was [1,2,3,4], MyArray is now [1,2,3,4, ]
**Setting a value within an array**
You can change the value within an array by using the Set command:
MyArray set [ArrayPosition, Value]
so
["Fred", "Barney", "Wilma", "Thelma"] set [3, "Dino"]
will produce
["Fred", "Barney", "Wilma", "Dino"]
You can use Set to delete individual elements by the following trick:
Set the element you want to change to something recognizable and unique, like "DELETEME". Subtract ["DELETEME"] from the array.
MyArray set [3, "DELETEME"]
MyArray = MyArray - ["DELETEME"]
Will get rid of "Dino"
**Performing actions on elements in an array**
Count
"condition" Count MyArray
"condition" is in quotes, the condition to check for.
Use the reserved variable _x to take the place of the element of the array. This will return a numeric value.
So,
"_x > 0" count MyArray
will return a value of 1
Note that the condition is in quotes. Local variables will not work inside the condition, nor will absolute string values (because of the quotes). So convert local variables to globals before checking them with Count, and convert absolute string values to variables as well. So in order to count the appearances of "Barney" in an array, we'd do:
BarneyName = "Barney"
"_x == BarneyName" Count SAmpleArray
ForEach works similarly, but allows you to execute commands on each element.
For example, if I had a trigger named Deathcloud, set to (West Present), condition "This and Time > 1200, I could put this in the activation field:
"_x setdammage 1" ForEach thislist
(thislist is the array of units capable of activating the presence trigger). This would go through each of the units in the array thislist and kill them.
**Reserved arrays** (not a complete list)
**thislist** When in a trigger's fields, an array of the units who currently satisfy the conditions of the trigger.\\
**_this** The array passed to a script via the exec command.
That's right, in:
[] exec "MyScript.sqs";
The [] is not just for show -- it's a null array. Put something in there and you can access it via _this
_this does not have to be an array, for you can pass a single value to a script. But good scripting disciplines requires that it be an array.
For scripts started via the addaction command, _this has the following value:
[unit to whom action is attached, unit that called action, number of action on unit to whom action is attached]
====== Useful Arrays ======
**list triggername**: Calls up the array of units that currently satisfy a trigger's conditions. This is useful for area detection and the rest.\\
**units groupname**: Gives an array of units in a given group.
**Metavariables**
Metavariables are variables whose name in an instruction or operation is itself variable. Metavariables in OFP scripting are extremely rare (As I write this, I know of nobody else who uses them), but they are extremely powerful.
What we do is take advantage of the transformation rules above for extremely powerful and fast results.
"Count" and "ForEach" process strings, turning them into instructions and operations respectively.\\
"Format" turns any variable into a string.
So, for instance, to create a series of variables, starting with dude0, that corresponds to the (variable) number of units in the player's group, we can use this simple instruction: (note that double quotes "" can be used to signify quotes within quotes, beyond that level we have to use global variables)
tempnum = 0
"Format [""dude%1 = units group player select tempnum"", tempnum]; ForEach [0]; tempnum = tempnum + 1" ForEach units group player
Or to trap the laser designator dot:
Make a trigger called "detectlaser", and make it as big as the area you want to detect the laser in (like the whole map). Set the trigger to "Anybody Present Repeatedly" (an untested improvement is "Civilian Present Repeatedly", and put in the condition field:
this && "LaserTarget" CountType list detectlaser > 0
In the on activation field, put:
"Format [""LaserTarget%1 = _X"", ""LaserTarget"" CountType [_x]] ForEach [_x]" ForEach list DetectLaser; LaserInitialized = True
On deactivation, put:
LaserInitialized = False
Then when LaserInitialized is TRUE, metavariable LaserTarget1 will indicate the Laser Designator Dot.