# Checkpoint 5B — trajets et regard indépendants

22 septembre 2026. Reprise de `b9f0964` ; travail exclusivement dans
`big-egg-3d/`. Arrêt après ce checkpoint à la demande de l'auteur.

## Périmètre confirmé

L'auteur a précisé que le boss à droite tirant un laser vers la gauche était
un **exemple de capacité souhaitée**. Cette étape livre les outils génériques.
Elle ne crée aucun boss, aucune attaque laser et aucune configuration publiée
de rencontre. L'étape spécifique « 5C : laser intégré » est retirée du plan.

## Utilisation dans le gestionnaire

1. Ouvrir **Mouvements**, créer ou sélectionner un mouvement et choisir
   **Trajet par points**.
2. Choisir un tracé initial vertical, horizontal, rectangulaire ou un point
   central. Les boutons remplacent les points du mouvement ouvert ; le regard
   reste indépendant. Modifier ensuite X, Y et l'attente de chaque point.
3. Les coordonnées vont de **0 à 1**, de gauche à droite et de haut en bas,
   dans l'intérieur utilisable de la salle. Le rayon physique du monstre et la
   marge supplémentaire sont retirés avant la conversion en positions.
4. Choisir **Une fois, puis tenir**, **Boucle** ou **Aller-retour**. Un seul
   point se rejoint puis se tient, quel que soit ce choix. Ajouter, retirer ou
   réordonner les points avec les boutons. Maximum : 32 points.
5. Régler le comportement après un blocage : continuer à essayer de rejoindre
   le point courant, ou passer au suivant après le délai sans progrès.
6. Choisir le regard : comportement habituel, direction du mouvement, vers le
   joueur, angle fixe ou conserver la direction courante. **0° = droite,
   90° = bas, ±180° = gauche, −90° = haut**. La vitesse de rotation existante
   `turn_speed` pilote le pivot ; 0 conserve l'angle courant.
7. Référencer ce mouvement depuis une fiche de monstre ou une surcharge de
   phase, comme les mouvements existants. Les gardes de références du lot 4
   prennent déjà en compte les mouvements des phases.

Un regard indépendant exige le déplacement omnidirectionnel ou le pas de côté.
Le gestionnaire explique la contradiction et PHP/Godot refusent une
configuration indépendante sur un corps orienté sans pas de côté. Le regard
« sens du mouvement » reste compatible avec ce corps et sa vitesse de pivot.

L'aperçu représente le trajet et le regard fixe dans une salle schématique ;
il n'est pas une simulation des collisions, de la vitesse propre à un monstre
ou de la durée exacte de parcours d'une salle particulière.

## Garanties d'exécution

- Le corps rejoint physiquement le premier point. Le programme demande une
  vitesse ; seul `Enemy` applique `move_and_slide()`, une fois par image.
- La progression suit la position réellement atteinte. Un mur ne valide pas
  un point. Aucun saut de position ni rattrapage accéléré n'est utilisé.
- La vitesse est celle du monstre multipliée par le mouvement et ses effets.
  La commande est plafonnée pour ne pas dépasser la destination en un pas,
  y compris après un bonus de vitesse. Le recul reste une force séparée.
- Les attentes, l'arrivée et les délais de blocage se suspendent pendant une
  immobilisation, un gel ou une attaque qui possède le déplacement. Une
  attaque libre laisse la route se poursuivre dès son lancement (5A).
- Le regard explicite reste prioritaire sur le mouvement et sur le regard
  demandé par une attaque ou un contact. La visée d'attaque reste séparée.
  Pour `target_mode: forward` et son repli, l'acquisition emploie désormais le
  regard réel lorsqu'un regard explicite est configuré. Le mode habituel
  conserve son ancienne acquisition.
- Une piste préemptée retrouve son point courant. Une nouvelle occurrence de
  segment, de boucle ou de réarmement repart vers le premier point. Un maintien
  final garde l'occurrence réelle, même si plusieurs segments emploient la
  même phase. La mémoire est bornée par les pistes, pas par le nombre de tours.
  Une boucle courte qui renouvelle l'occurrence de la même phase ne repousse
  pas le délai maximal d'une transition en attente de fin d'attaque.
- `Dungeon.get_combat_arena_rect()` fournit les mêmes limites logiques au jeu
  et au bac à sable. Les marges de caméra ne sont pas un espace de combat.
  Sans arène connue ou si le corps ne tient pas dedans, le trajet reste immobile.

