
PersonalPlayground
IDEAS.md — Banco de features para Mech Brawlers
Para el modelo que implemente esto: cada idea es autocontenida e incluye diseño (qué se siente jugar), números iniciales (balance de partida, ajustables) y guía de implementación (archivos y enfoque concretos de ESTE repo). Implementa UNA idea por vez, valida con
python3 -m gdtoolkit.parser(no hay Godot CLI en esta máquina) y actualiza el README. Respeta las convenciones existentes: constantes de balance en la cabecera del script, comentarios en español sin tildes, catálogo compartido víapreload(sinclass_name), y las cosas que se eligen en el lobby viajan porSessionData.current_match_loadout.
Mapa del código (referencia rápida):
| Sistema | Archivo |
|---|---|
| Mecha (movimiento, energia, armas, IA de bots) | entities/player/MechaPlayer.gd |
| Piloto (eyección, escudo, canalización de rebuild) | entities/player/Pilot.gd |
| Chatarra | entities/interactables/Scrap.gd |
| Catálogo de personalización (piezas/chasis/armas) | entities/player/MechaParts.gd |
| Flujo de partida, spawns, countdown, leaderboard | scenes/TestLevel.gd (compartido por los 3 mapas) |
| Estado de sesión (jugadores, loadout, wins, settings) | autoloads/SessionData.gd |
Audio (SFX generados con tools/gen_audio.py) | autoloads/AudioManager.gd |
| Lobby / personalización / votación de mapa | scenes/menus/PreMatchMenu.gd, MechaCustomizationMenu.gd, MapSelectionMenu.gd |
| HUD por jugador | systems/ui/PlayerHUD.gd |
| Cámara compartida | systems/camera/DynamicCamera.gd |
1. Gameplay — Combate
1.1 Habilidad por chasis (identidad activa, no solo stats)
Diseño. Hoy el chasis solo cambia velocidad/HP/escala. Darle a cada uno una habilidad activa (botón dedicado, p. ej. LB / E) crea identidad de "clase":
- LIGERO — Blink Dash: teletransporte corto (6 m) en la dirección de movimiento, 2 cargas, recarga 5 s por carga. Deja una estela fantasma.
- MEDIO — Pulso EMP: onda expansiva (radio 6 m) que no daña pero empuja
proyectiles enemigos (invierte
directionde losCannonBallen el área) y frena 40% por 1.5 s a los Mechas alcanzados. Cooldown 8 s. - PESADO — Ground Slam: salto corto + caída que genera onda de choque (radio 5 m, 20 de daño, knockback fuerte, sacude la cámara). Cooldown 10 s.
Implementación. En MechaParts.CHASSIS añadir "ability" (string) y
mostrarla en la card del menú de chasis (MechaCustomizationMenu._build_chassis_row).
En MechaPlayer.gd: constantes ABILITY_*, un ability_cooldown, input nuevo
(teclado E, joypad JOY_BUTTON_LEFT_SHOULDER — hoy libre), y un match por
chasis. El EMP puede iterar get_tree().get_nodes_in_group("projectiles")
filtrando por distancia. Los bots la disparan con probabilidad por tick cuando
aplica (dash al recibir daño, slam con 2+ enemigos cerca).
1.2 Melee con identidad por brazos
Diseño. Los brazos (ESTÁNDAR/PÚGIL/GARRA) hoy son cosméticos. Diferenciarlos:
- ESTÁNDAR: el melee actual (50 daño, knockback).
- PÚGIL: +daño (65), −alcance, y el knockback aturde 0.4 s (el objetivo no puede disparar).
- GARRA: −daño (35) pero roba 10 de energía al objetivo y golpea en arco
más amplio (rotar
melee_area±30° durante el golpe).
Implementación. Igual que las armas: constantes MELEE_* en
MechaPlayer.gd, match _variant("arms") dentro de melee_attack(). El stun
es un timer stunned_until que bloquea el bloque de disparo en
_physics_process. Actualizar descripciones en MechaParts.OPTIONS["arms"] y
el comentario de qué piezas afectan gameplay.
1.3 Cuarta arma: LANZAMINAS
Diseño. Dispara una mina que se pega al piso donde cae (arco corto, ~8 m). Arma hasta 3 minas activas; la más vieja explota al colocar la cuarta. Explota por proximidad (radio 2 m, 45 de daño) o a los 15 s. Las minas brillan del color del dueño (los rivales pueden verlas y dispararles para detonarlas). Coste 25 de energía. Convierte al jugador en controlador de zona — counter natural del OBÚS que ancla al que carga.
Implementación. Añadir entrada a MechaParts.OPTIONS["weapon"] y variante
3 en _build_weapon_details (caja + tubo corto inclinado). Nueva escena
entities/weapons/Mine.tscn (Area3D, como CannonBall.tscn pero estática con
timer). En MechaPlayer.gd: rama 3 en _handle_weapon_input y en el match
de bots (los bots la sueltan al estar a 4–8 m del objetivo, o al huir). Llevar
las minas vivas en un array del shooter para el límite de 3.
1.4 Hazards de arena activos
Diseño. Cada mapa gana un peligro periódico propio, telegrafiado 2 s antes:
- GRID HOLO: columnas de la grilla que se "des-renderizan" (agujeros de caída falsa: hacen 15 de daño y te re-materializan en el centro).
- ARENA PRIME: la prensa/imán de la chatarrería barre una franja (daño 30 + knockback fuerte). Las franjas hazard naranjas ya existentes marcan el borde.
- CRÁTER: los géiseres de las esquinas erupcionan (área 3 m, 25 de daño + lanzamiento vertical), y las grietas del shader de lava podrían iluminarse más fuerte durante el aviso.
Implementación. Script nuevo systems/arena/ArenaHazard.gd (Node3D con
@export var interval/warn_time/damage/area) instanciado en cada .tscn de
nivel sobre las posiciones deseadas. El aviso es un MeshInstance3D con
material emisivo pulsante; el golpe, un intersect_shape en capa 2 (mismo
patrón que fire_beam en MechaPlayer.gd). TestLevel.gd no necesita
cambios si el hazard es autónomo.
1.5 Overheat con contrajuego: venteo manual
Diseño. Estando sobrecalentado, mantener el botón de escudo 1 s ejecuta un "venteo": el Mecha queda inmóvil, expulsa vapor y recupera energía al doble de velocidad. Convierte el overheat de espera pasiva en decisión de riesgo.
Implementación. En MechaPlayer.gd, dentro del bloque de overheat: si
shield_pressed y is_overheated, acumular vent_timer; al pasar 1 s,
current_energy += 40.0 * delta y velocity a cero. Partículas: reutilizar
el patrón de materiales emisivos procedurales. Bots: ventean si no hay
enemigo a menos de 8 m.
2. Gameplay — Piloto y reconstrucción
2.1 El Piloto puede secuestrar Mechas enemigos vacíos
Diseño. Si un Mecha rival está destruido y su Piloto anda lejos, el Piloto
propio puede canalizar 4 s sobre el cadáver para robarlo: renace con 40% de
HP, pintado mitad y mitad (el sistema apply_foreign_paint ya tiñe piezas).
El dueño original ve un aviso y su Piloto gana +15% de velocidad ("rabia")
hasta recuperar chatarra suficiente para reconstruir otro.
Implementación. En Pilot.gd, al detectar cercanía a un Mecha con
is_dead == true que no es original_mecha, ofrecer el prompt de canalización
(reutilizar la plataforma holográfica del rebuild con otro color). Al completar,
transferir input_device_id/is_bot al Mecha robado, llamar rebuild() con
target_hp = max_hp * 0.4 y re-vincular original_mecha de ambos pilotos.
Cuidado con el hilo de IA: explode()/rebuild() ya manejan start/stop.
2.2 Scrap-denial: quemar chatarra ajena
Diseño. Disparar a un scrap ajeno 2 veces lo destruye (hoy la chatarra es intocable). Le quita economía de rebuild al rival a cambio de munición y tiempo de puntería. El scrap propio no se puede quemar (evita griefing accidental del propio equipo en modos por equipos).
Implementación. Scrap.gd: añadir hp := 2 y take_damage(); al morir,
efecto de chispas + sfx "drop". CannonBall._on_body_entered ya llama
take_damage sobre cualquier body que lo tenga — solo hay que asegurarse de
que el Scrap esté en una capa que las balas colisionen (mask 3) y filtrar
shooter == owner_mecha.
2.3 Mochila del Piloto: llevar 1 scrap encima
Diseño. El Piloto puede cargar físicamente UN scrap (se le monta en la espalda, visible) y soltarlo donde quiera. Permite "mudar" la economía a una esquina segura antes de canalizar, a costa de −20% de velocidad mientras carga.
Implementación. Pilot.gd: al recoger con un input dedicado (mantener la
tecla de interacción), reparentar el mesh del scrap a un Marker3D en la
espalda y marcar el scrap como carried (sin hitbox). Soltar lo re-instancia
a los pies. La lógica de conteo de scraps del rebuild no cambia: el scrap
cargado cuenta como "en el suelo" solo al soltarlo.
3. Rejugabilidad y progresión de sesión
3.1 Torneo local (primera a N victorias) con marcador persistente
Diseño. En el lobby, elegir "PARTIDA RÁPIDA" o "TORNEO A 3/5/7". En torneo,
tras cada ronda el PostMatch muestra el marcador acumulado (ya existe
SessionData.player_wins por color) y rota automáticamente al siguiente mapa
votado. Al llegar al objetivo: pantalla de campeón con el Mecha ganador en
grande sobre el pedestal del showcase, lluvia de confeti de su color y stats
de la serie (kills, scraps, rebuilds).
Implementación. SessionData: tournament_target := 0 (0 = rápida) y
round_stats. PreMatchMenu: selector arriba junto a COMENZAR.
PostMatchMenu.gd: si hay torneo y nadie llegó al target, botón "SIGUIENTE
RONDA" que salta directo a MapSelectionMenu conservando el loadout (ya viaja
en SessionData.current_match_loadout). La pantalla de campeón puede
reutilizar MechaShowcase3D.tscn con la customización del ganador.
3.2 Mutadores de partida (votados u ocultos)
Diseño. Al votar mapa, una tercera columna sortea 1 mutador (o "NINGUNO"):
- Energía infinita (sin overheat, caos de gatlings),
- Un solo HP (todo mata; el rebuild revive con 1 HP también),
- Gravedad lunar (
gravity *= 0.4, saltos flotados), - Chatarra doble (10 scraps por muerte),
- Velocidad x1.5 para todos,
- Sin escudos.
Implementación. SessionData.active_mutator: String. Un diccionario
MUTATORS en un nuevo systems/match/Mutators.gd (RefCounted, mismo patrón
que MechaParts.gd) con apply(mecha) por mutador; TestLevel._ready() lo
aplica a cada Mecha tras el spawn y ajusta lo global (gravedad se lee de
ProjectSettings en MechaPlayer, así que multiplicar mecha.gravity
directamente). MapSelectionMenu sortea y lo anuncia junto al mapa elegido.
3.3 Estadísticas y títulos de fin de partida
Diseño. Al final de cada ronda, además del leaderboard: premios estilo "party game" que dan personalidad aunque pierdas — Verdugo (más kills), Fénix (más rebuilds), Chatarrero (más scraps), Pacifista (menos daño hecho, gana igual), Kamikaze (más autodestrucciones). Cada premio muestra la card del Mecha con su decal.
Implementación. Contadores en MechaPlayer/Pilot (kills requieren
atribuir el shooter en take_damage — añadir parámetro opcional attacker
y propagarlo desde CannonBall, fire_beam y melee_attack). TestLevel
agrega los totales a SessionData.round_stats; PostMatchMenu los pinta.
3.4 Desbloqueables por sesión (decals y colores especiales)
Diseño. Colores metálicos (oro, cromo) y 3 decals extra que se desbloquean
por logros de la sesión: ganar con full-charge del obús, ganar sin morir,
ganar 3 seguidas. Se anuncian en el PostMatch ("¡Desbloqueaste ORO!") y quedan
disponibles en la paleta del lobby hasta cerrar el juego (o persistir en
user://unlocks.cfg si se quiere entre sesiones).
Implementación. SessionData.unlocked_colors/decals + chequeo de
condiciones en show_leaderboard(). PreMatchMenu.palette y
MechaParts.OPTIONS["decal"] se extienden en runtime leyendo esos arrays
(OPTIONS es const: usar un getter static func decal_options() que concatene).
4. Nuevos modos de juego
Patrón general:
SessionData.game_mode: String, seleccionado en el lobby (fila de botones bajo el título).TestLevel.gdya centraliza spawn, countdown y condición de fin — extraer la condición de victoria a un método_check_win_condition()y hacermatch SessionData.game_modeahí dentro es el 80% del trabajo de cada modo.
4.1 REY DE LA CHATARRA (King of the Hill)
Diseño. Una zona circular (anillo holográfico, 6 m) aparece en el mapa. Estar dentro sin rivales suma puntos (1/s); gana el primero en llegar a 60. La zona se muda a otra posición cada 25 s. Estar en zona da un brillo del color del ocupante. Fuerza el conflicto constante y castiga esconderse — y el OBÚS de área ancha se vuelve herramienta de desalojo.
Implementación. systems/match/HillZone.gd (Area3D cilíndrica + torus
emisivo). Posiciones candidatas: reutilizar los SpawnPoints del nivel.
Marcador: labels de color en un CanvasLayer (el patrón de _run_countdown).
Fin de partida: en vez de "último vivo", scores[color] >= 60. Los muertos
reviven solos a los 5 s (en este modo el Piloto/rebuild puede desactivarse
para mantener el ritmo: flag respawn_mode en TestLevel).
4.2 FIEBRE DEL SCRAP (recolección competitiva)
Diseño. Llueven scraps neutrales (grises) del cielo cada pocos segundos. Cada Mecha tiene un contenedor en su esquina; hay que recoger scrap y depositarlo en el contenedor propio (entrar al área lo descarga). Primer equipo/jugador con 15 gana. Puedes matar para hacer soltar lo que el rival lleva encima (hasta 3 slots por Mecha). Combina combate con courier-play.
Implementación. Reutiliza casi todo Scrap.gd (con owner_mecha = null y
color gris). MechaPlayer gana carried_scraps := 0 (el HUD ya muestra
energía; añadir contador). Contenedores: Area3D por jugador con su color en
posiciones de spawn. Al morir, soltar los scraps cargados (igual que suelta
el Piloto). Condición de fin en _check_win_condition().
4.3 JUGGERNAUT (1 vs todos rotativo)
Diseño. Un jugador es el Juggernaut: chasis PESADO forzado con x2 HP, gatling infinita y +15% velocidad. Los demás cooperan para derribarlo; quien le da el golpe final se convierte en el nuevo Juggernaut y hereda el marcador. Gana quien acumule 90 s total como Juggernaut. Perfecto para 3–6 jugadores de niveles dispares (los novatos cooperan, el bueno tanquea).
Implementación. TestLevel: variable juggernaut: MechaPlayer, aplicar
buffs con overrides sobre move_speed/max_hp tras _apply_chassis_stats() y
un aura visual (anillo hp_ring escalado + luz). En take_damage ya se puede
saber el atacante si se implementó 3.3. Timer por jugador en un dict.
Los no-Juggernaut no se dañan entre sí (chequear en take_damage con un flag
de modo).
4.4 DUELO DE PILOTOS (modo fiesta, ronda corta)
Diseño. Nadie tiene Mecha: todos son Pilotos con su pistolita, HP mínimo, y hay UN solo Mecha vacío en el centro. Quien lo alcanza y canaliza primero aplasta al resto... pero el Mecha aparece con 30% de HP y los Pilotos pueden concentrar fuego para destronarlo. Última persona viva gana la ronda; primera a 3 rondas gana. Rondas de <90 s, cero downtime.
Implementación. TestLevel con flag de modo: spawnear Pilotos directamente
(ya existe todo el flujo de Pilot.tscn y su combate) y un MechaPlayer con
is_dead = true en el centro esperando canalización (el flujo de rebuild de
Pilot.gd ya lo contempla — solo hay que permitir canalizar un Mecha que no es
original_mecha, mismo cambio que la idea 2.1). Sin countdown de scraps: la
canalización en este modo no exige chatarra (flag).
4.5 HORDA (cooperativo vs oleadas)
Diseño. 1–4 jugadores contra oleadas de bots que crecen (oleada N: N+1
bots, cada 3 oleadas entra un "élite" PESADO con obús). Entre oleadas hay 15 s
para recoger scrap y reconstruir caídos. Se termina al caer todos: el score es
la oleada alcanzada, con récord de sesión en SessionData. Da un modo PvE que
enseña las armas sin presión de PvP.
Implementación. El spawner reutiliza el loop de spawn de TestLevel._ready
con MechaParts.random_custom() para variedad visual. Los bots enemigos entran
en un "equipo": no se atacan entre sí — el filtro está en find_aim_target() y
el loop de IA (shared_targets hoy incluye a todos; filtrar por
get_meta("team")). El fin de oleada revive Pilotos caídos automáticamente.
4.6 EQUIPOS 2v2 / 3v3
Diseño. En el lobby, arrastrar cards a dos columnas (o botón "EQUIPO A/B" en cada card). Fuego amigo apagado, colores forzados a la gama del equipo (rojos vs azules — la paleta ya tiene variantes), y el anillo de HP muestra el símbolo del equipo. Condición de victoria: último EQUIPO en pie; los scraps de un aliado pueden usarse para reconstruirlo (rebuild asistido: dos pilotos canalizando dividen el tiempo a la mitad).
Implementación. slot["team"] en PreMatchMenu.player_slots/bot_slots y
en el loadout. mecha.set_meta("team", n) al spawnear. Filtros: en
take_damage (ignorar daño de mismo team salvo knockback reducido), en
find_aim_target() y en el thread de IA. El rebuild asistido toca
Pilot.gd (contar pilotos aliados canalizando el mismo Mecha).
5. Bots más interesantes
5.1 Personalidades de IA
Diseño. Cada bot sortea una personalidad que sesga sus timers ya existentes: Agresivo (rangos de fuego más cortos, más melee), Francotirador (mantiene 12–20 m, prefiere obús cargado), Carroñero (prioriza scraps y huye con poca vida), Guardaespaldas (en equipos, orbita a un aliado). Mostrar la personalidad bajo el nombre del bot en su card del lobby.
Implementación. MechaPlayer: bot_profile: Dictionary con
multiplicadores (fire_min/max, preferred_dist, flee_hp_ratio) sorteado en
_ready() y usado por _bot_ai_thread_loop en lugar de los literales. La
huida: si current_hp < flee_hp_ratio * max_hp, invertir want_dir y buscar
el scrap más cercano (pasar posiciones de scraps por shared_targets con un
segundo array shared_scraps).
5.2 Dificultad seleccionable por bot
Diseño. Botón en la card del bot (FÁCIL/NORMAL/DIFÍCIL). Fácil: +50% en
timers de fuego, ±8° de error de puntería, no ventea ni usa habilidades.
Difícil: −30% timers, esquiva lateral al detectar un obús cargando cerca
(leer is_charging de los rivales en el snapshot del hilo), usa el melee al
tener rival aturdido.
Implementación. bot_slots[i]["difficulty"] en PreMatchMenu → loadout →
mecha.bot_difficulty. El error de puntería se aplica en el bloque de aim del
bot en _physics_process (rotar target_pos unos grados aleatorios). El
"esquivar obús" requiere compartir is_charging de los targets en
shared_targets (convertirlo en array de dicts {pos, charging} — tocar
también el consumidor).
6. UX / UI / Onboarding
6.1 Pantalla de controles + práctica en el countdown
Diseño. El countdown de 3 s es poco para leer nada. Añadir en el lobby un botón "¿CÓMO SE JUEGA?" que abre un overlay con el mapeo visual de mando y teclado (dibujado con Controls, sin imágenes externas) y las 5 reglas de oro (mueres → eres Piloto → junta 3-5 scraps → canaliza → vuelves). Además, un modo práctica: entrar solo con 0 bots deja un dummy estático que muestra números de daño flotantes.
Implementación. Overlay: escena nueva scenes/menus/HowToPlay.tscn
siguiendo el patrón CanvasLayer + cierre con B/ESC de
MechaCustomizationMenu.gd. Números de daño: en take_damage, instanciar un
Label3D (el patrón exacto ya existe en TestLevel._add_name_tag) con el
número, tween hacia arriba y queue_free. El dummy: MechaPlayer con
controls_enabled = false e HP infinito.
6.2 Killfeed y anuncios de partida
Diseño. Esquina superior: "ROJO destruyó a AZUL (OBÚS FULL)", "VERDE se autodestruyó", "AMARILLO reconstruyó su Mecha". Anuncios grandes para hitos: "¡DOBLE BAJA!" si un haz mata a 2, "¡ÚLTIMO MECHA!" cuando quedan 2 jugadores.
Implementación. Autoload ligero o nodo en TestLevel: Killfeed.gd con
announce(text, color) que apila labels con fade-out. Requiere atribución de
atacante (idea 3.3). El "doble baja" se detecta en fire_beam contando
víctimas del mismo disparo.
6.3 Indicadores off-screen
Diseño. Flechas en el borde de pantalla apuntando a: tu Piloto (si tu Mecha murió y la cámara está lejos), scraps propios, y el Juggernaut/zona en esos modos. Color = color del dueño.
Implementación. systems/ui/OffscreenIndicators.gd (CanvasLayer): por
target, camera.unproject_position(); si queda fuera del rect visible,
clampear al borde con margen y rotar la flecha hacia el punto. La cámara es
única (DynamicCamera), lo que lo hace barato.
6.4 Vibración de mando (juice barato)
Diseño. Rumble corto al: recibir daño (fuerte), disparar obús full (medio), overheat (doble pulso), countdown GO (suave). Solo al device del jugador.
Implementación. Input.start_joy_vibration(device_id, weak, strong, duration)
en los puntos correspondientes de MechaPlayer.gd (guard con is_bot y
input_device_id >= 0).
7. Audio / Visual
7.1 SFX propios para las armas nuevas
Diseño. La gatling y el obús reutilizan "shoot" con pitch. Sonidos
dedicados: gatling (tick metálico corto), beam_charge (rampa ascendente en
loop mientras carga, pitch sube con charge), beam_fire (zap grave + cola).
Implementación. tools/gen_audio.py ya tiene osciladores/envelopes
(osc, noise, env_adsr, write_wav) y cada SFX es una función sfx_*.
Añadir las 3 funciones, regenerar (python3 tools/gen_audio.py), registrar en
AudioManager.SFX_STREAMS y reemplazar las llamadas en MechaPlayer.gd. Para
la rampa de carga: un AudioStreamPlayer dedicado en el Mecha cuyo
pitch_scale = 1.0 + charge se actualiza en _update_charge.
7.2 Música dinámica por intensidad
Diseño. battle_theme sube una capa (más percusión) cuando quedan ≤2
Mechas o alguien carga un obús full. Bajada suave al resolverse.
Implementación. Generar una segunda pista alineada (battle_theme_intense)
con gen_audio.py, reproducir ambas en paralelo sincronizadas y crossfadear
volúmenes en AudioManager (set_intensity(0..1) llamado desde TestLevel).
7.3 Restos de combate persistentes
Diseño. Las explosiones dejan marcas: decal oscuro simple (quad con material quemado) y 2–3 piezas de escombro físico (RigidBody pequeño que se duerme). El haz del obús deja una línea chamuscada 10 s. La arena cuenta la historia de la ronda.
Implementación. En explode() y fire_beam: instanciar quads con
material oscuro semitransparente sobre el piso (raycast hacia abajo para
altura), con límite global (pool de 30, FIFO) para no acumular draw calls en
el renderer mobile.
8. Técnico / Infraestructura
8.1 Replay de la jugada final (kill cam)
Diseño. Al terminar la ronda, repetición de los últimos 5 s desde una cámara cercana al ganador antes del leaderboard (skippeable).
Implementación. Grabador barato: cada 0.1 s, guardar
{pos, rot, aim, anim_state} de cada Mecha en un ring buffer (50 frames).
Para reproducir: congelar gameplay (get_tree().paused, los actores del
replay en PROCESS_MODE_ALWAYS), mover "cáscaras" visuales interpolando el
buffer. No simular física: solo transforms.
8.2 Pantalla dividida opcional (cámara por jugador)
Diseño. Hoy hay una cámara compartida; con 2 jugadores en mapas grandes
se sufre. Opción en OPCIONES: "Cámara: COMPARTIDA / DIVIDIDA (2P)". Dividida:
dos SubViewports lado a lado, cada uno con su DynamicCamera siguiendo a un
jugador.
Implementación. TestLevel: si el setting está activo y hay exactamente 2
humanos, mover el World3D a un contenedor de 2 SubViewportContainer
(world_3d compartido entre viewports, cámara propia por viewport). El HUD de
cada jugador va al viewport correspondiente. Es el cambio más invasivo de esta
lista — hacerlo detrás de un flag y con fallback limpio.
8.3 Guardado de loadouts favoritos
Diseño. En la pantalla de personalización, botón "GUARDAR COMO FAVORITO"
(3 slots). En el lobby, mantener X sobre la card carga el favorito 1. Persiste
en user://loadouts.cfg.
Implementación. SessionData: save_loadout(slot, custom) /
load_loadout(slot) con ConfigFile (mismo patrón que save_settings).
UI: fila de 3 botones en MechaCustomizationMenu bajo el chasis.
8.4 Suite de smoke-tests sin editor
Diseño. Script que valida lo validable sin Godot CLI: parseo gdtoolkit de
todos los .gd, consistencia de .tscn (refs/ids/parents — ya existe el
patrón en los scripts de validación usados en este repo), y chequeos de
contrato (que MechaParts.OPTIONS tenga las mismas keys que usa
_build_*_details, que todo play_sfx("x") exista en SFX_STREAMS).
Implementación. tools/check.py ejecutable con python3 tools/check.py;
los chequeos de contrato son greps estructurados sobre los fuentes. Documentar
en README como paso previo a probar en el editor.
Prioridades sugeridas
| Nivel | Ideas | Racional |
|---|---|---|
| Alto impacto / bajo esfuerzo | 1.5 venteo, 3.3 stats+títulos, 6.2 killfeed, 6.4 rumble, 7.1 SFX armas, 2.2 quemar scrap | Juice y legibilidad inmediatos con poco riesgo |
| Alto impacto / esfuerzo medio | 3.1 torneo, 4.1 King of the Hill, 3.2 mutadores, 5.1/5.2 bots, 1.1 habilidades de chasis | Rejugabilidad estructural |
| Apuestas grandes | 4.5 horda, 4.6 equipos, 4.3 juggernaut, 8.1 killcam, 8.2 split-screen | Modos completos; hacer tras estabilizar lo anterior |
Orden recomendado si se implementa en serie: 3.3 (atribución de daño — es dependencia de killfeed, juggernaut y títulos) → 6.2 → 3.1 → 4.1 → 3.2 → 5.1 → 1.1 → resto según feedback de juego real.