> 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/core-engine-concepts/abilities.md).

# Abilities

Abilities are the standard way to implement player actions with:

* A consistent button UI that works well on mobile and PC.
* Cooldowns
* Optional aiming (tap/drag on mobile, mouse aim on PC)

Abilities are **per-player**. When a player joins, All Out creates an instance of each ability type and stores it on `player.abilities`.

### Quick start (draw ability buttons)

Draw ability buttons in `Player.ao_late_update`, inside `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);  // big primary button
            draw_ability_button(this, Dodge_Roll, 1);     // small button
        }
    }
}
```

{% hint style="info" %}
Button indices map to fixed screen positions. Index `0` is the large primary button; indices `1-5` are smaller buttons around it.
{% endhint %}

### Ability API reference

```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; // Show the key hint, but handle its input yourself.

    #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;        // cooldown + can_use + Player.ao_can_use_ability (if present)
    drag_offset: v2;      // 0..1
    drag_direction: v2;   // unit direction
}

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

### Creating an ability (basic click)

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

    can_use :: method() -> bool {
        // Optional extra gating (in addition to cooldown)
        return true;
    }

    on_update :: method(params: ref Ability_Update_Params) {
        if params.clicked && params.can_use {
            // Apply gameplay here. This path runs through client prediction and on the server.
            // ...

            // IMPORTANT: set cooldown when you activate
            current_cooldown = 1.5;
        }
    }
}
```

### Holding abilities (active while held)

For abilities that are active while held (sprint, shield, beam), use `Ability_Utilities.update_holding_ability` so it works on both PC and mobile.

```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;
    }
}
```

### Aimed abilities (drag to aim on mobile)

If you want “always aiming” behavior (mouse aim + click to fire on PC, press-drag-release on mobile), use `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 is a unit vector
            // shoot_projectile(player.entity.world_position, activation.direction);
            current_cooldown = 0.5;
        }
    }
}
```

If you want “click to enter aim mode” (PC toggles aim mode; right-click cancels), use `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;
        }
    }
}
```

### Game-wide ability restrictions (optional)

Implement `ao_can_use_ability` on your `Player` class to enforce global rules (dead players can't use abilities, disabled during cutscenes, etc).

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

### Best practices

* Always draw buttons in `ao_late_update` and guard with `is_local_or_server()`
* Set `current_cooldown` when you activate (otherwise it can be spammed)
* Use `Ability_Utilities` helpers for holding/aiming so mobile + PC behave consistently
* Put global rules in `Player.ao_can_use_ability`, not duplicated per ability