`movement_ready()` indique qu'un point a été atteint physiquement ; il
**n'interdit pas automatiquement une attaque**. Un tir « devant » utilise le
regard réel au moment de l'acquisition, même si un pivot est encore en cours.
Un éventuel mécanisme d'attente avant attaque devra avoir un délai maximal
explicite ; cette étape n'introduit aucune attente infinie de phase invulnérable.

## Architecture et compatibilité

| Pièce | Fichier |
| --- | --- |
| Bornes, énumérations et valeurs par défaut communes | `data/movement_program_contract.json` |
| Lecture du contrat et validation PHP | `tools/game-data-manager/movement_program.php` |
| Validation Godot, progression et rotation | `scripts/core/movement_program.gd` |
| Intégration corps/attaques/phases | `scripts/combat/enemy.gd` |
| Identité d'occurrence et maintien final | `scripts/core/encounter_director.gd` |
| Interface et aperçu dédiés | `tools/game-data-manager/assets/movement_program_editor.js` |
| Jeux de cas communs PHP/Godot | `tools/game-data-manager/tests/fixtures/movement_program_cases.json` |
| Scène de contrôle physique | `scripts/core/movement_program_check.gd` |

Les cinq types précédents restent disponibles. L'absence de `facing` produit
le mode `legacy`. Le normaliseur garde un trajet présent lorsque l'auteur
change temporairement de type, afin de le retrouver en revenant à `path`.
Les paramètres habituels continuent d'être validés par les normaliseurs
existants ; le module ne les remplace pas.

Le schéma reste **77** : extension optionnelle sans transformation des anciennes
fiches par ce chantier. Le contrat arrive dans
la réponse API du gestionnaire, séparément des données d'auteur. Les fixtures
CGI qui copient explicitement les dépendances incluent le nouveau module et
son JSON.

Des modifications d'auteur sont apparues pendant cette étape dans le maître,
le brouillon et les sauvegardes du gestionnaire, ainsi qu'un document d'idées.
Elles sont conservées dans le dossier de travail et exclues du commit de code.

## Validation

Les nouveaux tests ont été mis en échec une fois par trois régressions ciblées,
puis le code de production a été restauré à l'octet : arrivée fictive sans
déplacement, coordonnées hors salle acceptées, réordonnancement des points
inopérant. Rapport rouge :
`tools/dev/runs/20260922-111950-checks-ma85o23z/report.json`.

Le cas de boucle courte ajouté lors de la revue finale a lui aussi échoué
avant correction : `tools/dev/runs/20260922-155652-checks-_xsqos59/report.json`.

La scène contrôle le contrat partagé, les anciens types, les limites de salle,
les grands pas de temps, les trois parcours, les pauses et le retour après
recul. Elle instancie aussi une vraie créature face à un vrai mur et vérifie
son regard, son immobilisation, le mouvement possédé par l'attaque et la visée
devant le corps. Les identités d'occurrence, le maintien final et la mémoire
bornée sont contrôlés séparément.

Le test navigateur manipule les champs et boutons réels, vérifie l'erreur de
configuration contradictoire et fait traverser les données écrites par PHP.
Toutes ses requêtes API sont interceptées : il ne réinitialise pas le vrai
brouillon du gestionnaire.

Commandes de reprise ciblées :

```powershell
python tools/dev/dev.py check --area movement --area manager --match movement
python tools/dev/dev.py check --area gameplay --area manager --match encounter
```

La batterie complète (125 contrôles) retrouve uniquement les cinq échecs
documentés du gestionnaire et le smoke test en échec :
`tools/dev/runs/20260922-112059-checks-hkq7fz2w/report.json`.
Après les ajustements d'interface et la correction de boucle, la validation
ciblée finale passe, sauf le smoke dont la liste d'erreurs est strictement
identique au checkpoint 5A :
`tools/dev/runs/20260922-155730-checks-u_ggd_dz/report.json`.
Le pont 3D a passé son contrôle dans la batterie complète.
Les tests sonores restent séparés : la scène de mouvement coupe l'audio pour
éviter de charger le mélangeur avec des centaines de pas simulés en une image.

## Suite, après reprise explicite de l'auteur

Passer au lot 6 : présentation des phases, sons, diagnostics et utilisation
dans le bac à sable. Conserver le périmètre générique. Les cas de référence
restent dans des fixtures ou un espace d'essai explicite.

Avant de déclarer l'ensemble terminé, compléter les vérifications temporelles
du plan : frontières exactes sous grand delta, horloges sous préemption et
transitions en attente. Le changement d'identité d'occurrence ne prétend pas
résoudre toutes ces questions. Le glisser-déposer et le redimensionnement de
la frise des rencontres restent aussi à éprouver dans le navigateur (lot 7).
