Scripting: Values – Arma Reforger
Lou Montana (talk | contribs) m (Text replacement - "<syntaxhighlight lang="C#">" to "<enforce>") |
Lou Montana (talk | contribs) m (Some wiki formatting) |
||
(12 intermediate revisions by 2 users not shown) | |||
Line 2: | Line 2: | ||
A '''value''' describes a ''data holder''; a value is either a '''variable''' (that can be changed) or a '''constant''' (that cannot be changed). | 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 {{hl|type identifier {{=}} value}} ({{hl|{{=}} value}} being optional). | Values are declared in Enfusion with a type, in format {{hl|type identifier {{=}} value}} (the {{hl|{{=}} value}} part being optional). | ||
Enforce Script uses strong types, which means a value's type cannot be changed along its lifetime. | |||
Line 16: | Line 17: | ||
The regular expression to be respected is: {{hl|^[a-zA-Z_][a-zA-Z0-9_]*$}} | The regular expression to be respected is: {{hl|^[a-zA-Z_][a-zA-Z0-9_]*$}} | ||
It is ''recommended'' to write variable identifiers in camelCase, (e.g {{hl|aNewVariable}}) and constants' in UPPER_CASE (e.g {{hl|A_NEW_CONSTANT}}). See Arma Reforger Variable | It is ''recommended'' to write variable identifiers in camelCase, (e.g {{hl|aNewVariable}}) and constants' in UPPER_CASE (e.g {{hl|A_NEW_CONSTANT}}). | ||
See {{Link|Arma Reforger:Scripting: Conventions#Variable}} for {{armaR}} naming conventions. | |||
<enforce> | <enforce> | ||
int myNumber = 10; | int myNumber = 10; | ||
Line 25: | Line 28: | ||
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 38: | ||
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 54: | ||
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 62: | ||
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 74: | ||
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 83: | ||
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 89: | Line 92: | ||
Notions: | Notions: | ||
* Passed by: content or reference - see above | * Passed by: content or reference - see above | ||
* Naming prefix: used in Object's ( | * Naming prefix: used in '''Object'''<nowiki/>'s value convention (See {{Link|Arma Reforger:Scripting: Conventions#Variable|conventions}}): {{hl|m_}} or {{hl|s_}} + '''prefix''' + VariableName (e.g: {{hl|m_'''b'''PlayerIsAlive {{=}} true}}){{Feature|informative|No prefix is used for constants in conventions.}} | ||
* Default value: the default value given when a value is declared without content (e.g: {{hl|int value}} - the variable here is 0, integer's default value) | * Default value: the default value given when a value is declared without content (e.g: {{hl|int value}} - the variable here is 0, integer's default value) | ||
Line 104: | Line 107: | ||
Print(variable); | Print(variable); | ||
} | } | ||
</ | </enforce> | ||
| | | | ||
<enforce> | <enforce> | ||
Line 113: | Line 116: | ||
Print(display); | Print(display); | ||
} | } | ||
</ | </enforce> | ||
|} | |} | ||
Line 190: | Line 193: | ||
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 213: | ||
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 245: | ||
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 261: | ||
{{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 inline>"abc" != "ABC"</enforce> | ||
}} | }} | ||
Line 265: | Line 268: | ||
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 287: | Line 290: | ||
UNCONSCIOUS, | UNCONSCIOUS, | ||
DEAD, | DEAD, | ||
} | } | ||
EHealthState healthState; // healthState is ALIVE (0) | EHealthState healthState; // healthState is ALIVE (0) | ||
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 303: | Line 306: | ||
UNCONSCIOUS = 50, | UNCONSCIOUS = 50, | ||
DEAD, // equals 51 | DEAD, // equals 51 | ||
} | } | ||
EHealthState healthState; // healthState is 0 (no corresponding enum) | EHealthState healthState; // healthState is 0 (no corresponding enum) | ||
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 {{Link|Arma Reforger:Scripting: Operators#<<|bit shifting}} for e.g flag usage | ||
enum ELifeStatus | enum ELifeStatus | ||
{ | { | ||
Line 316: | Line 319: | ||
HAS_HOUSE = 1 << 1, // 2 | HAS_HOUSE = 1 << 1, // 2 | ||
HAS_FOOD = 1 << 2, // 4 | HAS_FOOD = 1 << 2, // 4 | ||
} | } | ||
</ | </enforce> | ||
=== Vector === | === Vector === | ||
Line 332: | Line 335: | ||
<enforce> | <enforce> | ||
// there are three ways to create a vector | // there are three ways to create a vector | ||
vector | vector myVector0; // myVector0 is { 0, 0, 0 } | ||
vector | vector myVector1 = { 0, 1.5, 2 }; | ||
vector | vector myVector2 = "0 1.5 2"; | ||
myVector1 == myVector2; // true | |||
// | // editing one of the vector values | ||
vector myVector3 = myVector1; // '''copies''' the value | |||
myVector1 == myVector3; // true | |||
myVector1[1] = 42; // myVector1 is now { 0, 42, 2 } | |||
myVector1 == myVector3; // false | |||
// | // editing the whole vector | ||
myVector3 = { 0, 42, 2 }; // syntax "0 42 2" works too | |||
myVector1 == myVector3; // true | |||
</ | |||
// {{Link|https://en.wikipedia.org/wiki/Cross_product|cross product}} and {{Link|https://en.wikipedia.org/wiki/Dot_product|dot product}} in one operation | |||
vector crossProduct = vector1 * vector2; | |||
float dotProduct = vector1 * vector2; | |||
auto product = vector1 * vector2; // product is by default a vector | |||
</enforce> | |||
=== Array === | === Array === | ||
Line 353: | Line 361: | ||
Passed by: '''reference''' (dynamic array) or '''value''' (static array) | Passed by: '''reference''' (dynamic array) or '''value''' (static array) | ||
Naming prefix: '''a''' | Naming prefix: '''a''' for both | ||
Default value: null ('''not''' an empty array) | Default value: null ('''not''' an empty array) or static array filled with default item type value (e.g 0 for int, null for object, etc) | ||
Maximum size: | Maximum size: int.MAX | ||
An '''array''' is a list of values. In Enforce Script, an array can only hold one type of data (defined in its declaration). | An '''array''' is a list of values. In Enforce Script, an array can only hold one type of data (defined in its declaration). | ||
Line 375: | Line 383: | ||
dynamicArray[1] = "there"; // dynamicArray = { "Hello", "there" }; | dynamicArray[1] = "there"; // dynamicArray = { "Hello", "there" }; | ||
staticArray[1] = "there"; // staticArray | staticArray[1] = "there"; // staticArray = { "Hello", "there" }; | ||
// dynamic/static arrays cannot be directly compared for values; == would compare pointers (a.k.a is it the same array, not the same values) | // dynamic/static arrays cannot be directly compared for values; == would compare pointers (a.k.a is it the same array, not the same values) | ||
Line 381: | Line 389: | ||
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 410: | ||
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 445: | ||
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 449: | Line 457: | ||
A '''class''' is what defines an object's structure - said from the other end, an object is an '''instance''' of a class. | A '''class''' is what defines an object's structure - said from the other end, an object is an '''instance''' of a class. | ||
{{Feature|informative|For more information on classes and Object Oriented Programming, see | {{Feature|informative|For more information on classes and Object Oriented Programming, see {{Link|Arma Reforger:Object Oriented Programming Basics}} and {{Link|Object Oriented Programming Advanced Usage}}.}} | ||
Example: | Example: | ||
Line 457: | Line 465: | ||
protected int m_iHealth = 100; | protected int m_iHealth = 100; | ||
int | int GetHealth() | ||
{ | { | ||
return m_iHealth; | return m_iHealth; | ||
} | } | ||
bool | bool SetHealth(int health) | ||
{ | { | ||
if (health < 0 || health > 100) | if (health < 0 || health > 100) | ||
return false; | return false; | ||
m_iHealth = health; | m_iHealth = health; | ||
Line 478: | Line 484: | ||
ObjectClass myObjectInstance; // myObjectInstance is null | ObjectClass myObjectInstance; // myObjectInstance is null | ||
myObjectInstance = new ObjectClass(); | myObjectInstance = new ObjectClass(); | ||
int objectHealth = myObjectInstance. | int objectHealth = myObjectInstance.GetHealth(); | ||
Print(objectHealth); | Print(objectHealth); | ||
} | } | ||
</ | </enforce> | ||
=== Typename === | === Typename === | ||
Line 491: | Line 497: | ||
Default value: '''null''' | Default value: '''null''' | ||
A '''typename''' is class information | A '''typename''' is class information | ||
{{Wiki|WIP|talk about reflection?}} | |||
Example: | Example: | ||
<enforce> | <enforce> | ||
Line 504: | Line 510: | ||
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 537: | ||
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" | ||
! Incorrect | ! Incorrect | ||
! Correct | ! Correct | ||
! | ! Shorter but more expensive | ||
|- style="vertical-align: top" | |- style="vertical-align: top" | ||
| | | | ||
Line 550: | Line 556: | ||
} | } | ||
Print(message); // error: message variable is undefined here | Print(message); // error: message variable is undefined here | ||
</ | </enforce> | ||
| | | | ||
<enforce> | <enforce> | ||
Line 563: | Line 569: | ||
} | } | ||
Print(message); // OK | Print(message); // OK | ||
</ | </enforce> | ||
| | | | ||
<enforce> | <enforce> | ||
Line 576: | Line 582: | ||
Print(message); // OK | Print(message); // OK | ||
</ | </enforce> | ||
|} | |} | ||
Line 589: | Line 595: | ||
class Soldier_Base | class Soldier_Base | ||
{ | { | ||
int | int m_iScope = 0; | ||
} | } | ||
class B_Soldier_F : Soldier_Base | class B_Soldier_F : Soldier_Base | ||
{ | { | ||
int | int m_iScope = 2; | ||
void SayHello() | void SayHello() | ||
{ | { | ||
Line 606: | Line 612: | ||
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}} |
Latest revision as of 13:25, 2 October 2024
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 (the = value part being optional). Enforce 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 Scripting: Conventions - Variable for Arma Reforger 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 value convention (See conventions): m_ or s_ + prefix + VariableName (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 for both
Default value: null (not an empty array) or static array filled with default item type value (e.g 0 for int, null for object, etc)
Maximum size: int.MAX
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
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 | Shorter but more expensive |
---|---|---|
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.