Enforce Script Syntax – DayZ
Enforce Script is the language that is used by the Enfusion engine first introduced in DayZ Standalone. It is a Object-Oriented Scripting Language (OOP) that works with objects and classes and is similar to C# programming language.
Basics
Code blocks
Code block is bordered by curly brackets and defines a scope. Variables defined inside scope are accessible only from inside of it.
Scope example
void Hello()
{
int x = 2; // First declaration of x
}
void Hello2()
{
int x = 23; // Different x not related to the first one
}
Nested scope
void World()
{
int i = 5;
// Following i is in a nested scope (scope of the for loop)
// Therefore we get an error because multiple declaration is not allowed
for (int i = 0; i < 12; ++i)
{
}
}
Scope statements
void Hello()
{
if (true)
{
// This is code block for the if branch
int x = 2; // First declaration of x
}
else
{
// This is code block for the else branch
int x = 23; // This will currently throw a multiple declaration error - while this should change for future enfusion script iterations, it might stay like this in DayZ. To circumvent this, define the x above the if statement or use different variables.
}
}
Program structure
Enfusion script consists of classes and functions. All code must be declared inside a function.
class MyClass
{
void Hello()
{
Print("Hello World"); // ok
}
}
void Hello()
{
Print("Hello World"); // ok
}
Print("Hello World"); // this code will be never executed, and should be caught by compiler as unexpected statement
Variables
Variables are defined by type and name.
void Test()
{
// declare
int a;
// assign
a = 5;
// initialize
int b = 9;
}
Functions
Functions are basic feature of Enfusion script. Function declaration consist of return value type, function name and list of parameters.
- Function can be declared in global scope or inside class declaration
- Function parameters are fixed and typed (cannot be changed during run-time, no variadic parameters)
- Function can be overloaded
- Keyword 'out' before parameter declaration ensures, that the parameter is passed by reference (you can passed more than one value from a function this way, can be used only in native functions)
- Enfusion script supports default parameter
void MethodA() // function with no parameters and no return value
{
}
int GiveMeTen() // function with no parameters which returns integer value
{
return 10;
}
void GiveMeElevenAndTwelve(out int val1, out int val2, int val3) // function with 2 of the parameters passed as reference
{
val1 = 11;
val2 = 12;
val3 = 13;
}
void PrintNum(int a = 0) // example of function with default parameter
{
Print(a);
}
void MethodB()
{
int ten = 0;
int eleven = 0;
int twelve = 0;
int thirteen = 0;
ten = GiveMeTen();
// function "GiveMeElevenAndTwelve" sets values of "eleven" and "twelve" variables,
// because "val1" and "val2" parameters are marked with "out" keyword,
// but value of "thirteen" variable is not changed, because third parameter is not marked as "out" and "val3"
// behaves only like a local variable of "GiveMeElevenAndTwelve" function
GiveMeElevenAndTwelve(eleven, twelve, thirteen);
Print(ten); // prints "ten = 10"
Print(eleven); // prints "eleven = 11"
Print(twelve); // prints "twelve = 12"
Print(thirteen ); // prints "thirteen = 0"
PrintNum(); // function "PrintNum" has default parameter, so its ok to call with empty brackets, it prints "a = 0"
PrintNum(7); // prints "a = 7"
}
float Sum(float a, float b) // function with two float parameters which return float value
{
return a + b;
}
float Sum(int a, int b) // overloaded Sum function which uses int parameters instead
{
return a + b;
}
void PrintCount(TStringArray stringArray) // function with one "TStringArray" object parameter which returns no value
{
if (!stringArray) return; // check if stringArray is not null
int count = stringArray.Count();
Print(count);
}
Comments
/*
Multi
line
comment
*/
void Test()
{
Print("Hello"); // single line comment
}
Constants
Constants are like variables but read only. They are declared by const keyword.
const int MONTHS_COUNT = 12;
void Test()
{
int a = MONTHS_COUNT; // ok
MONTHS_COUNT = 7; // err! you cannot change constant!
}
Operators
Operator Priority: Priority of operators is similar to C language, more info.
Arithmetic Operators
Operation | Symbol |
---|---|
Add | +
|
Subtract | -
|
Multiply | *
|
Divide | /
|
Modulo | %
|
Assignments
Operation | Symbol |
---|---|
Assign value to variable | =
|
Increment variable by value | +=
|
Decrement variable by value | -=
|
Multiply variable by value | *=
|
Divide variable by value | /=
|
Increment variable by 1 | ++
|
Decrement variable by 1 | --
|
Relational (conditional)
Operation | Symbol |
---|---|
More than value | >
|
Less than value | <
|
More or equal to the value | >=
|
Less or equal to the value | <=
|
Equal | == |
Not equal | != |
Others
Category | - |
---|---|
Logical | &&, || |
Bitwise | &, |, ~ |
String | + |
Shift | <<, >> |
Assignment | = |
Indexing | [] |
Negation | ! |
Types
Primitive Types
Type name | Range | Default Value |
---|---|---|
int | from −2,147,483,648 to +2,147,483,647 | 0 |
float | from ±1.401298E−45 to ±3.402823E+38 | 0.0 |
bool | true or false | false |
string | - | "" (empty string) |
vector | see float | (0.0,0.0,0.0) |
void | - | - |
class | - | null |
typename | - | null |
Strings
- Strings are passed by value, like primitive types
- Can be concatenated by + operator
- Strings are initialized and destroyed automatically
- Strings can contain standardized escape sequences. These are supported: \n \r \t \\ \"
void Method()
{
string a = "Hello";
string b = " world!";
string c = a + b;
Print(a); // prints "Hello"
Print(b); // prints " world!"
Print(c); // prints "Hello world!"
}
Vectors
- Vectors are passed by value, like primitive types
- Vector values are accessible by [, ] operator, like static arrays
- Vectors are initialized and destroyed automatically
- Vector can be initialized by three numeric values in double quotes e.g. "10 22 13"
void Method()
{
vector up = "0 1 0"; // initialized by values <0, 1, 0>
vector down; // vector "down" has now default value <0, 0, 0>
down = up;
down[1] = -1; // change Y value of vector "down"
Print(up); // prints <0, 1, 0>
Print(down); // prints <0, -1, 0>
}
Objects
- Objects in enforce script are references and are passed by reference
- All member functions and variables are public by default. Use 'private' keyword to make them private
- 'autoptr' keyword before object variable declaration ensures that compiler automatically destroys the object when the scope is terminated (e.g. function call ends)
class MyClass
{
void Say()
{
Print("Hello world");
}
}
void MethodA()
{
MyClass o; // o == null
o = new MyClass; // creates a new instance of MyClass class
o.Say(); // calls Say() function on instance 'o'
delete o; // destroys 'o' instance
}
void MethodB()
{
// if you type autoptr into declaration, compiler automatically does "delete o;" when the scope is terminated
autoptr MyClass o; // o == null
o = new MyClass; // creates a new instance of MyClass class
o.Say(); // calls Say() function on instance 'o'
}
void MethodC()
{
MyClass o;
o = new MyClass;
o.Say();
// This function doesn't delete the object, which causes memory leak
}
void UnsafeMethod(MyClass o) // Method not checking for existence of the input argument
{
o.Say();
}
void SafeMethod(MyClass o)
{
if (o)
{
o.Say();
}
else
{
Print("Hey! Object 'o' is not initialised!");
}
}
void MethodD()
{
autoptr MyClass o;
o = new MyClass;
SafeMethod(o); // ok
UnsafeMethod(o); // ok
SafeMethod(null); // ok
UnsafeMethod(null); // Crash! Object 'o' is not initialised and UnsafeMethod accessed it!
}
Example of this & super
class AnimalClass
{
void Hello()
{
Print("AnimalClass.Hello()");
}
};
class HoneyBadger: AnimalClass
{
override void Hello()
{
Print("HoneyBadger.Hello()");
}
void Test()
{
Hello(); // prints "HoneyBadger.Hello()"
this.Hello(); // 'this' refers to this instance of object, so same as line above, prints "HoneyBadger.Hello()"
super.Hello(); // refers to base(super) class members, prints "AnimalClass.Hello()"
}
}
Enums
Enumerators are set of named constant identifiers.
- enums have int type
- enum item value can be assigned in definition, otherwise it is computed automatically (previous item value plus one)
- enum can inherit from another enum (item value continues from last parent item value)
- enum name used as type behaves like ordinary int (no enum value checking on assign)
enum MyEnumBase
{
Alfa = 5, // has value 5
Beta, // has value 6
Gamma // has value 7
};
enum MyEnum: MyEnumBase
{
Blue, // has value 8
Yellow, // has value 9
Green = 20, // has value 20
Orange // has value 21
};
void Test()
{
int a = MyEnum.Beta;
MyEnum b = MyEnum.Green;
int c = b;
Print(a); // prints '6'
Print(b); // prints '20'
Print(c); // prints '20'
}
Typenames
Typename is primitive type that contains type definition.
- Typename variable can be initialized by name of type directly
- Only known and fully defined types can be assigned ( not the forward declaration, which is a placeholder for later definition )
Templates
Enfusion script has template feature similar to C++ Templates, which allows classes to operate with generic types.
- Generic type declaration is placed inside <, > (e.g. "class TemplateClass<class GenericType>" )operators after template class name identifier
- Enfusion script supports any number of generic types per template class
class Item<Class T>
{
T m_data;
void Item(T data)
{
m_data = data;
}
void SetData(T data)
{
m_data = data;
}
T GetData()
{
return m_data;
}
void PrintData()
{
Print(m_data);
}
};
void Method()
{
Item<string> string_item = new Item<string>("Hello!"); // template class Item declared with type "string". In Item<string> class, all "T"s are substituted with 'string'
Item<int> int_item = new Item<int>(72); // template class Item declared with type "int". In Item<int> class, all "T"s are substituted with 'int'
string_item.PrintData(); // prints "m_data = 'Hello!'"
int_item.PrintData(); // prints "m_data = 72"
}
Arrays
Static Arrays
- Arrays are indexed from 0
- Arrays are passed by reference, like objects
- Static arrays are initialized and destroyed automatically
- Size of static arrays can be set only during compilation time
- Elements are accessible by array access operator [ ]
void MethodA()
{
int numbersArray[3]; // declaring array of int with size 3
numbersArray[0] = 54;
numbersArray[1] = 82;
numbersArray[2] = 7;
int anotherArray[3] = {53, 90, 7};
}
const int ARRAY_SIZE = 5;
void MethodB()
{
int numbersArray[ARRAY_SIZE]; // declaring array of int with size of value of ARRAY_SIZE constant
numbersArray[0] = 54;
numbersArray[1] = 82;
numbersArray[2] = 7;
numbersArray[3] = 1000;
numbersArray[4] = 324;
}
void MethodC()
{
int size = 3;
int numbersArray[size]; // err! size static array cannot be declared by veriable!
}
Dynamic Arrays
- Dynamic arrays support change of size at runtime by inserting/removing array items
- Dynamic arrays are provided through 'array' template class
- Dynamic arrays are passed by reference
- Dynamic Arrays are objects and therefore they must be created and destroyed like objects, so don't forget to use "autoptr" or delete operator!
- Elements are accessible by "Get" function or by array access operator [ ]
- There are already defined typedefs for primitive type arrays:
- array<string> = TStringArray
- array<float> = TFloatArray
- array<int> = TIntArray
- array<class> = TClassArray
- array<vector> = TVectorArray
void Method()
{
autoptr TStringArray nameArray = new TStringArray; // dynamic array declaration, "TStringArray" is the same as "array<string>"
nameArray.Insert("Peter");
nameArray.Insert("Michal");
nameArray.Insert("David");
string name;
name = nameArray.Get(1); // gets second element of array "nameArray"
Print(name); // prints "name = 'Michal'"
nameArray.Remove(1); // second element is removed
name = nameArray.Get(1); // gets second element of array "nameArray"
Print(name); // prints "name = 'David'"
int nameCount = nameArray.Count(); // gets elements count of array "nameArray"
Print(nameCount); // prints "nameCount = 2"
}
Control Structures
Control structures work very similar to c# or c/c++ languages.
Conditional structures
If statement
void Method()
{
int a = 4;
int b = 5;
if (a > 0)
{
Print("A is greater than zero!");
}
else
{
Print("A is not greater than zero!");
}
if (a > 0 && b > 0)
{
Print("A and B are greater than zero!");
}
if (a > 0 || b > 0)
{
Print("A or B are greater than zero!");
}
// 'else if' example
if (a > 10)
{
Print("a is bigger then 10");
}
else if (a > 5)
{
Print("a is bigger then 5 but smaller than 10");
}
else
{
Print("a is smaller then 5");
}
}
Switch statement
Switch statement supports switching by numbers, constants and strings.
void Method()
{
int a = 2;
switch(a)
{
case 1:
Print("a is 1");
break;
case 2:
Print("a is 2"); // this one is called
break;
default:
Print("it's something else");
break;
}
// using switch with constants
const int LOW = 0;
const int MEDIUM = 1;
const int HIGH = 2;
int quality = MEDIUM;
switch(quality)
{
case LOW:
// do something
break;
case MEDIUM:
// this one is called
// do something
break;
case HIGH:
// do something
break;
}
// using switch with strings
string name = "peter";
switch(name)
{
case "john":
Print("Hello John!");
break;
case "michal":
Print("Hello Michal!");
break;
case "peter":
Print("Hello Peter!"); // this one is called
break;
}
}
Iteration structures
For
The for loop consists of three parts: declaration, condition and increment.
void Method()
{
// this code prints
// "i = 0"
// "i = 1"
// "i = 2"
for (int i = 0; i < 3; i++)
{
Print(i);
}
}
// this function print all elements from dynamic array of strings
void ListArray(TStringArray a)
{
if (a == null) return; // check if "a" is not null
int i = 0;
int c = a.Count();
for (i = 0; i < c; i++)
{
string tmp = a.Get(i);
Print(tmp);
}
}
Foreach
Simpler and more comfortable version of for loop.
void TestFn()
{
int pole1[] = {7,3,6,8};
array<string> pole2 = {"a", "b", "c"};
auto mapa = new map<string, int>();
mapa["jan"] = 1;
mapa["feb"] = 2;
mapa["mar"] = 3;
// simple foreach iteration
foreach(int v: pole1) // prints: '7', '3', '6', '8'
{
Print(v);
}
// foreach iteration with key (if you iterate trough array, key is filled with array index)
foreach(int i, string j: pole2) // prints: 'pole[0] = a', 'pole[1] = b', 'pole[2] = c'
{
Print("pole[" + i + "] = " + j);
}
// map iteration, with key and value
foreach(auto k, auto a: mapa) // prints: 'mapa[jan] = 1', 'mapa[feb] = 2', 'mapa[mar] = 3'
{
Print("mapa[" + k + "] = " + a);
}
// map iteration with just value
foreach(auto b: mapa) // prints: '1', '2', '3'
{
Print(b);
}
}
While
void Method()
{
int i = 0;
// this code prints
// "i = 0"
// "i = 1"
// "i = 2"
while (i < 3)
{
Print(i);
i++;
}
}
Classes and Objects
Classes can be seen as a blueprint of an object. An object is an instance of a class. A class can have more than one object.
Basic Class Example
class MyClass
{
private string _test;
void MyClass()
{
// Constructor that will be called when class gets instantiated
}
void myMethod()
{
// Some code here
}
string getTest()
{
return _test;
}
string setTest(value)
{
_test = value;
}
}
Instantiate and Use
Use the new
operator to instantiate a class. You can access methods or attributes by using dot notation.
Example
class MyClass {
int attributeExample = 1;
public MyClass() {
// Constructor
}
public string myMethod() {
return "This is a string return";
}
}
MyClass myClassI = new MyClass();
myClassI.attributeExample // 1
myClassI.myMethod // "This is a string return"
Modded class
Modded class is used to inject inherited class into class hierarchy without modifying other scripts, which is required for proper modding
- Modded class behaves like class inherited from original class (you can use super to access original class)
- When modded class is declared, it will be instanced instead of original class everywhere in the script
- When several modded classes are modding the same vanilla class, the next modded class will instead inherit of the latest modded class, which enables mod compatibility
// original
class ModMe
{
void Say()
{
Print("Hello original");
}
};
// First mod
modded class ModMe // this class automatically inherits from original class ModMe
{
override void Say()
{
Print("Hello modded One");
super.Say();
}
};
// Second mod
modded class ModMe // this class automatically inherits from first mod's ModMe
{
override void Say()
{
Print("Hello modded Two");
super.Say();
}
};
void Test()
{
ModMe a = new ModMe(); // modded class ModMe is instanced
a.Say(); // prints 'Hello modded Two' , 'Hello modded One' and 'Hello original'
}