# Full Dominoes — Pack de Experiencia 01

Contiene la capa de movimiento (ondas, fondos vivos, tienda con volumen,
sala con jerarquía) y la corrección de dos reglas del motor que hoy hacen
que el juego anote distinto según cómo cierre la mano.

---

## 1. Archivos

| Archivo | Destino | Tipo |
|---|---|---|
| `public/assets/css/fd-experiencia.css` | `public/assets/css/` | **nuevo** |
| `public/assets/js/fd-experiencia.js` | `public/assets/js/` | **nuevo** |
| `public/assets/js/fd-fondo-vivo.js` | `public/assets/js/` | **nuevo** |
| `includes/DominoEngine.php` | `includes/` | **reemplaza** |

Nada de esto pisa `estilos.css`, `sala.js` ni `tienda-carrusel.js`. Si algo
no te gusta, quitas las 3 líneas del HTML y vuelve todo como estaba.

---

## 2. Integración (3 líneas por pantalla)

En `index.html`, `home.html`, `sala.html`, `tienda.html`, `tienda_vip.html`,
`ranking_global.html`, `comprar_monedas.html`, `final.html`:

**En el `<head>`, DESPUÉS de `estilos.css`:**

```html
<link rel="stylesheet" href="assets/css/fd-experiencia.css?v=1">
```

**Antes de `</body>`, al final de todos los scripts:**

```html
<script src="assets/js/fd-experiencia.js?v=1"></script>
<script src="assets/js/fd-fondo-vivo.js?v=1"></script>
```

Orden importante: `fd-experiencia.js` primero (es el que pone la clase
`.fd-vivo` en el `<body>`), `fd-fondo-vivo.js` después.

En `tienda.html` la ruta del CSS es la misma; recordá subir el `?v=` para
que el WebView de Android no sirva la versión cacheada.

---

## 3. Qué se activa solo y qué hay que llamar a mano

### Automático (cero código adicional)
- Ondas al pulsar en todo botón, `<a>`, `[role=button]`, `.btn-articulo`,
  `.chip-config-mesa`, `.tab-categoria` — **incluidos los que viven dentro
  del Shadow DOM** de los `<btn-*>` y del `<tienda-carrusel>`.
- Onda **dorada** en acciones de valor (el texto contiene comprar / jugar /
  recargar / reclamar / equipar / VIP…), turquesa en el resto.
- Relieve + brillo que barre en `.boton-grande`, `.boton-dorado`, `.btn-articulo`.
- Fondo vivo (aurora + polvo de luz + viñeta que respira) en cualquier
  `<body>` con `fondo-dominos`, `fondo-interior`, `fondo-tienda-pro`,
  `fondo-mesa-juego`, `tienda-pro`.
- Vibración corta en Android real.
- Guardián de FPS: si baja de 40 fps en los primeros 4 s, apaga solos los
  efectos caros y deja el juego intacto.

### Llamadas opcionales (3 líneas donde ya tenés el código)

**En `tienda-carrusel.js`**, donde hoy pintás cada tarjeta de artículo,
agregá las clases:

```js
tarjeta.classList.add('fd-card-3d');            // volumen + tilt al tocar
if (articulo.equipado) tarjeta.classList.add('fd-card-destacada'); // aro de luz
```

y al terminar de pintar la grilla:

```js
FDExperiencia.escalonar(contenedor.querySelectorAll('.item-articulo'));
```

Después de una compra exitosa (donde hoy hacés `mostrarExito`):

```js
FDExperiencia.celebrarCompra(tarjetaDelArticulo);   // destello + chispas
FDExperiencia.destacarNumero(document.getElementById('status-monedas'));
```

**En `sala.js`**, cuando cambie el turno:

```js
document.body.classList.toggle('fd-mi-turno', this.esMiTurno());
```

y cuando cambie el marcador:

```js
FDExperiencia.destacarNumero(elMarcador, 'fd-anota');
```

**En cualquier botón que dispare un `fetch`:**

```js
FDExperiencia.botonCargando(boton, true);
// ... await apiPost(...)
FDExperiencia.botonCargando(boton, false);
```

---

## 4. Parche de `PartidaService.php` (obligatorio con el nuevo motor)

`DominoEngine.php` mantiene las firmas viejas, así que **no se rompe nada
si no lo tocás** — pero mientras no apliques estos 3 cambios el desempate
de tranca y el conteo de pegada siguen con el comportamiento anterior.

### 4.1 — `aplicarJugadaInterna()`, cierre por pegada (~línea 351)

```php
// ANTES
$puntos = DominoEngine::puntosPorPegada($manosPorUsuario, $usuarioId, $modoConteo);

// DESPUÉS
$puntos = DominoEngine::puntosPorPegada($manosPorUsuario, $usuarioId, $modoConteo, $equipoPorUsuario);
```

`$equipoPorUsuario` ya está construido tres líneas más arriba.

### 4.2 — `aplicarJugadaInterna()`, cierre por tranca (~línea 379)

```php
// ANTES
$resultado = DominoEngine::resolverTranca($manosPorUsuario, $equipoPorUsuario, $partida['modo_conteo'] ?? 'enemigos');
self::finalizarRonda($db, $partidaId, $partida, $resultado['equipoGanador'], $resultado['puntosAnotados'], 'tranca', null, null);

// DESPUÉS
$resultado = DominoEngine::resolverTranca($manosPorUsuario, $equipoPorUsuario, $partida['modo_conteo'] ?? 'enemigos', $usuarioId);
if ($resultado['equipoGanador'] === null) {
    // Empate real y sin trancador conocido: la mano no anota, se reparte de nuevo.
    self::finalizarRonda($db, $partidaId, $partida, 'A', 0, 'tranca_empate', null, $usuarioId);
} else {
    self::finalizarRonda($db, $partidaId, $partida, $resultado['equipoGanador'], $resultado['puntosAnotados'], 'tranca', $ficha, $usuarioId);
}
```

Fijate que además ahora se pasan `$ficha` y `$usuarioId`: eso llena
`ficha_cierre` y `jugador_cierre_id` en `ultima_ronda_json`, que hoy llegan
en `null` y por eso el resumen de fin de mano no puede mostrar con qué
ficha ni quién trancó.

### 4.3 — `avanzarTurnoSinJugar()` (~línea 590)

Mismo cambio, pero acá el que trancó es el último que jugó, no el que
pasó. Ese dato no se está guardando: agregá una columna
`ultimo_jugador_id INT NULL` a `partidas`, escribila en cada jugada, y
pasala como cuarto argumento. Mientras tanto, con `null` el empate se
resuelve como "nadie anota" — que sigue siendo más justo que darle
siempre los puntos al equipo A.

---

## 5. Cosas que dejé sin tocar a propósito

- **Rediseño estructural de la sala** (dónde va cada avatar, tamaño del
  tablero, mano del jugador). Eso necesita ver capturas del celular real
  en horizontal; tocarlo a ciegas es la forma más rápida de romper el
  layout que ya te costó estabilizar.
- **`interacciones-3d.js`**: sigue funcionando igual y no choca con este
  pack. El tilt de ahí mueve el botón; las ondas de acá solo pintan
  encima, por eso sí se aplican a los `<btn-*>` sin cancelar el click en
  Android.
