Skip to content

Capitulo 1.1: Variables y Tipos ​


Introduccion ​

Enforce Script es el lenguaje de scripting del motor Enfusion, utilizado por DayZ Standalone. Es un lenguaje orientado a objetos con sintaxis similar a C, parecido a C# en muchos aspectos pero con su propio conjunto de tipos, reglas y limitaciones. Si tienes experiencia con C#, Java o C++, te sentiras comodo rapidamente --- pero presta mucha atencion a las diferencias, porque los puntos donde Enforce Script difiere de esos lenguajes son exactamente los lugares donde se esconden los bugs.

Este capitulo cubre los bloques fundamentales: tipos primitivos, como declarar e inicializar variables, y como funciona la conversion de tipos. Cada linea de codigo de un mod de DayZ comienza aqui.


Tipos Primitivos ​

Enforce Script tiene un conjunto pequeno y fijo de tipos primitivos. No puedes definir nuevos tipos de valor --- solo clases (cubiertas en el Capitulo 1.3).

TipoTamanoValor PredeterminadoDescripcion
int32 bits con signo0Numeros enteros de -2,147,483,648 a 2,147,483,647
float32 bits IEEE 7540.0Numeros de punto flotante
bool1 bit logicofalsetrue o false
stringVariable"" (vacio)Texto. Tipo de valor inmutable --- se pasa por valor, no por referencia
vector3x float"0 0 0"Tres componentes float (x, y, z). Se pasa por valor
typenameRef del motornullUna referencia al tipo en si, usada para reflexion
voidN/AN/ASe usa solo como tipo de retorno para indicar "no retorna nada"

Constantes de Tipos ​

Varios tipos exponen constantes utiles:

c
// limites de int
int maxInt = int.MAX;    // 2147483647
int minInt = int.MIN;    // -2147483648

// limites de float
float smallest = float.MIN;     // float positivo mas pequeno (~1.175e-38)
float largest  = float.MAX;     // float mas grande (~3.403e+38)
float lowest   = float.LOWEST;  // float mas negativo (-3.403e+38)

Declaracion de Variables ​

Las variables se declaran escribiendo el tipo seguido del nombre. Puedes declarar y asignar en una sola instruccion o por separado.

c
void MyFunction()
{
    // Solo declaracion (inicializado al valor predeterminado)
    int health;          // health == 0
    float speed;         // speed == 0.0
    bool isAlive;        // isAlive == false
    string name;         // name == ""

    // Declaracion con inicializacion
    int maxPlayers = 60;
    float gravity = 9.81;
    bool debugMode = true;
    string serverName = "My DayZ Server";
}

La Palabra Clave auto ​

Cuando el tipo es obvio por el lado derecho, puedes usar auto para que el compilador lo infiera:

c
void Example()
{
    auto count = 10;           // int
    auto ratio = 0.75;         // float
    auto label = "Hello";      // string
    auto player = GetGame().GetPlayer();  // DayZPlayer (o lo que sea que retorne GetPlayer)
}

Esto es puramente una conveniencia --- el compilador resuelve el tipo en tiempo de compilacion. No hay diferencia de rendimiento.

Constantes ​

Usa la palabra clave const para valores que nunca deben cambiar despues de la inicializacion:

c
const int MAX_SQUAD_SIZE = 8;
const float SPAWN_RADIUS = 150.0;
const string MOD_PREFIX = "[MyMod]";

void Example()
{
    int a = MAX_SQUAD_SIZE;  // OK: leyendo una constante
    MAX_SQUAD_SIZE = 10;     // ERROR: no se puede asignar a una constante
}

Las constantes se declaran tipicamente en el ambito del archivo (fuera de cualquier funcion) o como miembros de clase. Convencion de nombres: UPPER_SNAKE_CASE.


Trabajando con int ​

Los enteros son el tipo de trabajo pesado. DayZ los usa para conteos de items, IDs de jugadores, valores de salud (cuando se discretizan), valores de enum, bitflags, y mas.

c
void IntExamples()
{
    int count = 5;
    int total = count + 10;     // 15
    int doubled = count * 2;    // 10
    int remainder = 17 % 5;     // 2 (modulo)

    // Incremento y decremento
    count++;    // count ahora es 6
    count--;    // count ahora es 5 de nuevo

    // Asignacion compuesta
    count += 3;  // count ahora es 8
    count -= 2;  // count ahora es 6
    count *= 4;  // count ahora es 24
    count /= 6;  // count ahora es 4

    // La division entera trunca (sin redondeo)
    int result = 7 / 2;    // result == 3, no 3.5

    // Operaciones bitwise (usadas para flags)
    int flags = 0;
    flags = flags | 0x01;   // activar bit 0
    flags = flags | 0x04;   // activar bit 2
    bool hasBit0 = (flags & 0x01) != 0;  // true
}

