# game.roster
El plantel de **Mario Kart OrigoZero Ultimate**: 16 personajes y 6 vehículos,
con las cuatro estadísticas que `game.core` convierte en conducción.
```lua
local Roster = require("game.roster")
local tune = Roster.tuning("bowser", "boulder_kart", "150cc")
-- tune.topSpeed, tune.accel, tune.turnRate, tune.chargeSpeed, tune.boostTimeMul
```
## Personajes
En el orden que pide la especificación — dentro de cada peso, de menor a mayor.
**Ligeros** (más aceleración y manejo, menos velocidad):
Bat · Baby Rosalina · Baby Daisy · Cheep Cheep · Goomba · Shy Guy · Koopa
**Medianos** (un balance de todo):
Toadette · Toad · Luigi · Mario · Waluigi · Moo Moo
**Pesados** (más velocidad y peso, menos aceleración y manejo):
Wario · Donkey Kong · Bowser
Dos parejas comparten peso exactamente, como se pidió: **Toadette con Toad**,
y **Baby Rosalina con Baby Daisy**.
La clase se lee del peso (`Core.weightClass`), y es la que da las
bonificaciones: un ligero carga derrape y salto un 10 % más rápido, un mediano
un 5 % más y sus miniturbos duran un 5 % más, y un pesado sus miniturbos duran
un 10 % más.
## Vehículos
Un kart y una moto de cada peso. Dentro de cada peso la moto pesa menos y gira
algo mejor; el kart aguanta más.
| Vehículo | Clase | Kart o moto |
|---|---|---|
| Pip Kart | ligero | kart |
| Feather Bike | ligero | moto |
| Comet Kart | mediano | kart |
| Bolt Bike | mediano | moto |
| Boulder Kart | pesado | kart |
| Ironbike | pesado | moto |
Cada vehículo trae además `bodyScale`, `wheelRadius` y `wheelWidth`, que es lo
que hace que el peso **se vea**: una moto pesada es larga y ancha de rueda, y
una ligera es estrecha y corta.
## API
| Llamada | Qué da |
|---|---|
| `Roster.character(id)` | El personaje, o el de por defecto si no se pasa id. |
| `Roster.vehicle(id)` | El vehículo, o el de por defecto. |
| `Roster.kindOf(character)` | Su clase de peso: `light`, `medium` o `heavy`. |
| `Roster.tuning(charId, vehId, classId)` | La conducción final del conjunto. |
| `Roster.accelSeconds(charId, vehId, classId)` | Cuánto tarda de 0 a tope, sin conducir. |
`Roster.DEFAULT_CHARACTER` es `mario` y `Roster.DEFAULT_VEHICLE` es
`comet_kart` — un conjunto mediano, cuya referencia son los 1,75 s de la
especificación.
# game.core
El contrato compartido de **Mario Kart OrigoZero Ultimate**. Ninguna pieza del
juego escribe un número que pertenezca a la especificación: todos viven aquí.
`require("game.core")` desde cualquier parte del mundo.
## Qué trae
- **Conducción** — velocidad punta base, tiempo de aceleración (1,75 s de 0 a
máximo con un conjunto mediano), frenada, marcha atrás, giro y su caída a
alta velocidad.
- **Las 3 cilindradas** — 50cc / 100cc / 150cc con sus multiplicadores.
- **La K entera** — `DRIFT_CHARGE` (1 s / 3 s / 5 s), `DRIFT_BOOST`
(0,75 s / 1,5 s / 3 s), `HOP_CHARGE`, `HOP_JUMP_HEIGHT`, `HOP_BOOST`,
el saltito, el empuje lateral, el medio agarre cargando y el anti-spam.
- **Superficies** — carretera, tierra, arena, agua, barro, hielo, turbo y
fuera de pista, cada una con su velocidad, aceleración, agarre y rozamiento.
- **Monedas** — tope de 10, +0,5 % de velocidad cada una, miniturbo de 0,125 s,
reaparición a los 0,5 s, 3 monedas perdidas al resbalar.
- **Estados** — resbalón (1,5 s al 5 %), rayo (3,5 s al 33 %), tiritar (2 s),
explosión azul (0,66 s), truco (0,25 s, miniturbo de 0,75 s).
- **Estadísticas** — `Core.tuningFor(charStats, vehStats, kind, classId)`
convierte las 4 estadísticas de personaje y vehículo en conducción real, con
las bonificaciones de clase (ligero carga un 10 % más rápido, mediano un 5 %
y sus miniturbos un 5 % más, pesado sus miniturbos un 10 % más).
## Uso
```lua
local Core = require("game.core")
local tune = Core.tuningFor(char.stats, veh.stats, char.kind, "150cc")
-- tune.topSpeed, tune.accel, tune.turnRate, tune.chargeSpeed, tune.boostTimeMul
```
# achievements
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this module provides and who
consumes it, then delete both comment lines. -->
TODO: describe this module.
# game.track
Los circuitos de Mario Kart OrigoZero Ultimate, construidos en código en cada
carga: nada queda congelado en la escena, así que recargar el mundo deja el
mismo circuito.
```lua
local Track = require("game.track")
local inst = Track.build("pradera")
```
## Qué construye
- La carretera, como una fila de losas solapadas un 25 % para que no se vea
ninguna juntura.
- Un bordillo claro a cada lado.
- Nada más: el suelo, el cielo y el mar son de la escena.
## Consultas que da la instancia
| Llamada | Qué responde |
|---|---|
| `inst:nearest(p)` | La muestra más cercana: `index`, `t`, `arc`, `lateral` (metros a la derecha del eje), `along`, `planDistance`, `dir`, `right`. |
| `inst:surfaceAt(p)` | `"road"` si el punto cae dentro del ancho del asfalto; si no, la superficie del circuito (`"offroad"` por defecto). |
| `inst:startPose(i)` | Posición y rumbo (grados) de la muestra `i`, que es donde aparece un kart. |
| `inst:despawn()` | Quita el circuito del mundo. |
`Track.current` es el circuito activo. Construir uno nuevo quita el anterior.
## Añadir un circuito
Una entrada en `Track.defs`: su nombre, dificultad, ancho, colores, y una lista
de puntos de control que se cierran en bucle. La curva pasa por todos ellos y el
eje Y es la altura.
| Campo | Qué es |
|---|---|
| `points` | Puntos de control `{ x, y, z }` de la vuelta. |
| `width` | Ancho del asfalto en metros. |
| `surface` | Superficie de todo lo que no sea asfalto. |
| `walled` | Si lleva muros que impiden salirse. |
| `laps` | Vueltas de la carrera. |
| `roadTint` / `kerbTint` / `groundTint` | Colores. |
| `skyPreset` / `timeOfDay` | Cielo del circuito. |
| `sea` | Preset de océano, si el circuito tiene mar. |
# Kart
El modelo de conducción de Mario Kart OrigoZero Ultimate — y la K entera.
Vive en el cuerpo del kart (el `body` del `PlayerPrototype`). Attach it there
and every joining player drives their own.
## Controles
| Tecla | Qué hace |
|---|---|
| J | Acelerar. De 0 a velocidad máxima en 1,75 s con un conjunto mediano. |
| A / D | Girar a izquierda y derecha. |
| S / O | Frenar; por debajo de cierta velocidad, marcha atrás. |
| K | Saltar, derrapar y cargar el salto cargado. |
| L | Usar el objeto. |
## La K, entera
Un toque de K en el suelo salta. Si estás girando, el salto va **hacia el lado
contrario** al derrape que vas a hacer; si no, va recto.
Al caer derrapando empiezas a cargar, y cada nivel son chispas de las ruedas y
un miniturbo al soltar la K:
| Carga | Chispas | Miniturbo |
|---|---|---|
| 1 s | azules | 0,75 s |
| 3 s | naranjas | 1,5 s |
| 5 s | arcoíris | 3 s |
Al caer del salto recto, si sigues manteniendo la K y no giras, empiezas a
cargar un **salto cargado** — con la mitad de agarre. Las ruedas sueltan dos
remolinos de viento, y soltar la K da el salto de ese nivel:
| Carga | Viento | Salto | Miniturbo al aterrizar |
|---|---|---|---|
| 0 s | gris/blanco | — | — |
| 1 s | azul | pequeño | 0,5 s |
| 3 s | naranja | mediano | 1 s |
| 5 s | arcoíris | grande | 2 s |
Antes del azul no hay nada que soltar: ni miniturbo, ni salto.
Espamear la K no da miniturbos: cada salto reinicia la carga y entre salto y
salto hay un tiempo mínimo.
## Public fields
- `characterId`, `vehicleId`, `classId` — la selección.
- `isCpu`, `cpuSkill`, `gridIndex` — la parrilla.
- `speed`, `speedRatio`, `heading`, `coins`, `lap`, `lastLapTime`, `totalTime`,
`finished` — estado que leen la cámara, el HUD y la carrera.
- `drifting`, `driftSide`, `chargeMode`, `chargeLevel`, `chargeTime` — la carga.
- `boostTime`, `boostMul`, `boostKind` — el impulso en curso.
- `airborne`, `surface`, `squishTime`, `slipTime`, `starTime`, `controlLocked`,
`gone` — el resto de estados.
- `inputMap` — el mapa de controles que activa al arrancar.
## Methods
- `:setCombo(charId, vehicleId, classId, charStats, vehStats, kind)` — fija el
conjunto y recalcula la conducción.
- `:addCoins(n)` — suma o quita monedas (y da el miniturbo de 0,125 s al coger).
- `:applyBoost(duration, mul, kind)` — un impulso, sin acumular con el que ya lleve.
- `:slip()` — resbalón: 3 monedas y vueltas al 5 % durante 1,5 s.
- `:squish()` — rayo: encogido al 33 % durante 3,5 s.
- `:star()` — estrella: inmune, un 5 % más rápido, 10 s.
- `:rescueAt(index)` — Lakitu: vuelta al punto de control.
- `:isBoosting()`, `:isImmune()`.
## Lifecycle
- `awake()` — localiza las piezas visuales del kart y le pone las chispas.
- `start()` — activa su mapa de controles y se suscribe.
- `update(dt)` — toda la conducción.
- `onDestroy()` — suelta su reclamación del mapa de controles.
## Usage
```lua
body.component.add("Kart", { inputMap = "driveKart", heading = 0, classId = "150cc" })
```
# progress
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this module provides and who
consumes it, then delete both comment lines. -->
TODO: describe this module.
# race
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this module provides and who
consumes it, then delete both comment lines. -->
TODO: describe this module.