> 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/player-model.md).

# Añadir lógica del jugador

En All Out, el jugador es un objeto de jugabilidad de primera clase. Tu `Player :: class : Player_Base` es donde pones **estado por jugador** (salud, equipamientos, tiempos de reutilización, alternadores de UI, progresión, etc.).

{% hint style="warning" %}
Asume que hay múltiples jugadores conectados. Evita el estado global que se rompería cuando haya más de un jugador.
{% endhint %}

## Estado por jugador

Guarda el estado de jugabilidad en el jugador o en objetos poseídos por el jugador.

```go
Player :: class : Player_Base {
    health: int;
    inventory_open: bool;
}
```

## Servidor + cliente: ¿qué se ejecuta dónde?

All Out sincroniza automáticamente el estado de jugabilidad desde el servidor a los clientes. Los métodos de jugabilidad se ejecutan tanto en el cliente que predice como en el servidor, así que no los protejas con `Game.is_server()`.

Dos comprobaciones comunes:

* `is_local_or_server()`: toda la UI del jugador y la entrada que produce
* `is_local()`: solo sobrescrituras visuales específicas del jugador

```go
Player :: class : Player_Base {
    ao_late_update :: method(dt: float) {
        if is_local_or_server() {
            // Dibuja aquí toda la UI del jugador y maneja su entrada.
        }

        if is_local() {
            // Aplica aquí la visibilidad específica del jugador, pero no cambies campos.
        }
    }
}
```

{% hint style="info" %}
Dibuja toda la interfaz del jugador a partir de `Player.ao_late_update` en `is_local_or_server()`. Los campos cambiados solo dentro de `is_local()` son reemplazados durante la reconciliación.
{% endhint %}

## Identidad del jugador y datos del perfil

`Player_Base` expone campos de identidad que usarás a menudo:

* `p.get_username() -> string`
* `p.get_user_id() -> string`
* `p.avatar_color`
* `p.device_kind` (`.PHONE`, `.TABLET`, `.PC`)
* `p.is_game_owner()`, `p.is_game_editor()`, `p.is_owner_or_editor()` (el propietario del juego y su equipo), `p.is_vip()`, `p.is_moderator()`, `p.is_youtuber()`
* `p.is_chat_open()` y utilidades de rectángulo de la UI como `p.get_chat_rect()`

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

## Motivos de estado temporal

Los estados del jugador como congelación, invisibilidad, ocultar el nombre, modo fantasma, bloqueo de la entrada de movimiento y bloqueo del joystick usan motivos con nombre. Los motivos se contabilizan: cada llamada a un `add_*_reason` método requiere una `remove_*_reason` llamada correspondiente.

Usa el correspondiente `has_*_reason` método cuando necesites un comportamiento tipo conjunto o evitar agregar repetidamente el mismo motivo:

```go
if !player.has_freeze_reason("cutscene") {
    player.add_freeze_reason("cutscene");
}

if player.has_freeze_reason("cutscene") {
    player.remove_freeze_reason("cutscene");
}
```

El mismo patrón está disponible para `invisibilidad`, `name_invisibility`, `name_offset`, `fantasma`, `desactivar la entrada de movimiento`y `desactivar joystick` motivos. Cada familia también tiene `has_any_*_reason()` cuando solo importa la presencia de cualquier motivo. No llames a un método add en cada fotograma: coincidir por nombre no lo hace idempotente.

## Persistencia: dónde almacenar la progresión del jugador

* **Economy**: monedas (coins/gems/xp) con persistencia automática + edición en el portal de creadores\
  Consulta [Economy](/all-out-docs/docs-es/datos-y-persistencia/economy.md).
* **Guardar**: persistencia general de clave/valor (ajustes, estado de misiones, listas de desbloqueos, etc.)\
  Consulta [Sistema de guardado](/all-out-docs/docs-es/datos-y-persistencia/save.md).
* **Inventory**: pilas/instancias de objetos en un inventario de jugador (opcionalmente guardado automáticamente)\
  Consulta [Inventory](/all-out-docs/docs-es/conceptos-centrales-del-motor/inventory.md).

## Patrón común: carga los valores guardados en `ao_start`

```go
Player :: class : Player_Base {
    xp: s64;
    selected_skin: string;

    ao_start :: method() {
        xp = Save.get_int(this, "xp", 0);
        selected_skin = Save.get_string(this, "selected_skin", "default");
    }
}
```

## Buenas prácticas

* **Mantén el estado por jugador en `Player`.** Evita las globales para cualquier cosa específica del jugador.
* **Ejecuta el gameplay en la ruta predicha compartida.** Dibuja la UI del jugador bajo `is_local_or_server()` y reserva `is_local()` para sobrescrituras visuales específicas del jugador.
* **Prefiere las APIs de persistencia integradas** en lugar de crear las tuyas propias (Economy/Save/Inventory).

## Referencia de Player\_Base

Ver `api_references/core/ao/core.csl_engine` en la carpeta del proyecto para la completa `Player_Base` API.