Ejemplo del Mundo Real: Conteo de Jugadores ​

c
void PrintPlayerCount()
{
    array<Man> players = new array<Man>;
    GetGame().GetPlayers(players);
    int count = players.Count();
    Print(string.Format("Players online: %1", count));
}

Trabajando con float ​

Los floats representan numeros decimales. DayZ los usa extensivamente para posiciones, distancias, porcentajes de salud, valores de dano y temporizadores.

c
void FloatExamples()
{
    float health = 100.0;
    float damage = 25.5;
    float remaining = health - damage;   // 74.5

    // Especifico de DayZ: multiplicador de dano
    float headMultiplier = 3.0;
    float actualDamage = damage * headMultiplier;  // 76.5

    // La division float da resultados decimales
    float ratio = 7.0 / 2.0;   // 3.5

    // Matematicas utiles
    float dist = 150.7;
    float rounded = Math.Round(dist);    // 151
    float floored = Math.Floor(dist);    // 150
    float ceiled  = Math.Ceil(dist);     // 151
    float clamped = Math.Clamp(dist, 0.0, 100.0);  // 100
}

Ejemplo del Mundo Real: Verificacion de Distancia ​

c
bool IsPlayerNearby(PlayerBase player, vector targetPos, float radius)
{
    if (!player)
        return false;

    vector playerPos = player.GetPosition();
    float distance = vector.Distance(playerPos, targetPos);
    return distance <= radius;
}

Trabajando con bool ​

Los booleanos contienen true o false. Se usan en condiciones, flags y seguimiento de estado.

c
void BoolExamples()
{
    bool isAdmin = true;
    bool isBanned = false;

    // Operadores logicos
    bool canPlay = isAdmin || !isBanned;    // true (OR, NOT)
    bool isSpecial = isAdmin && !isBanned;  // true (AND)

    // Negacion
    bool notAdmin = !isAdmin;   // false

    // Los resultados de comparacion son bool
    int health = 50;
    bool isLow = health < 25;       // false
    bool isHurt = health < 100;     // true
    bool isDead = health == 0;      // false
    bool isAlive = health != 0;     // true
}

Veracidad en Condiciones ​

En Enforce Script, puedes usar valores no booleanos en condiciones. Los siguientes se consideran false:

  • 0 (int)
  • 0.0 (float)
  • "" (string vacio)
  • null (referencia de objeto nula)

Todo lo demas es true. Esto se usa comunmente para verificaciones de null:

c
void SafeCheck(PlayerBase player)
{
    // Estas dos son equivalentes:
    if (player != null)
        Print("Player exists");

    if (player)
        Print("Player exists");

    // Y estas dos:
    if (player == null)
        Print("No player");

    if (!player)
        Print("No player");
}

Trabajando con string ​

Los strings en Enforce Script son tipos de valor --- se copian cuando se asignan o se pasan a funciones, igual que int o float. Esto es diferente de C# o Java donde los strings son tipos de referencia.

c
void StringExamples()
{
    string greeting = "Hello";
    string name = "Survivor";

    // Concatenacion con +
    string message = greeting + ", " + name + "!";  // "Hello, Survivor!"

    // Formateo de strings (placeholders con indice desde 1)
    string formatted = string.Format("Player %1 has %2 health", name, 75);
    // Resultado: "Player Survivor has 75 health"

    // Longitud
    int len = message.Length();    // 17

    // Comparacion
    bool same = (greeting == "Hello");  // true

    // Conversion desde otros tipos
    string fromInt = "Score: " + 42;     // funciona -- el operador + convierte 42 a "42"
    string correct = "Score: " + 42.ToString();  // "Score: 42" (explicito, mismo resultado)

    // Usar Format es el enfoque preferido
    string best = string.Format("Score: %1", 42);  // "Score: 42"
}

Secuencias de Escape ​

Los strings soportan secuencias de escape estandar:

SecuenciaSignificado
\nNueva linea
\rRetorno de carro
\tTabulacion
\\Barra invertida literal
\"Comilla doble literal

