> 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/conceptos-basicos-del-motor/abilities.md).

# Habilidades

Las habilidades son la forma estándar de implementar las acciones del jugador con:

* Una interfaz de botones coherente que funciona bien en móvil y en PC.
* Tiempos de reutilización
* Apuntado opcional (tocar/arrastrar en móvil, apuntar con el ratón en PC)

Las habilidades son **por jugador**. Cuando un jugador se une, All Out crea una instancia de cada tipo de habilidad y la almacena en `player.abilities`.

### Inicio rápido (dibujar botones de habilidad)

Dibuja los botones de habilidad en `Player.ao_late_update`, dentro de `is_local_or_server()`:

```go
Player :: class : Player_Base {
    ao_late_update :: method(dt: float) {
        if this.is_local_or_server() {
            draw_ability_button(this, Shoot_Ability, 0);  // botón principal grande
            draw_ability_button(this, Dodge_Roll, 1);     // botón pequeño
        }
    }
}
```

{% hint style="info" %}
Los índices de los botones se asignan a posiciones fijas en pantalla. El índice `0` es el botón principal grande; los índices `1-5` son botones más pequeños alrededor de él.
{% endhint %}

### Referencia de la API de habilidades

```go
Ability_Base :: class {
    player: Player;

    name: string;
    icon: Texture_Asset;

    current_cooldown: float;
    type: typeid;
    is_aimed_ability: bool;
    mouse_position_on_press: v2;

    keybind_override: Keybind;
    disable_keybind: bool;
    draw_but_dont_use_keybind: bool; // Muestra la sugerencia de tecla, pero gestiona su entrada tú mismo.

    #interface on_update      :: proc(ability: Ability_Base, params: ref Ability_Update_Params);
    #interface can_use        :: proc(ability: Ability_Base) -> bool;
    #interface on_draw_button :: proc(ability: Ability_Base, rect: Rect);
}

Ability_Update_Params :: struct : Interact_Result {
    can_use: bool;        // enfriamiento + can_use + Player.ao_can_use_ability (si está presente)
    drag_offset: v2;      // 0..1
    drag_direction: v2;   // dirección unitaria
}

draw_ability_button :: proc(player: Player, $T: typeid, index: int);
```

### Crear una habilidad (clic básico)

```go
Dash_Ability :: class : Ability_Base {
    on_init :: method() {
        name = "Dash";
        icon = get_asset(Texture_Asset, "icons/dash.png");
    }

    can_use :: method() -> bool {
        // Gating adicional opcional (además del enfriamiento)
        return true;
    }

    on_update :: method(params: ref Ability_Update_Params) {
        if params.clicked && params.can_use {
            // Aplica aquí la jugabilidad. Esta ruta pasa por la predicción del cliente y en el servidor.
            // ...

            // IMPORTANTE: establece el enfriamiento cuando la actives
            current_cooldown = 1.5;
        }
    }
}
```

### Habilidades mantenidas (activas mientras se mantenga pulsado)

Para habilidades que están activas mientras se mantienen pulsadas (sprint, escudo, rayo), usa `Ability_Utilities.update_holding_ability` para que funcione tanto en PC como en móvil.

```go
keybind_sprint: Keybind;

ao_before_scene_load :: proc() {
    keybind_sprint = Keybinds.register("Sprint", .LEFT_SHIFT);
}

Sprint_Ability :: class : Ability_Base {
    on_init :: method() {
        name = "Sprint";
        draw_but_dont_use_keybind = true;
        keybind_override = keybind_sprint;
    }

    on_update :: method(params: ref Ability_Update_Params) {
        holding := Ability_Utilities.update_holding_ability(player, ref params, keybind_sprint);
        player.is_sprinting = holding.active;
    }
}
```

### Habilidades con apuntado (arrastrar para apuntar en móvil)

Si quieres un comportamiento de “apuntar siempre” (apuntar con el ratón + clic para disparar en PC, pulsar-arrastrar-soltar en móvil), usa `Ability_Utilities.full_update_aimed_ability`:

```go
Shoot_Ability :: class : Ability_Base {
    on_init :: method() {
        name = "Shoot";
        is_aimed_ability = true;
        disable_keybind = true;
    }

    on_update :: method(params: ref Ability_Update_Params) {
        activation := Ability_Utilities.full_update_aimed_ability(player, ref params);

        if activation.activate && params.can_use {
            // activation.direction es un vector unitario
            // shoot_projectile(player.entity.world_position, activation.direction);
            current_cooldown = 0.5;
        }
    }
}
```

Si quieres un comportamiento de “clic para entrar en modo apuntado” (en PC alterna el modo apuntado; clic derecho cancela), usa `Ability_Utilities.full_update_targeted_aimed_ability`:

```go
Roll_Ability :: class : Ability_Base {
    on_init :: method() {
        name = "Roll";
        is_aimed_ability = true;
    }

    on_update :: method(params: ref Ability_Update_Params) {
        activation := Ability_Utilities.full_update_targeted_aimed_ability(player, this, ref params);
        if activation.activate && params.can_use {
            current_cooldown = 1.25;
        }
    }
}
```

### Restricciones de habilidades a nivel global (opcional)

Implementa `ao_can_use_ability` en tu `Player` clase para imponer reglas globales (los jugadores muertos no pueden usar habilidades, deshabilitadas durante las cinemáticas, etc.).

```go
Player :: class : Player_Base {
    ao_can_use_ability :: method(ability: Ability_Base) -> bool {
        if health.is_dead return false;
        return true;
    }
}
```

### Buenas prácticas

* Dibuja siempre los botones en `ao_late_update` y protege con `is_local_or_server()`
* Establece `current_cooldown` cuando la actives (de lo contrario se puede spamear)
* Usa `Ability_Utilities` ayudantes para mantener/apuntar para que móvil + PC se comporten de forma coherente
* Pon las reglas globales en `Player.ao_can_use_ability`, no duplicadas por cada habilidad
