Scripting: Values – Arma Reforger
Lou Montana (talk | contribs) m (Text replacement - "lang="cpp">" to "lang="C#">") |
Lou Montana (talk | contribs) m (Add value prefix cheat sheet) |
||
(15 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{TOC|side}} | {{TOC|side}} | ||
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. | 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> | |||
int myNumber = 10; | int myNumber = 10; | ||
int _myNumber = 10; | int _myNumber = 10; | ||
int myNUMBER = 10; // different from myNumber | int myNUMBER = 10; // different from myNumber | ||
int 1number = 1; // wrong - starts with a number | int 1number = 1; // wrong - starts with a number | ||
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 31: | Line 34: | ||
Declaring a value is done by using a type and an identifier: | Declaring a value is done by using a type and an identifier: | ||
< | <enforce> | ||
int myNumber; // variable myNumber is declared and auto-initialised to 0 | int myNumber; // variable myNumber is declared and auto-initialised to 0 | ||
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> | ||
int myNumber = 10; | int myNumber = 10; | ||
</ | </enforce> | ||
=== const === | |||
A value can be made '''constant''', meaning that it will remain the same along its lifetime. | |||
<enforce> | |||
string value1 = "value"; // value1's value is "value" | |||
const string CONST_VALUE = "value"; | |||
value1 = "new value"; // value1 is now "new 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. | |||
<enforce> | |||
const ref array<string> STRINGS = {}; | |||
STRINGS.Insert("Hello there"); // OK: the array remains the same, its content is changed | |||
STRINGS = null; // error: cannot modify a const value | |||
</enforce> | |||
Line 47: | Line 69: | ||
=== By Content === | === By Content === | ||
< | <enforce> | ||
// integers (whole numbers) are passed by content | // integers (whole numbers) are passed by content | ||
int myVar1 = 33; | int myVar1 = 33; | ||
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 === | ||
< | <enforce> | ||
// arrays (list of values) are passed by reference | // arrays (list of values) are passed by reference | ||
array<int> myArray1 = { 0, 1, 2, 3 }; | array<int> myArray1 = { 0, 1, 2, 3 }; | ||
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> | ||
{| class="wikitable float-right" | |||
|+ Prefix Cheat Sheet | |||
! Value Type | |||
! Prefix | |||
|- | |||
| Bool | |||
| <enforce inline>m_b</enforce> | |||
|- | |||
| Integer | |||
| <enforce inline>m_i</enforce> | |||
|- | |||
| Float | |||
| <enforce inline>m_f</enforce> | |||
|- | |||
| String | |||
| <enforce inline>m_s</enforce> | |||
|- | |||
| Enum | |||
| <enforce inline>m_e</enforce> | |||
|- | |||
| Vector | |||
| <enforce inline>m_v</enforce> | |||
|- | |||
| Array | |||
| <enforce inline>m_a</enforce> | |||
|- | |||
| Map | |||
| <enforce inline>m_m</enforce> | |||
|- | |||
| Set | |||
| <enforce inline>m_</enforce> | |||
|- | |||
| Class | |||
| <enforce inline>m_</enforce> | |||
<!-- colleagues… | |||
|- | |||
| Color | |||
| <enforce inline>m_</enforce> | |||
--> | |||
|} | |||
== Types == | == Types == | ||
Line 70: | Line 132: | ||
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 76: | Line 138: | ||
! Incorrect | ! Incorrect | ||
! Correct | ! Correct | ||
|- | |- | ||
| | | | ||
< | <enforce> | ||
bool variable = true; | bool variable = true; | ||
if (variable) | if (variable) | ||
{ | { | ||
variable = "it works!"; // not - variable is and remains a | variable = "it works!"; // not - variable is and remains a bool | ||
Print(variable); | Print(variable); | ||
} | } | ||
</ | </enforce> | ||
| | | | ||
< | <enforce> | ||
bool variable = true; | bool variable = true; | ||
if (variable) | if (variable) | ||
Line 94: | Line 156: | ||
Print(display); | Print(display); | ||
} | } | ||
</ | </enforce> | ||
|} | |} | ||
Line 114: | Line 176: | ||
! float | ! float | ||
| float | | float | ||
|±1.18E-38 through ±3.402823E+38 | | ±1.18E-38 through ±3.402823E+38 | ||
| 0.0 | | 0.0 | ||
| 4 | | 4 | ||
Line 127: | Line 189: | ||
| char* | | char* | ||
| - | | - | ||
|"" (empty string) | |"" (empty string) | ||
| 8 (pointer) + (length × 1 byte) | | 8 (pointer) + (length × 1 byte) | ||
|- | |- | ||
Line 157: | Line 219: | ||
<nowiki>*</nowiki>the asterisk in C++ means a pointer. | <nowiki>*</nowiki>the asterisk in C++ means a pointer. | ||
=== | === Bool === | ||
Passed by: '''value''' | Passed by: '''value''' | ||
Line 165: | Line 227: | ||
Default value: '''false''' | Default value: '''false''' | ||
A ''' | A '''bool''' is a value that can be either '''true''' or '''false''' . For example, <enforce inline>bool result = 10 > 5;</enforce> result can either be true or false (here is true, as 10 is greater than 5). | ||
Example: | Example: | ||
< | <enforce> | ||
bool myValue; // myValue is false | bool myValue; // myValue is false | ||
myValue = 10 > 0; // myValue is true | myValue = 10 > 0; // myValue is true | ||
</ | </enforce> | ||
Line 187: | Line 249: | ||
Example: | Example: | ||
< | <enforce> | ||
int myValue; // myValue is 0 | int myValue; // myValue is 0 | ||
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 213: | Line 275: | ||
Example: | Example: | ||
< | <enforce> | ||
float myValue; // myValue is 0 (or 0.0) | float myValue; // myValue is 0 (or 0.0) | ||
myValue = 1; // myValue is 1 (or 1.0) | myValue = 1; // myValue is 1 (or 1.0) | ||
myValue /= 3; // myValue is 0.333333… | myValue /= 3; // myValue is 0.333333… | ||
float originalValue = 1; | float originalValue = 1; | ||
float divisionResult = originalValue/3333; | float divisionResult = originalValue/3333; | ||
Line 223: | Line 285: | ||
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 239: | Line 301: | ||
{{Feature|informative| | {{Feature|informative| | ||
* A string '''cannot''' be null | * A string '''cannot''' be null | ||
* String comparison is '''case-sensitive'''; e.g < | * String comparison is '''case-sensitive'''; e.g <enforce inline>"abc" != "ABC"</enforce> | ||
}} | }} | ||
Example: | Example: | ||
< | <enforce> | ||
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 261: | Line 323: | ||
Examples: | Examples: | ||
< | <enforce> | ||
enum EHealthState | enum EHealthState | ||
{ | { | ||
Line 269: | Line 331: | ||
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. | ||
< | <enforce> | ||
enum EHealthState | enum EHealthState | ||
{ | { | ||
Line 285: | Line 347: | ||
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> | ||
// 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 298: | Line 360: | ||
HAS_FOOD = 1 << 2, // 4 | HAS_FOOD = 1 << 2, // 4 | ||
} | } | ||
</ | </enforce> | ||
=== Vector === | === Vector === | ||
Line 311: | Line 373: | ||
Example: | Example: | ||
< | <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 334: | Line 401: | ||
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 348: | Line 415: | ||
Example: | Example: | ||
< | <enforce> | ||
array<string> dynamicArray = {}; | array<string> dynamicArray = {}; | ||
string staticArray[2] = { "Hello", "" }; | string staticArray[2] = { "Hello", "" }; | ||
dynamicArray.Insert("Hello"); // dynamicArray = { "Hello" }; | dynamicArray.Insert("Hello"); // dynamicArray = { "Hello" }; | ||
dynamicArray.Insert(""); // dynamicArray = { "Hello", "" }; | dynamicArray.Insert(""); // dynamicArray = { "Hello", "" }; | ||
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) | ||
dynamicArray == staticArray; // false | dynamicArray == staticArray; // false | ||
dynamicArray[0] == staticArray[0]; // true | dynamicArray[0] == staticArray[0]; // true | ||
dynamicArray[1] == staticArray[1]; // true | dynamicArray[1] == staticArray[1]; // true | ||
</ | </enforce> | ||
=== Set === | === Set === | ||
Line 375: | Line 442: | ||
Example: | Example: | ||
< | <enforce> | ||
set<string> setInstance = new set<string>(); | set<string> setInstance = new set<string>(); | ||
setInstance.Insert("Hello there"); | setInstance.Insert("Hello there"); | ||
setInstance.Insert("General Kenobi"); | setInstance.Insert("General Kenobi"); | ||
setInstance.Insert("Hello there"); // setInstance will still only contain "Hello there" and "General Kenobi" | setInstance.Insert("Hello there"); // setInstance will still only contain "Hello there" and "General Kenobi" | ||
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 398: | Line 465: | ||
Example: | Example: | ||
< | <enforce> | ||
map<int, string> mapInstance = new map<int, string>(); | map<int, string> mapInstance = new map<int, string>(); | ||
mapInstance.Set(5712, "Hello there"); | mapInstance.Set(5712, "Hello there"); | ||
mapInstance.Set(5716, "General Kenobi"); | mapInstance.Set(5716, "General Kenobi"); | ||
mapInstance.Get(5712); // returns "Hello there" | mapInstance.Get(5712); // returns "Hello there" | ||
mapInstance.Get(5715); // /!\ returns "" (default string) | mapInstance.Get(5715); // /!\ returns "" (default string) | ||
mapInstance.Get(5716); // returns "General Kenobi" | mapInstance.Get(5716); // returns "General Kenobi" | ||
mapInstance.GetKeyByValue("Hello there"); // returns 5712 | mapInstance.GetKeyByValue("Hello there"); // returns 5712 | ||
mapInstance.GetKeyByValue("test"); // /!\ returns 0 (default int) | mapInstance.GetKeyByValue("test"); // /!\ returns 0 (default int) | ||
mapInstance.Contains(5716); // true | mapInstance.Contains(5716); // true | ||
mapInstance.ReplaceKey(5716, 5715); // replaces "General Kenobi" key | mapInstance.ReplaceKey(5716, 5715); // replaces "General Kenobi" key | ||
mapInstance.Contains(5716); // false | mapInstance.Contains(5716); // false | ||
mapInstance.Contains(5715); // true | mapInstance.Contains(5715); // true | ||
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 429: | Line 496: | ||
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 {{Link|Arma Reforger:Object Oriented Programming Basics}} and {{Link|Object Oriented Programming Advanced Usage}}.}} | |||
Example: | Example: | ||
< | <enforce> | ||
class ObjectClass | class ObjectClass | ||
{ | { | ||
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 452: | Line 519: | ||
} | } | ||
} | } | ||
void HealthMethod() | void HealthMethod() | ||
{ | { | ||
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 470: | Line 537: | ||
Default value: '''null''' | Default value: '''null''' | ||
A '''typename''' is class information | A '''typename''' is class information | ||
{{Wiki|WIP|talk about reflection?}} | |||
Example: | Example: | ||
< | <enforce> | ||
class ObjectClass | class ObjectClass | ||
{ | { | ||
int Health = 100; | int Health = 100; | ||
} | } | ||
typename t; // t is null | typename t; // t is null | ||
t = ObjectClass; | t = ObjectClass; | ||
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 489: | Line 556: | ||
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. | 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. | ||
< | <enforce> | ||
void SetDammage(int dammage) | void SetDammage(int dammage) | ||
{ | { | ||
int newHealth; | int newHealth; // newHealth variable is declared | ||
newHealth = m_iHealth - dammage; | newHealth = m_iHealth - dammage; | ||
if (newHealth < 0) | if (newHealth < 0) | ||
Line 506: | Line 573: | ||
// difference variable does not exist in this scope and cannot be used | // difference variable does not exist in this scope and cannot be used | ||
m_iHealth = newHealth; | m_iHealth = newHealth; // newHealth variable's last usage - the variable still exists | ||
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" | ||
| | | | ||
< | <enforce> | ||
if (soldiersHealth > 75) | if (soldiersHealth > 75) | ||
{ | { | ||
Line 525: | Line 592: | ||
else | else | ||
{ | { | ||
// no conflict with the previous variable as scopes are different | |||
string message = "I don't feel so good"; | string message = "I don't feel so good"; | ||
} | } | ||
Print(message); // error: message variable is undefined here | Print(message); // error: message variable is undefined here | ||
</ | </enforce> | ||
| | | | ||
< | <enforce> | ||
string message; | string message; | ||
if (soldiersHealth > 75) | if (soldiersHealth > 75) | ||
Line 541: | Line 609: | ||
} | } | ||
Print(message); // OK | Print(message); // OK | ||
</ | </enforce> | ||
| | | | ||
< | <enforce> | ||
string message = "I don't feel so good"; | string message = "I don't feel so good"; | ||
if (soldiersHealth > 75) | if (soldiersHealth > 75) | ||
Line 549: | Line 617: | ||
message = "I'm doing well"; | message = "I'm doing well"; | ||
} | } | ||
Print(message); // OK | Print(message); // OK | ||
</ | </enforce> | ||
|} | |} | ||
Line 562: | Line 630: | ||
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. | 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. | ||
''' | {{Feature|important|A wrong cast will return a '''null''' value - no exception will be thrown.}} | ||
< | |||
<enforce> | |||
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 | void SayHello() | ||
{ | { | ||
Print("Hello there"); | Print("Hello there"); | ||
} | } | ||
} | } | ||
Soldier_Base aSoldier = new B_Soldier_F(); // valid | Soldier_Base aSoldier = new B_Soldier_F(); // valid | ||
aSoldier.SayHello(); // invalid - Soldier_Base does not have the SayHello method | aSoldier.SayHello(); // invalid - Soldier_Base does not have the SayHello method | ||
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:02, 9 December 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
Value Type | Prefix |
---|---|
Bool | m_b |
Integer | m_i |
Float | m_f |
String | m_s |
Enum | m_e |
Vector | m_v |
Array | m_a |
Map | m_m |
Set | m_ |
Class | m_ |
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 bool
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.
Bool
Passed by: value
Naming prefix: b
Default value: false
A bool is a value that can be either true or false . For example, bool result = 10 > 5; result can either be true or false (here is true, as 10 is greater than 5).
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.