Commit Graph

162 Commits

Author SHA1 Message Date
JailDesigner a44748c0c4 feat(border): bump del border per explosions properes a la paret 2026-05-21 22:48:49 +02:00
JailDesigner e678f8d538 feat(border): refactor a Graphics::Border amb bumps i flash verd clar per impactes contra les parets 2026-05-21 22:39:08 +02:00
JailDesigner 07985228b2 feat(playfield): refactor a Playfield amb animació de creació durant l'INIT_HUD 2026-05-21 20:44:17 +02:00
JailDesigner f30b195778 feat(grid): graella verda fosca de fons al playfield (16x8) 2026-05-21 20:16:44 +02:00
JailDesigner 8b32a0a404 fix(join): registrar el cos físic del jugador al món quan s'uneix 2026-05-21 19:44:29 +02:00
JailDesigner 51308fa25e tune(trail): vida més llarga, offset darrere i paleta vermella per al P2 2026-05-21 19:40:15 +02:00
JailDesigner 74d855357d feat(trail): estela daurada de partícules quan la nau accelera 2026-05-21 19:29:32 +02:00
JailDesigner dec72340de feat(audio): so hit.wav quan l'enemic passa a ferit 2026-05-21 19:05:42 +02:00
JailDesigner 7646daef3d tune(stages): stage 1 a 50 enemics i puja el cap de validació a 200 2026-05-21 18:58:33 +02:00
JailDesigner e6eaf870c6 tune(bullets): puja MAX_BALES a 50 i deshardcoded el slot per jugador 2026-05-21 18:51:55 +02:00
JailDesigner 0cc1f7623a feat(fireworks): burst radial blanc al explotar enemic + tuning 2026-05-21 17:41:10 +02:00
JailDesigner 56ce1a3236 feat(fireworks): infraestructura (manager + pool + render, sin spawn aún) 2026-05-21 17:22:46 +02:00
JailDesigner 2869c63517 tune(debris): N=1, shrink completo y sin herencia angular en enemigos 2026-05-21 17:11:08 +02:00
JailDesigner 87b96b8226 fix(debris): bugs rotacion cuadratica y shrink exponencial (geometria autoritativa) 2026-05-21 14:05:10 +02:00
JailDesigner 7505de074c feat(debris): rebote contra los limites del playarea (restitution 0.7) 2026-05-21 13:55:32 +02:00
JailDesigner ae1d1397b1 revert: vuelve al modelo de efd18ff + ENEMY_LIFETIME 3.0 -> 4.5 2026-05-21 13:46:25 +02:00
JailDesigner 9b25e875f3 fix(debris): bug rotacion cuadratica + shrink exponencial; geometria autoritativa 2026-05-21 13:37:12 +02:00
JailDesigner e84f555a66 fix(debris): rotación visual decae con fricción + modulada por size_factor 2026-05-21 13:23:16 +02:00
JailDesigner 048263a1d0 feat(debris): modelo INTACTO→MENGUANDO→0 (sin pop, fade-out por tamaño) 2026-05-21 12:53:01 +02:00
JailDesigner efd18ff852 feat(debris): vida híbrida (mínima + umbral velocidad) + multiplier para enemigos 2026-05-21 12:07:50 +02:00
JailDesigner e3af88ea8c tune(enemy): més empenta + cos inert quan està herit
- IMPACT_MOMENTUM_FACTOR: 1.0 → 2.0 (doble del moment de la bala).
  Pentagon Δv = 140 px/s (≈4× la seva velocity base), prou clar.
- Enemy::update: salta el switch de behavior (Pentagon zigzag,
  Quadrat tracking, Molinillo proximity-spin) mentre wounded_timer_>0.
  El enemic herit és un "cos mort" inert: només respon a la inèrcia
  del impulse rebut i a les col·lisions físiques resoltes per
  PhysicsWorld. Abans, el Quadrat renormalitzava la velocity cada 1s
  cap al ship, esborrant la inèrcia.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 11:33:03 +02:00
JailDesigner ff5dfab94d tune(bullet): empuje cuasi-físico (momento real de la bala)
Sustitueix IMPACT_IMPULSE (magnitud arbitrària radial) per
IMPACT_MOMENTUM_FACTOR (factor de transferència del moment de la bala).

