Scripting: Values – Arma Reforger
Lou Montana (talk | contribs) m (Text replacement - "<syntaxhighlight lang="C#">" to "<enforce>") |
Lou Montana (talk | contribs) m (Text replacement - "</syntaxhighlight>" to "</enforce>") |
||
Line 25: | Line 25: | ||
int my#variable = 1; // wrong - contains a character that is not letter/number/underscore | int my#variable = 1; // wrong - contains a character that is not letter/number/underscore | ||
int auto = 1; // wrong - the "auto" keyword exists and cannot be replaced | int auto = 1; // wrong - the "auto" keyword exists and cannot be replaced | ||
</ | </enforce> | ||
Line 35: | Line 35: | ||
myNumber = 10; // myNumber is now 10 | myNumber = 10; // myNumber is now 10 | ||
</ | </enforce> | ||
It can also be directly created with a value: | It can also be directly created with a value: | ||
<enforce> | <enforce> | ||
int myNumber = 10; | int myNumber = 10; | ||
</ | </enforce> | ||
=== const === | === const === | ||
Line 51: | Line 51: | ||
value1 = "new value"; // value1 is now "new value" | value1 = "new value"; // value1 is now "new value" | ||
CONST_VALUE = "new value"; // error: cannot modify a const value | CONST_VALUE = "new value"; // error: cannot modify a const value | ||
</ | </enforce> | ||
An object (array, set, map, other class instance) can be {{hl|const}} yet still have its values changed - {{hl|const}} here only keeps the reference and does not "freeze" the object in place. | An object (array, set, map, other class instance) can be {{hl|const}} yet still have its values changed - {{hl|const}} here only keeps the reference and does not "freeze" the object in place. | ||
Line 59: | Line 59: | ||
STRINGS.Insert("Hello there"); // OK: the array remains the same, its content is changed | STRINGS.Insert("Hello there"); // OK: the array remains the same, its content is changed | ||
STRINGS = null; // error: cannot modify a const value | STRINGS = null; // error: cannot modify a const value | ||
</ | </enforce> | ||
Line 71: | Line 71: | ||
int myVar2 = myVar1; // myVar2 is 33 - it copied myValue1's content | int myVar2 = myVar1; // myVar2 is 33 - it copied myValue1's content | ||
myVar2 = 42; // myVar2 is now 42, myVar1 is still 33 - they are two different values | myVar2 = 42; // myVar2 is now 42, myVar1 is still 33 - they are two different values | ||
</ | </enforce> | ||
=== By Reference === | === By Reference === | ||
Line 80: | Line 80: | ||
array<int> myArray2 = myArray1; // myArray2 targets myArray1 object - value is not copied but referenced | array<int> myArray2 = myArray1; // myArray2 targets myArray1 object - value is not copied but referenced | ||
myArray2[0] = 99; // myArray1 is now { 99, 1, 2, 3 }; | myArray2[0] = 99; // myArray1 is now { 99, 1, 2, 3 }; | ||
</ | </enforce> | ||
Line 104: | Line 104: | ||
Print(variable); | Print(variable); | ||
} | } | ||
</ | </enforce> | ||
| | | | ||
<enforce> | <enforce> | ||
Line 113: | Line 113: | ||
Print(display); | Print(display); | ||
} | } | ||
</ | </enforce> | ||
|} | |} | ||
Line 190: | Line 190: | ||
bool myValue; // myValue is false | bool myValue; // myValue is false | ||
myValue = 10 > 0; // myValue is true | myValue = 10 > 0; // myValue is true | ||
</ | </enforce> | ||
Line 210: | Line 210: | ||
myValue = 20; // myValue is 20 | myValue = 20; // myValue is 20 | ||
myValue /= 3; // myValue is 6: 20 / 3 = 6.666… which gets floored to 6 (and not rounded) | myValue /= 3; // myValue is 6: 20 / 3 = 6.666… which gets floored to 6 (and not rounded) | ||
</ | </enforce> | ||
=== Float === | === Float === | ||
Line 242: | Line 242: | ||
originalValue == result; // returns false due to floating point precision | originalValue == result; // returns false due to floating point precision | ||
float.AlmostEqual(originalValue, result); // returns true | float.AlmostEqual(originalValue, result); // returns true | ||
</ | </enforce> | ||
=== String === | === String === | ||
Line 258: | Line 258: | ||
{{Feature|informative| | {{Feature|informative| | ||
* A string '''cannot''' be null | * A string '''cannot''' be null | ||
* String comparison is '''case-sensitive'''; e.g <enforce>"abc" != "ABC"</ | * String comparison is '''case-sensitive'''; e.g <enforce>"abc" != "ABC"</enforce> | ||
}} | }} | ||
Line 265: | Line 265: | ||
string username; // username is "" (empty string) | string username; // username is "" (empty string) | ||
username = "Player 1"; // username is "Player 1"; | username = "Player 1"; // username is "Player 1"; | ||
</ | </enforce> | ||
=== Enum === | === Enum === | ||
Line 292: | Line 292: | ||
healthState = EHealthState.UNCONSCIOUS; // healthState is UNCONSCIOUS (4) | healthState = EHealthState.UNCONSCIOUS; // healthState is UNCONSCIOUS (4) | ||
int myValue = EHealthState.ALIVE; // valid | int myValue = EHealthState.ALIVE; // valid | ||
</ | </enforce> | ||
By default, the first value is equal to 0 and the next values are incremented by 1. | By default, the first value is equal to 0 and the next values are incremented by 1. | ||
Line 308: | Line 308: | ||
healthState = EHealthState.INJURED; // healthState is 43 (INJURED) | healthState = EHealthState.INJURED; // healthState is 43 (INJURED) | ||
int myValue = EHealthState.ALIVE; // 42 | int myValue = EHealthState.ALIVE; // 42 | ||
</ | </enforce> | ||
<enforce> | <enforce> | ||
// an enum value can also be defined through bit shifting for e.g flag usage | // an enum value can also be defined through bit shifting for e.g flag usage | ||
Line 317: | Line 317: | ||
HAS_FOOD = 1 << 2, // 4 | HAS_FOOD = 1 << 2, // 4 | ||
}; | }; | ||
</ | </enforce> | ||
=== Vector === | === Vector === | ||
Line 347: | Line 347: | ||
myVector2 = { 0, 42, 2 }; // syntax "0 42 2" works too | myVector2 = { 0, 42, 2 }; // syntax "0 42 2" works too | ||
myVector == myVector2; // true | myVector == myVector2; // true | ||
</ | </enforce> | ||
=== Array === | === Array === | ||
Line 381: | Line 381: | ||
dynamicArray[0] == staticArray[0]; // true | dynamicArray[0] == staticArray[0]; // true | ||
dynamicArray[1] == staticArray[1]; // true | dynamicArray[1] == staticArray[1]; // true | ||
</ | </enforce> | ||
=== Set === | === Set === | ||
Line 402: | Line 402: | ||
setInstance.Get(0); // the values order is never guaranteed as it can change on value insertion! | setInstance.Get(0); // the values order is never guaranteed as it can change on value insertion! | ||
</ | </enforce> | ||
=== Map === | === Map === | ||
Line 437: | Line 437: | ||
mapInstance.Remove(5715); // removes "General Kenobi" from the map | mapInstance.Remove(5715); // removes "General Kenobi" from the map | ||
mapInstance.Contains(5715); // false | mapInstance.Contains(5715); // false | ||
</ | </enforce> | ||
=== Class === | === Class === | ||
Line 481: | Line 481: | ||
Print(objectHealth); | Print(objectHealth); | ||
} | } | ||
</ | </enforce> | ||
=== Typename === | === Typename === | ||
Line 504: | Line 504: | ||
string classname = TypeName(t); // returns "ObjectClass"; | string classname = TypeName(t); // returns "ObjectClass"; | ||
t = Type(classname); // returns ObjectClass typename too | t = Type(classname); // returns ObjectClass typename too | ||
</ | </enforce> | ||
Line 531: | Line 531: | ||
Print("Health has been set"); // newHealth is destroyed after this line (on closing the "SetDammage" scope) | Print("Health has been set"); // newHealth is destroyed after this line (on closing the "SetDammage" scope) | ||
} | } | ||
</ | </enforce> | ||
{| class="wikitable" | {| class="wikitable" | ||
Line 550: | Line 550: | ||
} | } | ||
Print(message); // error: message variable is undefined here | Print(message); // error: message variable is undefined here | ||
</ | </enforce> | ||
| | | | ||
<enforce> | <enforce> | ||
Line 563: | Line 563: | ||
} | } | ||
Print(message); // OK | Print(message); // OK | ||
</ | </enforce> | ||
| | | | ||
<enforce> | <enforce> | ||
Line 576: | Line 576: | ||
Print(message); // OK | Print(message); // OK | ||
</ | </enforce> | ||
|} | |} | ||
Line 606: | Line 606: | ||
B_Soldier_F mySoldierF = B_Soldier_F.Cast(aSoldier); | B_Soldier_F mySoldierF = B_Soldier_F.Cast(aSoldier); | ||
mySoldierF.SayHello(); // valid | mySoldierF.SayHello(); // valid | ||
</ | </enforce> | ||
{{GameCategory|armaR|Modding|Guidelines|Scripting}} | {{GameCategory|armaR|Modding|Guidelines|Scripting}} |
Revision as of 19:18, 30 July 2022
A value describes a data holder; a value is either a variable (that can be changed) or a constant (that cannot be changed).
Values are declared in Enfusion with a type, in format type identifier = value (= value being optional). Enfusion Script uses strong types, which means a value's type cannot be changed along its lifetime.
Identifier
An identifier is the actual name of a value; it identifies the value. The naming rules are:
- an identifier can be composed of ASCII letters, numbers and underscores
- an identifier must start with an underscore or a letter (cannot start with a number)
- an identifier is case-sensitive
- an identifier cannot be identical to a keyword
The regular expression to be respected is: ^[a-zA-Z_][a-zA-Z0-9_]*$
It is recommended to write variable identifiers in camelCase, (e.g aNewVariable) and constants' in UPPER_CASE (e.g A_NEW_CONSTANT). See Arma Reforger Variable Conventions for naming conventions.
Value Declaration
Declaring a value is done by using a type and an identifier:
It can also be directly created with a value:
const
A value can be made constant, meaning that it will remain the same along its lifetime.
An object (array, set, map, other class instance) can be const yet still have its values changed - const here only keeps the reference and does not "freeze" the object in place.
Passing a Value
By Content
By Reference
Types
Values can be of various types, listed below.
Notions:
- Passed by: content or reference - see above
- Naming prefix: used in Object's (member) variable convention: m_prefixVariableName (e.g: m_bPlayerIsAlive = true)
- Default value: the default value given when a value is declared without content (e.g: int value - the variable here is 0, integer's default value)
Incorrect | Correct |
---|---|
bool variable = true;
if (variable)
{
variable = "it works!"; // not - variable is and remains a boolean
Print(variable);
} |
Primitive Types
Type name | C++ equivalent | Range | Default value | Size (Bytes) |
---|---|---|---|---|
int | int32 | -2,147,483,648 through +2,147,483,647 | 0 | 4 |
float | float | ±1.18E-38 through ±3.402823E+38 | 0.0 | 4 |
bool | bool | true or false | false | 4 |
string | char* | - | "" (empty string) | 8 (pointer) + (length × 1 byte) |
vector | float[3] | like float | { 0.0, 0.0, 0.0 } | 8 (pointer) + (3 × float) 12* |
void | void | - | - | - |
class | Instance* | pointer to any script object | null | 8 |
typename | VarType* | pointer to type structure | null | 8 |
*the asterisk in C++ means a pointer.
Boolean
Passed by: value
Naming prefix: b
Default value: false
A boolean is a value that can be either true or false . For example, boolean result = 10 > 5; result can either be true or false.
Example:
Integer
Passed by: value
Naming prefix: i
Default value: 0
Range: -2,147,483,648 to 2,147,483,647
Description: An integer (or int) is a whole number, meaning a value without decimals. It can be positive or negative.
Example:
Float
Passed by: value
Naming prefix: f
Default value: 0.0
Range: 1.18 E-38 to 3.40 E+38
A float, or its full name floating-point number is a number that can have decimals.
Precision is a matter at hand when working with floats; do not expect exact calculations: 0.1 + 0.1 + 0.1 != 0.3 - rounding would be needed to have the result one can expect.
Example:
String
Passed by: value
Naming prefix: s
Default value: "" (empty string)
Maximum length: 2,147,483,647 characters
Description: a string is a sequence of characters; it supports the following escape characters:
Example:
Enum
Passed by: value
Naming prefix: e
Default value: 0 (which may not exist in the enum)
An enum is a value that offers a choice between defined options.
"Behind the curtains" it is also an integer that can be assigned to an int variable.
Examples:
By default, the first value is equal to 0 and the next values are incremented by 1.
Vector
Passed by: value
Naming prefix: v
Default value: { 0, 0, 0 }
A vector is a type that holds three float values. Two vectors can be compared with == for value comparison.
Example:
Array
Passed by: reference (dynamic array) or value (static array)
Naming prefix: a
Default value: null (not an empty array)
Maximum size:
An array is a list of values. In Enforce Script, an array can only hold one type of data (defined in its declaration).
There are two types of array in Enfusion:
- dynamic array: "list" that will extend the more items are added
- static array: fixed-size list of items - items can be changed, but the array size cannot
Example:
Set
Passed by: reference
Naming prefix: none
Default value: null (not an empty set)
A set is a list that ensures uniqueness of values. Due to this uniqueness check, item insertion is slower than for an Array; however, checking if an item is contained is faster.
Example:
Map
Passed by: reference
Naming prefix: m
Default value: null (not an empty map)
A map is a list of key-value pairs, also known as a dictionary. Two keys cannot be identical as they are used to index the values.
A float cannot be a map key.
Example:
Class
Passed by: reference
Naming prefix: none
Default value: null
A class is what defines an object's structure - said from the other end, an object is an instance of a class.
Example:
Typename
Passed by: reference
Naming prefix: none
Default value: null
A typename is class information (WIP: talk about reflection?)
Example:
Scope
A value has a lifetime, whether it is the game instance, mission or script duration; but it also has a scope that defines its existence and its accessibility.
Incorrect | Correct | Best |
---|---|---|
string message;
if (soldiersHealth > 75)
{
message = "I'm doing well";
}
else
{
message = "I don't feel so good";
}
Print(message); // OK |
string message = "I don't feel so good";
if (soldiersHealth > 75)
{
message = "I'm doing well";
}
Print(message); // OK |
Casting
A value can sometimes be returned as one of its inherited classes or interfaced type - it can be casted ("forced" into a type) if the underlying type is known.