> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/docs-es/programacion/syntax.md).

# Primeros pasos con CSL

CSL es el lenguaje de scripting personalizado de All Out. Es tipado estáticamente y se parece más a Go/Odin — excepto **el estado de la jugabilidad se sincroniza automáticamente del servidor a los clientes**.

{% hint style="info" %}
No necesitas escribir RPCs, SyncVars ni replicación personalizada. ¡Nosotros nos encargamos de eso por ti!
{% endhint %}

## Tu primer script (`main.csl`)

Cuando creas un nuevo proyecto, All Out genera un `main.csl` en tu carpeta de proyecto `scripts/` folder.

```go
import "core:ao"

// ============================================================================
// Ciclo de vida global
// ============================================================================

ao_before_scene_load :: proc() {
    // Registrar definiciones de objetos, monedas, etc.
    // Se ejecuta después de que existe la Scene vacía, antes de que se cargue el contenido de la escena.
}

ao_start :: proc() {
    // Se llama una vez cuando comienza la escena.
}

ao_update :: proc(dt: float) {
    // Se llama en cada frame.
}

ao_late_update :: proc(dt: float) {
    // Se llama en cada frame después de ao_update.
}

// ============================================================================
// Ciclo de vida del jugador
// ============================================================================

Player :: class : Player_Base {
    ao_start :: method() {
    }

    ao_update :: method(dt: float) {
    }

    ao_late_update :: method(dt: float) {
    }

    ao_end :: method() {
    }
}
```

Por ejemplo, registra un mensaje cuando se una cada jugador:

```go
Player :: class : Player_Base {
    ao_start :: method() {
        log_info("hello %", {this.get_username()});
    }
}
```

Si quieres una explicación más profunda de cuándo se ejecutan estas funciones, consulta [Ciclo de vida del juego/fotograma](/all-out-docs/docs-es/programacion/game-frame-lifecycle.md).

## Importaciones

Tu `main.csl` debe importar `core:ao` y cualquier carpeta que crees (como `ui/`, `abilities/`, etc.).

```go
import "core:ao"
import "ui"
```

Las importaciones apuntan a carpetas, no a archivos individuales. Una importación de carpeta incluye los `.csl` archivos de esa carpeta. Las importaciones dentro de esa carpeta se resuelven de forma relativa a ella:

```go
// main.csl
import "core:ao"
import "abilities"

// abilities/projectiles.csl
import "helpers"
```

{% hint style="warning" %}
En la mayoría de los proyectos, **importa en `main.csl` solo**. No disperses importaciones por muchos archivos; tarde o temprano acabarás con problemas confusos de orden/visibilidad.
{% endhint %}

## Declaraciones (variables y constantes)

Las declaraciones vinculan un nombre a un valor.

### Variables

```go
// Forma general
<nombre>: <tipo> = <expresión>;
```

O bien `<tipo>` o `<expresión>` puede omitirse:

```go
// Tipo explícito
my_value: int = 42;

// Inferencia de tipos
my_value := 42; // inferido como int

// Inicialización a cero (igual que my_value := 0;)
my_value: int;
```

### Constantes

Las constantes usan `::` y deben ser constantes en tiempo de compilación. Pueden ser escalares, cadenas, tipos, valores de procedimiento, arrays o literales compuestos:

```go
MAX_PLAYERS :: 12;

Spawn_Desc :: struct {
    name: string;
    pos: v2;
}

DEFAULT_SPAWNS: []Spawn_Desc : {
    {"Blue", {-4, 0}},
    {"Red", {4, 0}},
};
```

Esto no es válido (porque `a` no es una constante en tiempo de compilación):

```go
a := 123;
b :: a; // error de compilación
```

Los inicializadores de variables globales también deben ser constantes en tiempo de compilación. Usa `ao_before_scene_load` o `ao_start` para la inicialización en tiempo de ejecución.

### Variables globales

Las globales usan la misma sintaxis de declaración que las locales. Pueden dejarse inicializadas a cero o inicializadas con constantes en tiempo de compilación, incluidos structs, arrays, valores de procedimiento y `typeid` valores:

```go
score_total: int;
spawn_names: []string = {"Blue", "Red"};
default_type: typeid = int;

start_round :: proc() {
}

on_match_start: proc() = start_round;
```

Las globales son mutables y persisten durante toda la vida útil de la instancia del script. Evita usarlas para el estado de jugabilidad por jugador.

## Tipos

### Tipos primitivos

