> For the complete documentation index, see [llms.txt](https://claude.fractalgamestudios.es/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://claude.fractalgamestudios.es/bolas/game-info/modo-boss-fight.md).

# Modo Boss Fight

### 2026-08-04 (implementación del modo BossFight de cero: jefe de 10.000 de vida, dos equipos, barra de vida estilo Minecraft)

Nuevo `/goal`: montar el modo **BossFight**, que hasta ahora solo existía como decorado — la arena (`Workspace.BossFight.BossFight`), el hitbox de la lobby (`Workspace.Lobbies.BossFight`) y una entrada en `LobbyConfig` estaban puestos, pero **ningún código sabía qué es un Boss**: la tabla `ArenaConfig.Boss` (con la vida y el tamaño ya escritos) no la leía nadie, y arrancar una partida de BossFight solo creaba seis bolas normales peleando entre sí.

Pedido literal: jefe con **10.000 de vida**, **el resto de estadísticas normales**, **tamaño x4 en bola y arma**, **dos equipos como el 3v3** (uno el Boss — "que no deja de ser un bot en verdad" — y el otro jugadores + bots de relleno), **barra de vida de boss como en Minecraft**, el Boss **aparece en el centro de la part `Floor`** de la arena, los atacantes en el suelo de `NoBossFloor`, el Boss **no se mueve** y **atraviesa** ese suelo, y se puede entrar **global, local o con party** (party: elemento aún no definido).

#### Geometría real de la arena (los números que hacen que todo encaje)

La arena `BossFight` tiene **dos suelos superpuestos**, y esa es la clave del modo:

| Part          | Centro                      | Tamaño                            | Cara superior |
| ------------- | --------------------------- | --------------------------------- | ------------- |
| `Floor`       | `(-1408.99, 109.37, 25.56)` | `90 × 2 × 90`                     | `Y = 110.37`  |
| `NoBossFloor` | `(-1408.99, 115.14, 25.56)` | `90 × 2 × 90` (transparencia 0.4) | `Y = 116.14`  |

El detector genérico de suelos de `ArenaBuilder` se queda siempre con el **más alto** — o sea `NoBossFloor` —, así que los atacantes ruedan a `Y = 118.64` (`116.14 + radio 2 + 0.5`), que es justo lo que se quiere. El Boss, con radio `2 × 4 = 8`, se apoya sobre el suelo **bajo**: centro en `(-1408.99, 118.37, 25.56)`. Resultado: la esfera del Boss va de `Y = 110.37` a `Y = 126.37` y **atraviesa** `NoBossFloor`, dejando \~10 studs de esfera asomando por encima del suelo por el que ruedan los atacantes — exactamente lo pedido. No hizo falta ningún grupo de colisión para el "atraviesa": las dos parts (Boss y `NoBossFloor`) están **ancladas**, y dos parts ancladas simplemente se solapan sin que la física intente separarlas.

La arena tiene 6 `SpawnPointA` (los atacantes) y 1 `SpawnPointB`; **`SpawnPointB` se queda sin usar** — el Boss se coloca por código en el centro de `Floor`, tal y como se pidió, no en ese spawn (que además está descentrado, en `(-1398.57, ..., 39.98)`).

#### Arquitectura

* **`ServerStorage.Classes.BallSystem.BossFactory`** (nuevo). Crea la bola del jefe: x4, 10.000 de vida, color morado, **anclada** (no se le montan ni el motor de movimiento, ni el `AlignPosition`, ni la gravedad, ni el rescate anti-atasco — todo eso existe para bolas que ruedan). Lo único que se mueve del Boss es su arma: el `HingeConstraint` que monta `WeaponSystem` funciona igual con la bola anclada, tratándola como base fija y haciendo girar el `WeaponRotator` a su alrededor. Los `Attachment` (`HittedAttach`, `WeaponAttach`) se escalan x4 con la bola, porque sus posiciones estaban calibradas para el radio 2 por defecto.
* **Equipos**: `Boss` vs `Attackers`, escritos en el atributo `Team` de cada bola — el mismo que ya usaban `WeaponSystem`/`BallFactory` para filtrar el fuego amigo, así que los atacantes no se hacen daño entre ellos sin tocar nada más. A los atacantes se les pasa `teamColor = nil` **a propósito**: en 3v3 el color de equipo es la única forma de distinguir bandos, pero aquí el bando contrario es UNA bola gigante morada — forzarles un color único (`FORCE_TEAM_COLORS` en `BallFactory`) solo les quitaría su skin sin aportar nada.
* **`MinPlayers`/`MaxPlayers` de `LobbyConfig.BossFight` cuentan solo a los ATACANTES** (bajado de 7 a 6, que son los 6 `SpawnPointA`). El Boss **no sale de la cola**: lo crea `ArenaManager.StartMatch` aparte. Si contase en la cola, el matchmaking podría acabar metiendo a un jugador real en el papel de Boss.
* El Boss se crea **antes** que los atacantes, no después: si se creara al final existiría una ventana en la que el equipo `Boss` aún no tiene a nadie registrado, y cualquier muerte en ese instante habría dado la partida por ganada a los atacantes.
* **Arma del Boss fija a `Sword`** (`ArenaConfig.Boss.WeaponType`) en vez de la aleatoria que da `BotManager`: el Boss está anclado, así que su única forma de hacer daño es el arma girando: un arma de proyectil o `Unarmed` dependen del movimiento de la propia bola y darían un jefe impredecible o inofensivo. `BotManager.createProfile` acepta ahora dos parámetros opcionales (`weaponIdOverride`, `nameOverride`) para eso; sin ellos se comporta exactamente igual que siempre.

#### Bug real encontrado: `Model:ScaleTo` es ABSOLUTO, no relativo

El código de escalado del arma del Boss ya existía en `WeaponSystem.rebuildWeapons` (lee el atributo `WeaponScaleMultiplier`), pero **nunca se había ejecutado** porque nadie ponía ese atributo. Al activarlo por primera vez salió el bug: hacía `model:ScaleTo(weaponScale)`, y `ScaleTo` significa *"ponte a escala N respecto a como te modelaron"*, no *"hazte N veces más grande de lo que se te ve ahora"*. Los modelos de arma de este proyecto **no están guardados a escala 1** — vienen de Blender con `Model.Scale ≈ 0.0684` (`DefaultWeapon_A/B/C`) y `≈ 0.0584` (`ImperialWeapon_A/B`).

Resultado medido en playtest: la espada del Boss salía a **x58** (`4 / 0.0684 = 58.4`) en vez de x4 — una hoja de **176 × 294 × 27 studs** cuyo centro quedaba a 155 studs de la bola, barriendo la arena entera (90 × 90) de punta a punta. Mataba a los seis atacantes en unos 20 segundos sin que ninguno llegara siquiera a acercarse al jefe.

**Arreglo**: `model:ScaleTo(model:GetScale() * weaponScale)` — multiplicar por la escala ACTUAL del modelo, así sale el x4 real que se pide sea cual sea la escala con la que se guardó cada arma. Verificado midiendo: bola del Boss `16.0` studs y arma `12.08 × 20.13 × 1.84` = exactamente 4× la de un atacante (bola `4.0`, arma `3.02 × 5.03 × 0.46`) — misma proporción bola/arma (1.26) en los dos.

#### Arreglo colateral necesario: el equipo ganador no llegaba a los muertos

`didPlayerWin` leía el equipo del atributo `Team` de la **bola** del jugador, pero para cuando se llama esa función la bola de cualquiera que haya muerto ya está destruida (`disintegrateCharacter` la borra 1s después de morir, y `EndRound` llega 2s después del último fallecido). Con eso, **todo el que muriese antes del final quedaba registrado como DERROTA aunque su equipo ganase** — un bug que ya existía en 3v3, pero que en BossFight es la norma y no la excepción (lo esperable es caer antes de que el jefe muera). Arreglado con un registro `participantTeams` (participante → equipo) fijado al crear cada bola, que sobrevive a la destrucción de la bola; `checkWinCondition` también lee de ahí ahora. De paso, `checkWinCondition` se generalizó a una tabla `TEAM_MODES` en vez de tener el 3v3 escrito a mano, así que 3v3 y BossFight comparten exactamente la misma lógica (incluido el respaldo por muerte simultánea de la sesión del 2026-08-02).

#### Barra de vida estilo Minecraft

* `BossFactory` marca la bola con el atributo **`IsBoss`**; `Front.Controllers.CombatController` (que ya escaneaba todas las bolas de la partida y escuchaba sus atributos) lo expone como `isBoss` en su tipo `Combatant`. El cliente **no necesita saber en qué modo está**: si hay una bola con `IsBoss`, hay barra.
* Nueva vista **`Front.Modules.BossBar.BossBar`**, `sticky` como `CombatHUD`/`LobbyJoinPanel` (registrada en `Front.Router.routes` y `Front.Router.RouterView`): barra ancha y baja centrada arriba, nombre en mayúsculas encima, vida en número a la derecha y **10 segmentos separados por muescas verticales**, como la del Wither/Dragón. Colores nuevos `Theme.Colors.Boss` / `BossDark` (magenta sobre casi negro) — no reutiliza `Danger` (rojo) a propósito, porque el rojo ya significa "vida baja" dentro de las propias barras y la del jefe tiene que leerse como "esto es el jefe" incluso estando llena.
* `CombatHUD` **deja de listar al Boss** como una tarjeta lateral más (sería duplicar su vida en dos sitios, y con 10.000 puntos su barra no se parece en nada a las de los demás), y **baja sus dos columnas 58px** mientras haya jefe en partida: en una ventana estrecha la barra es lo bastante ancha como para llegar hasta donde empieza la columna izquierda.

#### Entrada al modo

**Global y local ya funcionan sin tocar nada**: el panel de unión (`Front.Modules.LobbyJoinPanel`) y las dos colas (`LocalLobbyService` y `GlobalMatchmakingService`) son genéricas por modo y leen el atributo `ArenaMode` del hitbox, que en `Workspace.Lobbies.BossFight.Hitbox` ya vale `"BossFight"`. **Party sigue sin implementarse** — el propio pedido lo marca como "elemento no definido"; no existe ningún sistema de party en el proyecto (`PartyController_DEPRECATED` está deshabilitado). Cuando se defina, el sitio donde engancharlo es `Lobby/JoinQueue` en `LobbyController`, que ya distingue `requestType` (`LocalMulti` / `GlobalMulti`).

#### Validación en playtest (partidas reales completas, no revisión de código)

* **Partida real por la cola local** (`Lobby/JoinQueue` → temporizador de 20s → relleno con 5 bots → `MatchStarter.Initiate` → `ArenaManager.StartMatch`): 6 atacantes + 1 Boss. Verificado por inspección del servidor: `Boss_ball` con `Team=Boss`, `IsBoss=true`, `Health=10000/10000`, `Size=16.0`, `Anchored=true`, posición exacta `(-1408.99, 118.37, 25.56)` (centro de `Floor` + radio), `WeaponScaleMultiplier=4`; atacantes con `Team=Attackers`, `Size=4.0`, a `Y=118.64` sobre `NoBossFloor`.
* **Captura de pantalla**: bola morada gigante en el centro atravesando el suelo de cristal, su espada x4 girando, los 6 atacantes rodando alrededor, barra `BOSS 9992 / 10000` segmentada arriba del todo y las dos columnas del `CombatHUD` desplazadas por debajo de ella, sin el Boss entre ellas.
* **Victoria del Boss**: partida natural completa, `¡EQUIPO BOSS GANA!` con el jefe "Vivo" y los 6 atacantes "Eliminado".
* **Victoria de los atacantes**: forzando `Health = 0` en el Boss, `¡EQUIPO ATTACKERS GANA!` con el Boss "Eliminado" — y un atacante que había muerto ANTES sale igualmente en el bando ganador.
* **Persistencia del resultado para un jugador muerto de un equipo ganador** (el arreglo de `didPlayerWin`): matado el jugador real primero y el Boss después → `Wins` pasó de **23 a 24** y `Losses` se quedó en **38**. Antes del arreglo habría contado derrota.
* Sin errores nuevos en `get_runtime_logs` en ninguna de las partidas.

#### Observación de equilibrio (decisión del usuario, no cambiada)

Con las estadísticas pedidas al pie de la letra, **el Boss gana con muchísima holgura**. Medido en la partida natural completa: duró **42 segundos**, murieron los 6 atacantes y **el Boss terminó con \~9.992 de 10.000** (menos del 0,1% de su vida). El motivo es estructural, no un bug: los atacantes tienen 100 de vida y hacen \~1–2,5 de daño por golpe (con `HIT_COOLDOWN` de 0,4s), así que quitarle 10.000 puntos exige varios minutos de golpes ininterrumpidos, mientras que el arma x4 del jefe barre un radio enorme y su daño por golpe (escalado de `Sword`) sube hasta \~9–33 en menos de un minuto. Palancas para ajustarlo, todas en `ArenaConfig.Boss`, si se quiere que sea ganable: bajar `WeaponScale` (menos alcance del barrido), cambiar `WeaponType`, o subir la vida/daño de los atacantes. **No se ha tocado nada**: las estadísticas son exactamente las pedidas.

#### Pendiente / avisos para la siguiente sesión

1. **`LobbyConfig.BossFight.PlaceId` es inventado** (`352735233760132`, ya venía marcado `-- invent` en el código). En Studio da igual (la arena vive en el mismo server, ver `MatchStarter`), pero **en producción ni la cola local ni la global podrán teletransportar a nadie** hasta que se publique un place real para BossFight y se ponga aquí su PlaceId.
2. **Incoherencia preexistente entre `GameSettings.Places` y `LobbyConfig`**: `GameSettings.Places.BossFight.PlaceId = 113735233768813` es exactamente el PlaceId que `LobbyConfig` asigna a **BattleRoyale**, y `GameSettings.Places.BattleRoyale` usa otro distinto (`113691792337207`). `GameSettings.Places` solo lo consume `GamemodeController_DEPRECATED` (deshabilitado), así que hoy no rompe nada, pero hay que decidir cuál de las dos tablas es la buena antes de publicar.
3. **Bug preexistente, no relacionado con BossFight, detectado al encadenar partidas rápido**: `ArenaManager.EndRound` programa `cleanup()` a los 8 segundos (`RESULTS_DURATION`), pero `sessionActive` pasa a `false` al instante. Si en esos 8 segundos arranca una partida NUEVA, el `cleanup()` retrasado de la anterior destruye las bolas y el estado de la nueva (`activeBalls` y compañía son estado de módulo, no de la ronda). Reproducido dos veces durante las pruebas. Arreglo natural: que el `cleanup()` retrasado capture y limpie solo lo de SU ronda.
4. **Party** sin definir (ver arriba).

#### Archivos

**Nuevos:** `ServerStorage.Classes.BallSystem.BossFactory`, `ReplicatedStorage.Front.Modules.BossBar.BossBar`.

**Tocados:** `ServerStorage.Data.LobbyConfig` (BossFight: `MaxPlayers` 7→6 + documentación), `ServerStorage.Classes.Arena.ArenaConfig` (`Boss.WeaponScale` 3.5→4, `Boss.WeaponType` nuevo), `ServerStorage.Managers.BotManager` (parámetros opcionales `weaponIdOverride`/`nameOverride`), `ServerStorage.Classes.BallSystem.WeaponSystem` (arreglo de `ScaleTo`), `ServerScriptService.Managers.ArenaManager` (equipos, alta del Boss, `TEAM_MODES`, `participantTeams`, `freezeAndCenterSurvivors` sin mover al Boss, `CameraHeights.BossFight`), `ReplicatedStorage.Front.Controllers.CombatController` (`isBoss`), `ReplicatedStorage.Front.Modules.CombatHUD.CombatHUD` (filtra al Boss + hueco superior), `ReplicatedStorage.Front.Shared.Theme` (`Colors.Boss`/`BossDark`), `ReplicatedStorage.Front.Router.routes` y `RouterView` (registro de `BossBar`).

**Sin cambios (ya eran genéricos por modo):** `LobbyController`, `LocalLobbyService`, `MatchStarter`, `GlobalMatchmakingService`, `ArenaBuilder`, `LobbyJoinPanel`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://claude.fractalgamestudios.es/bolas/game-info/modo-boss-fight.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