El impulse ara és bullet.body.velocity * (bullet.body.mass * factor),
és a dir el moment lineal real de la bala, dirigit cap a on viatjava.
Amb factor=1.0 i la bala (m=0.5, v=700 px/s):
  - Pentagon (m=5)  → Δv = 70 px/s (doble de la seva velocity base)
  - Quadrat  (m=8)  → Δv = 44 px/s
  - Molinillo (m=4) → Δv = 88 px/s

Visiblement notable durant el segon de "ferit" abans de l'explosió.
El factor és tunable per pujar/baixar segons gusts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:37:23 +02:00
JailDesigner 2cf5292b16 feat(collision): cadena herit→sa via fregada física (Fase 6)
Systems::Collision::detectWoundedChain itera parells d'enemics: si
exactament un està herit i toquen (Physics::checkCollision), el sa entra
en estat herit propagant last_hit_by_ → la cascada de morts segueix
acreditant el shooter original. El rebot físic ja el gestiona
PhysicsWorld; aquí només propaguem l'estat.

Hook a detectAll just després de detectBulletEnemy: les balles tenen
prioritat sobre la cadena del mateix frame.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:29:29 +02:00
JailDesigner 7b24bfae94 feat(enemy): parpadeig dorat quan està herit (Fase 4)
Enemy::draw() ara, si wounded_timer_ > 0, alterna entre el color del
tipus i Defaults::Palette::WOUNDED (dorat) a Wounded::BLINK_HZ usant
fmod sobre el periode del cicle — patró reutilitzat del Ship::draw()
d'invulnerabilitat però aplicat a color en lloc de visibilitat.