* Enteros con signo: `s8`, `s16`, `s32`, `s64`
* Enteros sin signo: `u8`, `u16`, `u32`, `u64`
* Booleanos: `bool`
* Flotantes: `f32`, `f64`
* Alias:
  * `int` == `s64`
  * `uint` == `u64`
  * `float` == `f32`
* Vectores: `v2`, `v3`, `v4`
* `string`
* `typeid`
* `cualquier`

### Los tipos vectoriales

`v2` tiene `.x`, `.y`; `v3` añade `.z`; `v4` añade `.w` — todos los campos float:

```go
pos: v2 = {10, 20};        // x=10, y=20
color: v4 = {1, 0, 0, 1};  // rojo con alpha=1
offset := v3{1, 4, 9};     // inferencia de tipos
```

## Structs y clases

Los structs son **tipos por valor** (se copian al asignarse). Las clases son **tipos por referencia** (las asignas con `new`).

### Structs (tipos por valor)

```go
Food_Definition :: struct {
    name: string;
    food_value: int;
}

food: Food_Definition;
food.name = "Apple";
food.food_value = 10;
```

### Clases (tipos por referencia)

```go
Foo :: class {
    value: int = 10;
    position: v2 = {12, 34};
}

foo := new(Foo);
```

Los campos de clase pueden tener valores predeterminados. Una clase derivada puede sobrescribir los valores predeterminados heredados sin redeclarar el campo:

```go
Enemy :: class {
    health: int = 100;
    speed: float = 3.0;
}

Boss :: class : Enemy {
    health = 500;
    speed = 1.5;
}
```

### Herencia

Los structs/clases pueden heredar de otros structs/clases:

```go
Animal :: class {
    name: string;
    age: int;
}

Dog :: class : Animal {
    breed: string;
}

dog := new(Dog);
dog.name = "Buddy";
dog.age = 5;
dog.breed = "Labrador";
```

## Procedimientos y métodos

### Procedimientos (`proc`)

```go
add :: proc(a: int, b: int) -> int {
    return a + b;
}

result := add(2, 4); // 6
```

Los procedimientos son valores normales y pueden asignarse/almacenarse como cualquier otro valor:

```go
op := proc(a: int, b: int) -> int { return a + b; };
op = proc(a: int, b: int) -> int { return a * b; };
```

### Métodos (`método`)

Usa `method()` dentro de un struct/class. Los métodos tienen un parámetro implícito por referencia `this` de referencia.

```go
Dog :: class {
    name: string;

    bark :: method() {
        log_info("% says bark!", {name});
    }
}

dog := new(Dog);
dog.name = "Buddy";
dog.bark();
```

### Acceso a campos vs llamadas a métodos

Usa `.` tanto para campos como para métodos:

```go
hp := player.health;        // acceso a campo
player.respawn();          // llamada a método
entity.set_local_scale({2, 2});
```

{% hint style="info" %}
Cualquier procedimiento puede llamarse como un “método” si su primer parámetro coincide con el tipo del receptor. Los métodos reales y los campos de tipo valor de procedimiento tienen prioridad antes de que CSL recurra a un procedimiento libre coincidente.
{% endhint %}

## Arrays

CSL tiene algunos tipos “similares a arrays” que usarás constantemente:

* **Arreglos fijos**: `[4]int`
* **Slices / arreglos administrados**: `[]T` (a menudo usado como “vista de solo lectura” de un array)
* **Arreglos dinámicos**: `[..]T` (lista redimensionable)
* **Arrays no gestionados**: `[^]T` (usado en firmas de API integradas como `format_string`, `log_info`, etc. — pasa valores como `{a, b, c}`)

Los arrays dinámicos exponen `.data`, `.count`, y `.capacity`, y usan sintaxis de llamada a método para las operaciones:

```go
numbers: [..]int;
numbers.append(10);
numbers.append(20);

log_info("count: %", {numbers.count});
log_info("first: %", {numbers[0]});
```

Para una guía completa (incluidos los patrones de eliminación), consulta [Arreglos y colecciones](/all-out-docs/docs-es/programacion/arrays-and-collections.md).

## Flujo de control

### Si / else

```go
if hp <= 0 {
    die();
} else if hp < 25 {
    Notifier.notify(player, "¡Salud baja!");
} else {
    // todo bien
}
```

### Switch

Usa `default:` para la cláusula predeterminada. Los cases admiten **múltiples valores** (separados por comas) y **rangos**. No hay fallthrough al estilo C.