Advertencia: Aunque estan documentadas, la barra invertida (\\) y las comillas escapadas (\") son conocidas por causar problemas con el CParser en algunos contextos, especialmente en operaciones relacionadas con JSON. Cuando trabajes con rutas de archivos o strings JSON, evita las barras invertidas cuando sea posible. Usa barras normales para las rutas --- DayZ las acepta en todas las plataformas.

Ejemplo del Mundo Real: Mensaje de Chat ​

c
void SendAdminMessage(string adminName, string text)
{
    string msg = string.Format("[ADMIN] %1: %2", adminName, text);
    Print(msg);
}

Trabajando con vector ​

El tipo vector contiene tres componentes float (x, y, z). Es el tipo fundamental de DayZ para posiciones, direcciones, rotaciones y velocidades. Como los strings y los primitivos, los vectores son tipos de valor --- se copian al asignarse.

Inicializacion ​

Los vectores se pueden inicializar de dos formas:

c
void VectorInit()
{
    // Metodo 1: Inicializacion por string (tres numeros separados por espacios)
    vector pos1 = "100.5 0 200.3";

    // Metodo 2: Funcion constructora Vector()
    vector pos2 = Vector(100.5, 0, 200.3);

    // El valor predeterminado es "0 0 0"
    vector empty;   // empty == <0, 0, 0>
}

Importante: El formato de inicializacion por string usa espacios como separadores, no comas. "1 2 3" es valido; "1,2,3" no lo es.

Acceso a Componentes ​

Accede a componentes individuales usando indexacion estilo array:

c
void VectorComponents()
{
    vector pos = Vector(100.5, 25.0, 200.3);

    // Lectura de componentes
    float x = pos[0];   // 100.5  (Este/Oeste)
    float y = pos[1];   // 25.0   (Arriba/Abajo, altitud)
    float z = pos[2];   // 200.3  (Norte/Sur)

    // Escritura de componentes
    pos[1] = 50.0;      // Cambiar altitud a 50
}

Sistema de coordenadas de DayZ:

  • [0] = X = Este(+) / Oeste(-)
  • [1] = Y = Arriba(+) / Abajo(-) (altitud sobre el nivel del mar)
  • [2] = Z = Norte(+) / Sur(-)

Constantes Estaticas ​

c
vector zero    = vector.Zero;      // "0 0 0"
vector up      = vector.Up;        // "0 1 0"
vector right   = vector.Aside;     // "1 0 0"
vector forward = vector.Forward;   // "0 0 1"

Operaciones Comunes con Vectores ​

c
void VectorOps()
{
    vector pos1 = Vector(100, 0, 200);
    vector pos2 = Vector(150, 0, 250);

    // Distancia entre dos puntos
    float dist = vector.Distance(pos1, pos2);

    // Distancia al cuadrado (mas rapida, buena para comparaciones)
    float distSq = vector.DistanceSq(pos1, pos2);

    // Direccion de pos1 a pos2
    vector dir = vector.Direction(pos1, pos2);

    // Normalizar un vector (hacer que la longitud sea 1)
    vector norm = dir.Normalized();

    // Longitud de un vector
    float len = dir.Length();

    // Interpolacion lineal (50% entre pos1 y pos2)
    vector midpoint = vector.Lerp(pos1, pos2, 0.5);

    // Producto punto
    float dot = vector.Dot(dir, vector.Up);
}

Ejemplo del Mundo Real: Posicion de Spawn ​

c
// Obtener una posicion en el suelo en coordenadas X,Z dadas
vector GetGroundPosition(float x, float z)
{
    vector pos = Vector(x, 0, z);
    pos[1] = GetGame().SurfaceY(x, z);  // Establecer Y a la altura del terreno
    return pos;
}

// Obtener una posicion aleatoria dentro de un radio desde un punto central
vector GetRandomPositionAround(vector center, float radius)
{
    float angle = Math.RandomFloat(0, Math.PI2);
    float dist = Math.RandomFloat(0, radius);

    vector offset = Vector(Math.Cos(angle) * dist, 0, Math.Sin(angle) * dist);
    vector pos = center + offset;
    pos[1] = GetGame().SurfaceY(pos[0], pos[2]);
    return pos;
}

Trabajando con typename ​

El tipo typename contiene una referencia a un tipo en si. Se usa para reflexion --- inspeccionar y trabajar con tipos en tiempo de ejecucion. Lo encontraras al escribir sistemas genericos, cargadores de configuracion y patrones factory.

c
void TypenameExamples()
{
    // Obtener el typename de una clase
    typename t = PlayerBase;

    // Obtener typename desde un string
    typename t2 = "PlayerBase".ToType();

    // Comparar tipos
    if (t == PlayerBase)
        Print("It's PlayerBase!");

    // Obtener el typename de una instancia de objeto
    PlayerBase player;
    // ... asumiendo que player es valido ...
    typename objType = player.Type();

    // Verificar herencia
    bool isMan = objType.IsInherited(Man);

    // Convertir typename a string
    string name = t.ToString();  // "PlayerBase"

    // Crear una instancia desde typename (patron factory)
    Class instance = t.Spawn();
}

Conversion de Enum con typename ​

c
enum DamageType
{
    MELEE = 0,
    BULLET = 1,
    EXPLOSION = 2
};

void EnumConvert()
{
    // Enum a string
    string name = typename.EnumToString(DamageType, DamageType.BULLET);
    // name == "BULLET"

    // String a enum
    int value;
    typename.StringToEnum(DamageType, "EXPLOSION", value);
    // value == 2
}

Conversion de Tipos ​

Enforce Script soporta conversiones tanto implicitas como explicitas entre tipos.

Conversiones Implicitas ​

Algunas conversiones ocurren automaticamente:

c
void ImplicitConversions()
{
    // int a float (siempre seguro, sin perdida de datos)
    int count = 42;
    float fCount = count;    // 42.0

    // float a int (TRUNCA, no redondea!)
    float precise = 3.99;
    int truncated = precise;  // 3, NO 4

    // int/float a bool
    bool fromInt = 5;      // true (distinto de cero)
    bool fromZero = 0;     // false
    bool fromFloat = 0.1;  // true (distinto de cero)

    // bool a int
    int fromBool = true;   // 1
    int fromFalse = false; // 0
}

Conversiones Explicitas (Parsing) ​

Para convertir entre strings y tipos numericos, usa metodos de parsing:

c
void ExplicitConversions()
{
    // String a int
    int num = "42".ToInt();           // 42
    int bad = "hello".ToInt();        // 0 (falla silenciosamente)

    // String a float
    float f = "3.14".ToFloat();       // 3.14

    // String a vector
    vector v = "100 25 200".ToVector();  // <100, 25, 200>

    // Numero a string (usando Format)
    string s1 = string.Format("%1", 42);       // "42"
    string s2 = string.Format("%1", 3.14);     // "3.14"

    // int/float .ToString()
    string s3 = (42).ToString();     // "42"
}

Casteo de Objetos ​

Para tipos de clase, usa Class.CastTo() o ClassName.Cast(). Esto se cubre en detalle en el Capitulo 1.3, pero aqui esta el patron esencial:

c
void CastExample()
{
    Object obj = GetSomeObject();

    // Casteo seguro (preferido)
    PlayerBase player;
    if (Class.CastTo(player, obj))
    {
        // player es valido y seguro de usar
        string name = player.GetIdentity().GetName();
    }

    // Sintaxis de casteo alternativa
    PlayerBase player2 = PlayerBase.Cast(obj);
    if (player2)
    {
        // player2 es valido
    }
}

Ambito de Variables ​

Las variables existen solo dentro del bloque de codigo (llaves) donde se declaran. Enforce Script no permite redeclarar un nombre de variable dentro de ambitos anidados o hermanos.

c
void ScopeExample()
{
    int x = 10;

    if (true)
    {
        // int x = 20;  // ERROR: redeclaracion de 'x' en ambito anidado
        x = 20;         // OK: modificando el x externo
        int y = 30;     // OK: nueva variable en este ambito
    }

    // y NO es accesible aqui (declarada en ambito interno)
    // Print(y);  // ERROR: identificador no declarado 'y'

    // IMPORTANTE: esto tambien aplica a los bucles for
    for (int i = 0; i < 5; i++)
    {
        // i existe aqui
    }
    // for (int i = 0; i < 3; i++)  // ERROR en DayZ: 'i' ya declarada
    // Usa un nombre diferente:
    for (int j = 0; j < 3; j++)
    {
        // j existe aqui
    }
}

La Trampa del Ambito Hermano ​

Esta es una de las peculiaridades mas notorias de Enforce Script. Declarar el mismo nombre de variable en bloques if y else causa un error de compilacion:

c
void SiblingTrap()
{
    if (someCondition)
    {
        int result = 10;    // Declarada aqui
        Print(result);
    }
    else
    {
        // int result = 20; // ERROR: declaracion multiple de 'result'
        // Aunque este es un ambito hermano, no el mismo ambito
    }

    // SOLUCION: declarar antes del if/else
    int result;
    if (someCondition)
    {
        result = 10;
    }
    else
    {
        result = 20;
    }
}

Errores Comunes ​

1. Variables No Inicializadas Usadas en Logica ​

Los primitivos obtienen valores predeterminados (0, 0.0, false, ""), pero depender de esto hace que el codigo sea fragil y dificil de leer. Siempre inicializa explicitamente.

c
// MAL: dependiendo del cero implicito
int count;
if (count > 0)  // Esto funciona porque count == 0, pero la intencion no es clara
    DoThing();

// BIEN: inicializacion explicita
int count = 0;
if (count > 0)
    DoThing();

2. Truncamiento de Float a Int ​

La conversion de float a int trunca (redondea hacia cero), no redondea al mas cercano:

c
float f = 3.99;
int i = f;         // i == 3, NO 4

// Si quieres redondeo:
int rounded = Math.Round(f);  // 4

3. Precision de Float en Comparaciones ​

Nunca compares floats por igualdad exacta:

c
float a = 0.1 + 0.2;
// MAL: puede fallar por la representacion de punto flotante
if (a == 0.3)
    Print("Equal");

// BIEN: usa una tolerancia (epsilon)
if (Math.AbsFloat(a - 0.3) < 0.001)
    Print("Close enough");

4. Concatenacion de Strings con Numeros ​

No puedes simplemente concatenar un numero a un string con +. Usa string.Format():

c
int kills = 5;
// Potencialmente problematico:
// string msg = "Kills: " + kills;

// CORRECTO: usa Format
string msg = string.Format("Kills: %1", kills);

5. Formato de String de Vector ​

La inicializacion de vector por string requiere espacios, no comas:

c
vector good = "100 25 200";     // CORRECTO
// vector bad = "100, 25, 200"; // INCORRECTO: las comas no se parsean correctamente
// vector bad2 = "100,25,200";  // INCORRECTO

6. Olvidar que los Strings y Vectores son Tipos de Valor ​

A diferencia de los objetos de clase, los strings y vectores se copian al asignar. Modificar una copia no afecta al original:

c
vector posA = "10 20 30";
vector posB = posA;       // posB es una COPIA
posB[1] = 99;             // Solo posB cambia
// posA sigue siendo "10 20 30"

Ejercicios Practicos ​

Ejercicio 1: Basicos de Variables ​

Declara variables para almacenar:

  • El nombre de un jugador (string)
  • Su porcentaje de salud (float, 0-100)
  • Su conteo de kills (int)
  • Si es admin (bool)
  • Su posicion en el mundo (vector)

Imprime un resumen formateado usando string.Format().

Ejercicio 2: Convertidor de Temperatura ​

Escribe una funcion float CelsiusToFahrenheit(float celsius) y su inversa float FahrenheitToCelsius(float fahrenheit). Prueba con el punto de ebullicion (100C = 212F) y el punto de congelacion (0C = 32F).

Ejercicio 3: Calculadora de Distancia ​

Escribe una funcion que tome dos vectores y retorne:

  • La distancia 3D entre ellos
  • La distancia 2D (ignorando la altura/eje Y)
  • La diferencia de altura

Pista: Para la distancia 2D, crea nuevos vectores con [1] establecido en 0 antes de calcular la distancia.

Ejercicio 4: Malabarismo de Tipos ​

Dado el string "42", conviertelo a:

  1. Un int
  2. Un float
  3. De vuelta a un string usando string.Format()
  4. Un bool (deberia ser true ya que el valor int es distinto de cero)

Ejercicio 5: Posicion en el Suelo ​

Escribe una funcion vector SnapToGround(vector pos) que tome cualquier posicion y la retorne con el componente Y establecido a la altura del terreno en esa ubicacion X,Z. Usa GetGame().SurfaceY().


Resumen ​

ConceptoPunto Clave
Tiposint, float, bool, string, vector, typename, void
Predeterminados0, 0.0, false, "", "0 0 0", null
ConstantesPalabra clave const, convencion UPPER_SNAKE_CASE
VectoresInicializar con string "x y z" o Vector(x,y,z), acceder con [0], [1], [2]
AmbitoVariables con ambito a bloques {}; sin redeclaracion en bloques anidados/hermanos
Conversionfloat a int trunca; usa .ToInt(), .ToFloat(), .ToVector() para parseo de strings
FormateoSiempre usa string.Format() para construir strings desde tipos mixtos

Released under CC BY-SA 4.0 | Code examples under MIT License