> 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. Está tipado estáticamente y se parece más a Go/Odin, excepto **el estado del gameplay 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 proyecto nuevo, All Out genera un `main.csl` en la carpeta `scripts/` carpeta de tu proyecto.

```go
import "core:ao"

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

ao_before_scene_load :: proc() {
    // Registrar definiciones de objetos, monedas, etc.
    // Se ejecuta antes de que se cree la escena.
}

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

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

ao_late_update :: proc(dt: float) {
    // Se llama en cada fotograma 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 une 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` debería 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, **importar en `main.csl` solo**. No esparzas 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>;
```

Ya sea `<tipo>` o `<expresión>` puede omitirse:

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

// Inferencia de tipo
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, arreglos 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 inicializarse con constantes en tiempo de compilación, incluidas estructuras, arreglos, 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 la vida de la instancia del script. Evita usarlas para el estado de juego 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`

### 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 tipo
```

## Estructuras y clases

Las estructuras son **tipos por valor** (se copian al asignar). 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 de 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

Las estructuras/clases pueden heredar de otras estructuras/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 una estructura/clase. Los métodos tienen un parámetro de referencia implícito `this` .

```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 `.` para tanto campos como 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 receptor. Los métodos reales y los campos con valor de procedimiento del tipo tienen prioridad antes de que CSL recurra a un procedimiento libre que coincida.
{% endhint %}

## Arreglos

CSL tiene unos pocos tipos “similares a arreglos” que usarás constantemente:

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

Los arreglos 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

### If / 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 casos admiten **múltiples valores** (separados por comas) y **rangos**. Sin 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 de rango
get_difficulty :: proc(level: int) -> string {
    switch level {
        case 1..5:          return "Fácil";
        case 6..<11:        return "Medio";
        case 11..20, 25:    return "Difícil";
        default:            return "Desconocido";
    }
}
```

`..` 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 en reversa
for i: 0..<items.count #reverse {
    log_info("reverse item %", {items[i]});
}

// Iterar elementos de arreglos/slices
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 `current` .

## Conversión

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`** sobre punteros crudos.

```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 función + userdata (sin cierres)

CSL no tiene cierres. Los `proc(...) { ... }` en línea no pueden capturar variables del entorno.

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

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

    die :: method() {
        if 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 procedimientos 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}
```

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

* **Evita el estado global del gameplay.** Se conectan varios jugadores — guarda el estado por jugador en `Player` su lugar.
* **Separa la lógica cosmética de la lógica de gameplay.** Usa `is_local()` para UI/partículas solo locales, y `is_local_or_server()` para entradas de gameplay que deben ejecutarse en el servidor + cliente local.
* **Valores predeterminados para móviles.** No dependas de la entrada de teclado/ratón a menos que tu juego esté claramente enfocado a PC.
* **Si no estás seguro sobre la sintaxis o las APIs**, consulta la `api_reference/` carpeta generada en tu proyecto (contiene la última `core.csl` superficie).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.allout.game/all-out-docs/docs-es/programacion/syntax.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