```go
Item_Tier :: enum {
    COMMON;
    UNCOMMON;
    RARE;
    EPIC;
    LEGENDARY;
}

get_tier_color :: proc(tier: Item_Tier) -> v4 {
    switch tier {
        case .COMMON:              return {0.7, 0.7, 0.7, 1.0};
        case .UNCOMMON:            return {0.3, 0.8, 0.3, 1.0};
        case .RARE, .EPIC:         return {0.3, 0.5, 1.0, 1.0};
        case .LEGENDARY:           return {1.0, 0.8, 0.2, 1.0};
        default:                   return {1, 1, 1, 1};
    }
}

// Casos por rango
get_difficulty :: proc(level: int) -> string {
    switch level {
        case 1..5:          return "Easy";
        case 6..<11:        return "Medium";
        case 11..20, 25:    return "Hard";
        default:            return "Unknown";
    }
}
```

`..` incluye ambos extremos. `..<` excluye el extremo superior.

### While / for

```go
while condition {
    // ...
}

// Rango inclusivo: 0..9 incluye 9
for i: 0..9 {
    log_info("i=%", {i});
}

// Rango semiabierto: 0..<count excluye count
for i: 0..<items.count {
    log_info("item %", {items[i]});
}

// Iteración inversa
for i: 0..<items.count #reverse {
    log_info("reverse item %", {items[i]});
}

// Iterar elementos de array/slice
for item: my_items {
    // ...
}

// Con variable de índice
for item, i: my_items {
    log_info("item % at index %", {item, i});
}

// Iterar iteradores personalizados (común para entidades/componentes)
for enemy: component_iterator(Enemy) {
    enemy.update_ai();
}
```

Basado en iterador personalizado `for` los bucles requieren un `next :: method() -> bool` y un `campo` .

## Conversión de tipos

Usa `expr.(T)` o `cast(T)expr` Para convertir:

```go
a := 123.4;
b := a.(int);   // 123
c := cast(float)b; // 123.0
```

Cuando el tipo objetivo ya se conoce, puedes dejar que CSL lo infiera:

```go
i: int = a.;
j: int = cast a;
```

## Pasar por referencia: `ref` (preferido)

Cuando necesites modificar un parámetro, **prefiere `ref`** en lugar de punteros en bruto.

```go
update_position :: proc(pos: ref v2, velocity: v2, dt: float) {
    pos.x += velocity.x * dt;
    pos.y += velocity.y * dt;
}

my_pos := v2{0, 0};
update_position(ref my_pos, {10, 5}, 0.16);
```

## Callbacks: punteros a funciones + userdata (sin cierres)

CSL no tiene cierres. En línea `proc(...) { ... }` no pueden capturar variables circundantes.

Para transportar contexto, combina los callbacks con un `campo userdata: Object` campo:

```go
Player :: class : Player_Base {
    on_death_userdata: Object;
    on_death: proc(player: Player, userdata: Object);

    die :: method() {
        si on_death != null {
            on_death(this, on_death_userdata);
        }
    }
}

Death_Tracker :: class : Component {
    count: int;

    ao_start :: method() {
        player := entity.get_component(Player);
        player.on_death_userdata = this;
        player.on_death = proc(player: Player, userdata: Object) {
            tracker := userdata.(Death_Tracker);
            tracker.count += 1;
        };
    }
}
```

## Información de tipos (tipos como valores)

`typeid` los valores pueden pasarse a procs polimórficos:

```go
default_of :: proc($T: typeid) -> T {
    t: T;
    return t;
}

a := default_of(int);      // 0
b := default_of(string);   // ""
c := default_of([4]int);   // {0, 0, 0, 0}
```

## Buenas prácticas (CSL en All Out)

* **Evita el estado global de jugabilidad.** Se conectan varios jugadores: guarda el estado por jugador en `Player` en su lugar.
* **Dibuja toda la UI del jugador desde `Player.ao_late_update`.** Envuélvelo en `is_local_or_server()`.
* **Usa `is_local()` solo para invalidaciones visuales específicas del jugador.** No cambies el estado de jugabilidad ni de la UI dentro de él.
* **Valores predeterminados orientados a móvil.** No dependas del teclado/ratón a menos que tu juego esté explícitamente enfocado en PC.
* **Si no estás seguro de la sintaxis o las API**, abre el `.csl_engine` archivo correspondiente en `api_references/` de tu proyecto.