A 10 Hz amb DURATION=1s dóna ~10 parpadeigs visibles abans d'explotar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:27:56 +02:00
JailDesigner 5cb547db0a feat(collision): primer impacte fereix, segon mata; mort diferida via timer (Fase 3)
- Defaults::Physics::Debris::ENEMY_VELOCITY_INHERITANCE (placeholder 1.0).
- Enemy::herir(shooter_id) emmagatzema last_hit_by_ per a atribució posterior.
- collision_system: helper anònim explodeNow(ctx, enemy, shooter_id) que
  llegeix velocity/dades ABANS de destruir() (corregeix bug latent: el codi
  anterior llegia getVelocityVector() després de destruir, que zera velocity
  → l'explosió mai heretava inèrcia).
- detectBulletEnemy: primer impacte aplica impulse + herir(); segon impacte
  sobre enemy ferit dispara explodeNow immediata.
- processWoundedDeaths: explota enemics amb wound timer expirat aquest frame.
- detectAll: processWoundedDeaths abans de detectBulletEnemy (les expiracions
  maten primer; les bales del mateix frame ja no toquen el cos destruït).

Puntos s'atribueixen a la mort real, no a l'impacte inicial.

Build neta i smoke test xvfb OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:26:13 +02:00
JailDesigner dc2824a095 feat(collision): la bala transmet impulse mass-aware al enemic (Fase 2)
- Defaults::Physics::Bullet::IMPACT_IMPULSE (50 px·s placeholder)
- detectBulletEnemy: calcula normal bullet→enemy, normalitza
  (fallback a direcció de bala o (0,-1) si estan solapats) i crida
  enemy.applyImpulse(normal * IMPACT_IMPULSE) abans de destruir.

El destruir() immediat encara zera la velocity, així que l'efecte
visual no es nota: serà visible quan la Fase 3 difereixi la mort.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:22:25 +02:00
JailDesigner d169a1997c feat(enemy): afegeix estat "wounded" amb timer i API base (Fase 1)
- Defaults::Palette::WOUNDED ({255,215,0}) dorat per a parpadeig
- Defaults::Enemies::Wounded::{DURATION, BLINK_HZ}
- Enemy: wounded_timer_, wound_expired_this_frame_
- API: herir(), isWounded(), getWoundedTimer(),
  woundExpiredThisFrame(), consumeWoundExpired(), applyImpulse()
- update() decrementa timer i marca expiració al creuar 0
- destruir() reseteja l'estat wounded

Sense efectes visuals ni canvis de comportament: cap callsite invoca
encara herir() ni applyImpulse(). Build verda i smoke test xvfb OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:20:42 +02:00
JailDesigner bb21191c5b refactor(defaults): substitueix els 999.0F restants per HIT_TIMER_INACTIVE_PLAYER 2026-05-21 09:48:20 +02:00
JailDesigner 7139dea7f6 refactor(defaults): centralitza init hud, tips, hit timer, line thickness i debug overlay 2026-05-21 09:45:55 +02:00
JailDesigner 08100f60e8 refactor(defaults): centralitza constants de bullet, ship, enemy, hud i notifier 2026-05-21 09:39:36 +02:00
JailDesigner 61ae211dab chore(iwyu): subheaders concrets i pragma exports al umbrella
Reemplaça core/defaults.hpp pels subheaders concrets a director.cpp i
config_yaml.cpp (silencia unused-includes de clangd). Marca el umbrella
amb IWYU pragma: begin_exports/end_exports per evitar falsos positius
als consumidors transitius.
2026-05-21 08:52:19 +02:00
JailDesigner 5d1dae1d86 feat(render): resolució d'offscreen configurable via YAML
Separa el tamany lògic (1280×720) del render target offscreen. Llista
tancada de 5 presets 16:9 (720p/900p/1080p/1440p/2160p) llegida de
rendering.render_{width,height} amb fallback a 1280×720 si invàlida.
Inclou API resizeRenderTarget() preparada per al menú de servei futur.
2026-05-21 08:46:22 +02:00
JailDesigner 6629e9b9aa fix(warnings): cast RAND_MAX a float per evitar conversió implícita 2026-05-21 08:16:55 +02:00
JailDesigner 329ae7a38e refactor(#28): renombrar Options → ConfigYaml + netejar aliases
Pas 7 final del hallazgo #28. La capa de game/options havia esdevingut
exclusivament una capa de persistència YAML que llegia i escrivia
Config::EngineConfig. El nom "Options" no reflectia bé aquest rol.

Canvis:

- Renomenats fitxers: game/options.{hpp,cpp} → game/config_yaml.{hpp,cpp}
  (preservant la història de git via mv).
- Renomenat namespace: Options → ConfigYaml.
- Esborrades del .hpp les referències-alias inline (window, rendering,
  player1, player2, keyboard_controls, gamepad_controls, console) que
  ja no tenien call-sites externs (només existien per a la transició).
  El .hpp ara només exposa engine_config + version + path + funcions.
- A config_yaml.cpp s'introdueixen aliases internes (anonymous namespace)
  per mantenir llegible el codi de la implementació, sense exposar-les.
- Actualitzat main.cpp per a usar ConfigYaml::*.
- Actualitzats els comentaris stale a sdl_manager.hpp, director.hpp,
  engine_config.hpp i audio.hpp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:47:18 +02:00
JailDesigner 5f6d51b6cb refactor: introduir Config::EngineConfig com a struct POD a core/
Pas 1/N del hallazgo #28. Sense canvi de comportament:

Nou: source/core/config/engine_config.hpp
- Defineix Config::EngineConfig (POD) amb les sub-structs WindowConfig,
  RenderingConfig, KeyboardBindings, GamepadBindings, PlayerBindings i
  el flag console.
- Sense singletons ni virtuals; la inversió real es fa en commits
  posteriors injectant Config::EngineConfig& per constructor.

Modificat: source/game/options.hpp
- Elimina les struct definitions locals (Window, Rendering, ...).
- Afegeix Options::engine_config (única font de veritat).
- Conserva Options::window, Options::rendering, player1, player2,
  keyboard_controls, gamepad_controls i console com a referències
  inline a camps d'engine_config. Cost runtime zero, callsites
  existents no requereixen cap canvi.

Hallazgo #28 de CODE_REVIEW.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:24:06 +02:00
JailDesigner a0c1c8342f refactor: esborrar aliases morts de game/constants.hpp (#24)
Esborrats:
- Constants::MARGIN_LEFT/RIGHT/TOP/BOTTOM (zero callers; tots els
  call-sites llegeixen Defaults::Zones::PLAYAREA directament).
- Constants::VELOCITAT i VELOCITAT_MAX (zero callers; eren els últims
  lectors de Defaults::Physics::ENEMY_SPEED/BULLET_SPEED).

Es mantenen MAX_ORNIS, MAX_BALES (sí usats a game_scene.hpp) i PI,
més els helpers de zona.

Habilita el hallazgo #25 (eliminar Defaults::Physics::ENEMY_SPEED /
BULLET_SPEED / VELOCITY_SCALE) — ja sense lectors.

Hallazgo #24 de CODE_REVIEW.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 18:18:12 +02:00
JailDesigner 11e9d6569b refactor: eliminar Options::physics/audio/gameplay (codi mort)
Aquestes tres seccions s'estaven carregant del YAML, parsejant,
validant i escrivint, però cap d'elles tenia consumidor en runtime:
- Options::physics: l'únic call-site era un std::cout informatiu a
  director.cpp:109. Ship/Enemy/Bullet llegeixen Defaults::Physics
  directament.
- Options::audio: explícitament desacoblat (audio.hpp:22-25) — la
  font de configuració era Defaults::Audio via Audio::Config.
- Options::gameplay: zero readers. Els arrays són compile-time.

Esborrats:
- Structs Physics/Gameplay/Music/Sound/Audio i les globals.
- Defaults a init(), helpers loadXxxConfigFromYaml, secció escrita
  a saveToFile, crides al loadFromFile.
- La línia "Física: rotation=..." del console output del Director.

Es manté Options::window i Options::rendering (sí utilitzats).

Hallazgo #21 de CODE_REVIEW.md (opció a: borrar).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 18:07:27 +02:00
JailDesigner 97c98272c9 refactor: consolidar Ship::isAlive/isHit/isActive en isActive()
Els tres mètodes retornaven el mateix bool a partir d'is_hit_:
  isActive() = !is_hit_   (override de Entity)
  isAlive()  = !is_hit_
  isHit()    =  is_hit_

Eren tres formes diferents de preguntar el mateix, repartides sense
criteri pels call-sites (collision_system, game_scene). Conservem
isActive() perquè és l'override polimòrfic d'Entity i esborrem els
altres dos. Actualitzats els 5 call-sites externs.

Hallazgo #11 de CODE_REVIEW.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:37:37 +02:00
JailDesigner e1d6cd1bb9 refactor: fusionar GameScene::init() al ctor (coherent amb Scene)
L'interfície Scene només declara handleEvent/update/draw/isFinished.
GameScene::init() era un mètode públic addicional que ningú (ni el
Director) cridava externament: només el propi ctor el cridava al
final. El comentari del header ("llamado por Director tras crear la
escena") era fals: el Director mai l'invoca.

TitleScene i LogoScene ja inicialitzen tot al ctor sense exposar
init(). Aquesta diferència trencava l'expectativa del lifecycle.

Movem tot el cos de init() al ctor i esborrem la declaració i la
definició. Aprofitem per:
- Eliminar el guard "if (!stage_config_)" que pressuposava re-init,
  cas que mai s'arribava a donar.
- Treure el comentari DEPRECATED sobre spawn_position_ (residu).

Hallazgo #1 de CODE_REVIEW.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:25:02 +02:00
JailDesigner e3b0958d10 refactor: eliminar doble inicialització d'enemies_ a GameScene
El ctor de GameScene ja construïa cada Enemy amb el renderer, però
init() (cridat des del propi ctor) tornava a assignar
enemies_[i] = Enemy(sdl_.getRenderer()) sobre la mateixa instància.
Treball perdut, a més d'incoherent amb ships_ i bullets_, que no es
reassignen a init() sinó que es limiten a init()/addBody.

Eliminem la reassignació i deixem només setShipPosition i addBody,
alineat amb la resta d'entitats.

Hallazgo #34 de CODE_REVIEW.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:11:47 +02:00
JailDesigner 88bb6afab1 refactor: convertir loops del ctor de GameScene a std::ranges::fill
Cppcheck (style: useStlAlgorithm) marcava els raw loops d'assignació
sobre std::array com a candidats clars per std::fill/std::generate.
Amb fill només es construeix la temporal una vegada i es copia a cada
element, en lloc de construir N temporals.

Preexistent, no introduït per cap commit recent, però el hook ho
demanava en tocar el fitxer. Es resolt el root cause en lloc de
suprimir.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:10:59 +02:00
JailDesigner 707fd29b97 refactor: eliminar Rotation3D i el seu camí de codi (codi mort)
L'struct Rotation3D, la funció apply3dRotation i el paràmetre opcional
rotation_3d de renderShape mai s'activaven en cap caller:
- Ship, Enemy i Bullet passaven explícitament nullptr.
- Title scene, logo scene, starfield, vector_text i ship_animator
  usaven el default nullptr (set els 7 callers).

CLAUDE.md descriu un sistema 3D del title screen que ja no està viu —
el comentari en ship_animator.cpp aclareix que la perspectiva s'ha
bakeat dins de la shape, així que la rotació dinàmica era residu
històric.

Esborrats: struct Rotation3D + ctors + hasRotation(), apply3dRotation(),
la branca rotation_3d a transformPoint() i el seu paràmetre, el
paràmetre rotation_3d de renderShape, i els arguments nullptr als
3 callers d'entitats.

Hallazgo #16 de CODE_REVIEW.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:50:03 +02:00
JailDesigner bbbb8d47ae Lint: rename públicos al inglés + refactor cognitive-complexity + unused-includes
Identifier-naming: rename de métodos públicos y cross-file al inglés
(camelBack), traducción de campos y locales en el proceso (TitleShip,
StageManager, SpawnController, ShipAnimator, helpers de PlayArea, etc.).

Refactor por cognitive-complexity (>25): GameScene::draw (59→3) con 9
helpers de estado, PhysicsWorld::resolveBodyCollisions (35→5) extrayendo
resolveBodyPair, Options::load{Window,Physics,Audio}ConfigFromYaml
(32/49/57→5/2/3) con templates readField, TitleScene::update (68→4) con
5 sub-pasos por estado + handleSkipInput/handleStartInput +
triggerExitForJoinedPlayers, DebrisManager::explode (39→3) con
extractSegments/spawnDebris/applyAngularVelocity/applyVisualRotation.

use-anyofallof: bucles → std::ranges::any_of/all_of en Input,
ShipAnimator y SpawnController.

readability-static-accessed-through-instance: Director::run y
VectorText::getTextWidth/Height invocados por clase.

readability-convert-member-functions-to-static: ResourcePack::decryptData.

unused-includes: eliminación de <utility>, <cstdint>, <vector>,
<iostream>, defaults.hpp y otros no usados directamente en headers y
unidades de traducción. Restablecido core/defaults.hpp en title_scene.cpp
(falsa "unused" del header).

Bug fix: eliminado isActive() duplicado en Bullet (redeclaración tras
rename de esta_activa→isActive que chocaba con el override de Entity).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:41:33 +02:00
JailDesigner 4e5ab6be1d Lint: convert-member-functions-to-static (20 hits)
Métodos privados que no consultan estado de la instancia pasan a 'static'
en la declaración del header. Las definiciones en el .cpp pierden el 'const'
trailing (incompatible con static). Cero callsites afectados: las
llamadas via 'this->method()' o sin qualifier siguen siendo válidas para
métodos estáticos.

Aplicado en:
- Shape: trim, startsWith, extractValue, parsePoints.
- VectorText: getShapeFilename, get_text_width, get_text_height.
- Pack: readFile, calculateChecksum, encryptData.
- DebrisManager: computeExplosionDirection.
- Enemy: attemptSafeSpawn.
- LogoScene / TitleScene: checkSkipButtonPressed (consulta Input singleton).
- SpawnController: get_enemics_vius.
- StageManager: processPlaying.
- ShipAnimator: updateEntering, updateFloating, updateExiting,
  configureShipP1, configureShipP2, computeOffscreenPosition.
- Director: run (los miembros executable_path_ / system_folder_ se fijan
  en el ctor y no se vuelven a leer en el loop principal).

Verificado previamente con grep que ningún '&Class::method' los usa como
function pointer (cambiar a estático cambiaría su tipo).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:22:37 +02:00
JailDesigner 6d0df85e5e Lint: rename de métodos privados (camelBack + traducción al inglés)
Tanda grande de identifier-naming: 47 métodos privados pasan de
snake_case (en su mayoría catalán/spanish) a camelBack inglés. Solo
afecta a sus archivos hpp+cpp; ningún símbolo cruza fichero (los
públicos quedan para una pasada manual con VS Code).

Renames por clase:

- ShapeLoader: resolve_path → resolvePath.
- VectorText: load_charset → loadCharset, get_shape_filename →
  getShapeFilename.
- Shape: starts_with → startsWith (cuidado de no tocar
  std::string::starts_with que también usaba), extract_value →
  extractValue, parse_center → parseCenter, parse_points → parsePoints.
- Starfield: inicialitzar_estrella → initStar, fora_area →
  isOutsideArea, calcular_escala → computeScale, calcular_brightness →
  computeBrightness.
- TitleScene: actualitzar_animacio_logo → updateLogoAnimation,
  inicialitzar_titol → initTitle.
- LogoScene: inicialitzar_lletres → initLetters, actualitzar_explosions
  → updateExplosions, canviar_estat → changeState,
  totes_lletres_completes → allLettersComplete.
- SpawnController: generar_spawn_events → generateSpawnEvents,
  seleccionar_tipus_aleatori → selectRandomType, spawn_enemic →
  spawnEnemy, aplicar_multiplicadors → applyMultipliers.
- ShipAnimator: actualitzar_entering/floating/exiting →
  updateEntering/Floating/Exiting, configurar_nau_p1/p2 →
  configureShipP1/P2, calcular_posicio_fora_pantalla →
  computeOffscreenPosition.
- GameScene: dibuixar_marges → drawMargins, dibuixar_marcador →
  drawScoreboard, disparar_bala → fireBullet, obtenir_punt_spawn →
  getSpawnPoint, unir_jugador → joinPlayer, dibuixar_continue →
  drawContinue, dibuixar_missatge_stage → drawStageMessage.
- StageLoader: parse_metadata/stage/spawn_config/distribution/multipliers/
  spawn_mode → parseMetadata/Stage/SpawnConfig/Distribution/Multipliers/
  SpawnMode, validar_config → validateConfig.
- StageManager: canviar_estat → changeState,
  processar_init_hud/level_start/playing/level_completed →
  processInitHud/LevelStart/Playing/LevelCompleted, carregar_stage →
  loadStage.

Métodos públicos y funciones libres (cross-file) quedan a propósito sin
tocar — los renombrará el usuario con la herramienta de rename de VS Code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:55:21 +02:00
JailDesigner c80212adb9 Lint: rename de locales (constants + const-ref vars)
Tanda de identifier-naming de variables y constantes locales a funciones
o archivos. Ninguno cross-file (los símbolos públicos quedan para una
pasada manual con VS Code).

- audio_adapter.cpp: path → PATH (const local en 3 funciones).
- vector_text.cpp: symbols → SYMBOLS, char_width_scaled → CHAR_WIDTH_SCALED,
  char_height_scaled → CHAR_HEIGHT_SCALED, spacing_scaled → SPACING_SCALED
  (const locales en render/renderCentered/get_text_width).
- physics_world.cpp: acceleration → ACCELERATION (const local en update).
- constants.hpp::dins_zona_joc: point → POINT.
- game_scene.cpp:
  - stepGameOver: game_over_text → GAME_OVER_TEXT.
  - dibuixar_marcador: scale/spacing → SCALE/SPACING (const), y la ref
    local 'scoreboard' (const SDL_FRect&) → 'scoreboard_zone' para no
    colisionar con Defaults::Zones::SCOREBOARD (las refs no son
    "constant" según el .clang-tidy y deben ser lower_case).
  - dibuixar_missatge_stage: max_width → MAX_WIDTH (const local).
  - dibuixar_continue: continue_text/counter_str/continues_text →
    UPPER_CASE.
- title_scene.cpp::draw (sección MAIN): spacing → SPACING, main_text →
  MAIN_TEXT, escala_main → MAIN_SCALE.
- shape_renderer.cpp: const Vec2& SHAPE_CENTRE → shape_centre (es ref,
  no constant).
- collision_system.cpp: const Vec2& POS_ENEMIC → enemy_pos (ref + traducción).
- init_hud_animator.cpp: refs ZONA → zone (en 2 funciones), SCOREBOARD →
  scoreboard_zone (sin colisionar con Defaults::Zones::SCOREBOARD).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:50:58 +02:00
JailDesigner 1214599c4c Lint: rename de helpers file-static y constexpr locales
Tanda local de identifier-naming: ningún símbolo cross-file, todo
contenido en su propio TU. De paso traduce los catalán/spanish a inglés
allá donde aplica.

- shape_renderer.cpp: apply_3d_rotation → apply3dRotation, transform_point
  → transformPoint, perspective_factor → PERSPECTIVE_FACTOR (constexpr).
- debris_manager.cpp: transform_point → transformPoint (otro file-static
  con el mismo nombre, no comparte símbolo con shape_renderer).
- logo_scene.cpp: calcular_progress_letra → computeLetterProgress.
- vector_text.cpp: char_width/char_height → BASE_CHAR_WIDTH/BASE_CHAR_HEIGHT
  (el sufijo BASE_ evita el conflicto con la macro CHAR_WIDTH de Windows
  headers que clang-tidy detectó).
- floating_score_manager.cpp::draw: constexpr scale/spacing → SCALE/SPACING.
- game_scene.cpp::dibuixar_missatge_stage: escala_base/spacing →
  BASE_SCALE/SPACING (constexpr locales).
- game_scene.cpp::dibuixar_continue: constexpr spacing → SPACING.
- game_scene.cpp en stepGameOver: constexpr scale/spacing → SCALE/SPACING.
- ship_animator.cpp::actualizar_exiting: constexpr Vec2 punt_fuga →
  VANISHING_POINT.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:45:50 +02:00
JailDesigner 424d0d2b89 Lint: bugs reales + enums uint8_t + use-equals-default
Resuelve la categoría de findings de tidy que son bugs reales o cambios
de tipo concretos, no transforms automáticos:

Bugs reales (bugprone-* y clang-diagnostic-*):

- bugprone-empty-catch en postfx_config.cpp: el catch silencioso del
  parser RGB era intencional (fallback a defaults si el array no parsea
  como int). Marcado con @INTENTIONAL (keyword ya configurado en
  .clang-tidy via bugprone-empty-catch.IgnoreCatchWithKeywords) y
  comentario ampliado explicando la decisión.

- clang-diagnostic-unused-private-field en Starfield: el campo
  'densitat_' se asignaba en el constructor pero nunca se leía. El
  parámetro 'densitat' se reparte directamente en las CapaConfig al
  construir, así que el field era código muerto. Eliminado.

- bugprone-branch-clone en vector_text.cpp: el switch de
  get_shape_filename tenía dos grupos consecutivos (dígitos 0-9 y
  mayúsculas A-Z) con cuerpo idéntico. Fusionados en un único case con
  comentario explicando que comparten path porque la shape se llama
  igual que el caracter.

- bugprone-switch-missing-default-case en Input::handleEvent: el switch
  manejaba solo SDL_EVENT_GAMEPAD_ADDED/REMOVED y caía por fall-through
  a un return {} fuera del switch. Añadido default: explícito con
  comentario sobre qué hace Input vs el resto del sistema.

- bugprone-implicit-widening-of-multiplication-result en
  GameScene::bullets_ y Collision::Context::bullets: 'MAX_BALES * 2'
  es int*int y se widening implícitamente a std::size_t para el
  template arg de std::array. Cast explícito a size_t en ambos sitios.

Otros mecánicos:

- performance-enum-size: 10 enums sin tipo subyacente pasaron a
  ': std::uint8_t' (PrimitiveType, InputAction, Mode, SceneType,
  Option, AnimationState, TitleState, ModeSpawn, EstatStage,
  ShipState). #include <cstdint> añadido donde faltaba.

- modernize-use-equals-default en SpawnController: el ctor por
  defecto tenía cuerpo vacío ({}). Pasado a '= default;'.

Cero supresiones. La única "marca" es @INTENTIONAL en el empty-catch,
que es el mecanismo configurado en el .clang-tidy del proyecto para
distinguir intencionales de accidentales.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:23:49 +02:00
JailDesigner c45e524109 Lint: clang-tidy --fix mecánico (trailing return, default member init, auto, enum size)
Pase automático de clang-tidy --fix sobre el conjunto de checks que son
puro transform de sintaxis y no rompen API. Invocado con
--format-style=none para que clang-tidy NO arrastre clang-format sobre
las líneas tocadas (evita la regla NamespaceIndentation: All del
.clang-format reformateando solo trozos del archivo).

Checks aplicados:

- modernize-use-trailing-return-type (193 hits): 'int foo()' →
  'auto foo() -> int'. Estilo coherente con la convención del proyecto.
- modernize-use-default-member-init (36 hits): inicialización de
  miembros pasa de la lista del constructor a la declaración. Reduce
  duplicación cuando hay varios constructores con los mismos defaults.
- modernize-use-auto (6 hits): tipos largos sustituidos por auto donde
  el tipo es evidente del contexto (new T, dynamic_cast, etc).
- modernize-use-starts-ends-with (2 hits): s.rfind(x) == 0 →
  s.starts_with(x), aprovechando C++20.
- performance-enum-size (10 hits): enums pequeños declaran tipo
  subyacente (uint8_t / similar) para reducir tamaño y precisar layout.

NO aplicado en este pase (riesgo de cambios semánticos o de API):
- readability-identifier-naming (renames pueden romper callsites parciales)
- readability-convert-member-functions-to-static (cambia firma)
- readability-use-anyofallof (reescribe loops, side effects)
- readability-function-cognitive-complexity (requiere refactor manual)
- bugs reales (bugprone-*, clang-diagnostic-*) → uno a uno

Cambios manuales asociados:
- SDLManager::clear() ahora devuelve bool: propaga el resultado de
  beginFrame al caller para que Director::runFrameLoop salte
  draw+present cuando la swapchain no esté disponible (ventana
  minimizada). Antes la función ignoraba el [[nodiscard]] del
  beginFrame y los vértices se acumulaban en el batch sin nadie que
  los consumiera.
- vector_text.cpp: borrada la línea suelta "// Test pre-commit hook"
  que quedó como cruft.

clang-tidy crashea en LLVM 19.1 con performance-noexcept-move-constructor
(recursión infinita en ExceptionSpecAnalyzer al procesar std::set);
check deshabilitado en .clang-tidy con comentario explicativo.

Build limpio, smoke test OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:59:56 +02:00
JailDesigner efbf2457a1 Lint: inicializadores + retornos const-ref + warnings preexistentes
Primera tanda mecánica sobre el lint pendiente. Arregla la causa raíz, no
silencia diagnósticos. Detalle por categoría:

- Uninit members (cppcheck warnings) → inicializadores en declaración:
  Bullet (esta_, owner_id_, grace_timer_), Enemy (drotacio_, rotacio_,
  esta_, type_, tracking_timer_, ship_position_, tracking_strength_,
  direction_change_timer_, timer_invulnerabilitat_), Ship (is_hit_,
  invulnerable_timer_), Shape (escala_defecte_) y TitleShip (todos los
  miembros del struct, que viven dentro de un std::array<,2>).

- returnByReference (cppcheck performance) → return const T&:
  Shape::getName, ResourceLoader::getBasePath. De paso, Shape::get_nom
  se renombra a getName y get_num_primitives a getNumPrimitives para
  cumplir la convención camelBack del proyecto (lint del .clang-tidy).

- useInitializationList (cppcheck performance) →
  Starfield::shape_estrella_ pasa a la lista de inicialización (reordenada
  según la declaración para no disparar -Wreorder-ctor).

- noExplicitConstructor (cppcheck style) → explicit en ctores de 1 arg:
  Bullet(Renderer*), Enemy(Renderer*), Ship(Renderer*,...) y VectorText(Renderer*).

- variableScope (cppcheck style) → en vector_text.cpp se elimina la
  variable 'c' intermedia y se usa el literal '\\xA9' directamente en el
  único punto donde se necesita.

- constParameterReference (cppcheck style) → drawScoreboardAnimated pasa
  el VectorText por const ref (la API render/renderCentered es const).

- Warnings preexistentes del compilador (resueltos de paso):
  - stage_config.hpp: stage_id <= 255 sobre uint8_t era siempre true; se
    elimina la comparación redundante y se explica con comentario.
  - director.cpp: 'struct stat st = {.st_dev = 0};' disparaba
    -Wmissing-field-initializers; pasa a 'struct stat st{};' (zero-init
    completo, robusto a las variantes específicas del SO).
  - game_scene.cpp: stepDeathSequence devolvía un bool [[nodiscard]] que
    el caller ignoraba; el valor era puramente interno. Cambiada la
    firma a void.

- cppcheck: añadido --suppress=useStlAlgorithm. Las 26 sugerencias
  'Consider using std::any_of/find_if/count_if' son cosméticas y no
  aportan claridad sobre las raw loops actuales.

- .clang-tidy de source/core/audio/ eliminado: deshabilitaba todos los
  checks en ese subdirectorio por dependencia de jail_audio.hpp, pero
  impedía ejecutar 'make tidy' (clang-tidy aborta con "no checks
  enabled" al primer archivo del directorio). El proyecto pasa a usar
  el mismo patrón de CCAE: solo source/external/ y source/legacy/
  quedan fuera del lint.

- lint-reports/ añadido a .gitignore. Carpeta donde 'make tidy' y
  'make cppcheck' vuelcan su salida completa para inspección posterior.

Build limpio, cero warnings activos.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:29:36 +02:00