# Scénarios runtime — configuration, réponses et évaluation

## Rôle du système Scenario

Le système **Scenario** gère le contenu d'introduction/contexte, les questions, les réponses de segments et leur évaluation. Il ne doit pas être confondu avec :

- **Tutoriels** — guides interactifs qui montrent l'UI et attendent des actions;
- **Timeline** — séquences Unity/PlayableDirector audiovisuelles;
- **ScenarioStep** — flags de progression persistés dans `userDetails`.

```mermaid
flowchart LR
SD[Static data / ScenarioPages] --> UI[ScenarioPanelControlBase]
UI --> Q[Questions / Segment grid]
Q --> SAVE[SaveScenarioAnswers / SaveEvalSegment]
SAVE --> EVAL[(evaluation.scenario)]
EVAL --> COMPUTE[compute_scenario_score / compute_segment_score]
COMPUTE --> SCORE[evaluation.scores]
SCORE --> CORRECT[ScenarioEval / corrected UI]
UI --> STEP[eFinishQuestions]
STEP --> USER[(userDetails.scenarioStep)]

```

## Modèles principaux

<table id="bkmrk-fichier-responsabili"><thead><tr><th>Fichier</th><th>Responsabilité</th></tr></thead><tbody><tr><td>`Scenario.cs`</td><td>Réponses booléennes et réponses de segments de l'étudiant.</td></tr><tr><td>`ScenarioAnswer.cs`</td><td>Réponse attendue par UID.</td></tr><tr><td>`ScenarioEval.cs`</td><td>Scenario + nombre de bonnes réponses scénario/segments.</td></tr><tr><td>`ScenarioPages.cs`</td><td>ScriptableObject qui décrit les pages affichées.</td></tr><tr><td>`ScenarioPanelControlBase.cs`</td><td>Moteur UI principal, navigation, validation et sauvegarde.</td></tr><tr><td>`ScenarioSegGridControlBase.cs`</td><td>Base de la grille de segments.</td></tr><tr><td>`EvalCorrectedPopupControl.cs`</td><td>Vue de correction.</td></tr></tbody></table>

## ScenarioPages

Chaque `PagesDefinition` contient :

- `headerText`;
- `segGridUid`;
- `pages[]`;
- `questionsStartIndex`;
- `numQuestions`.

### Chargement By Year

```csharp
ScenarioPages = Resources.Load<ScenarioPages>(
    $"data_{GameUid}/ScenarioPages"
);
```

Ce chargement est fait dans `StaticDataByYearController.Initialize()`.

### Chargement By Module

```csharp
string moduleUid = moduleByUid.Key.SnakeCaseToPascalCase();

ScenarioPages scenarioPages =
    Resources.Load<ScenarioPages>(
        $"data_{GameUid}/{moduleUid}ScenarioPages"
    );
```

`StaticDataByModuleController` charge donc un asset ScenarioPages distinct par module lorsqu'il existe.

## Créer ou modifier un Scenario de A à Z

### 1. Définir le contenu et les réponses attendues

Les réponses des questions sont stockées sous des UIDs comme `question_0`, `question_1`, etc. Vérifier que `questionsStartIndex` et `numQuestions` correspondent aux réponses statiques attendues.

### 2. Modifier le bon ScenarioPages asset

- By Year : `data_<gameUid>/ScenarioPages`;
- By Module : `data_<gameUid>/<ModuleUid>ScenarioPages`.

`ScenarioPagesEditor.cs` masque la référence de segment grid lorsque `useSegmentsInScenario` est false.

### 3. Ajouter les textes

Ajouter les titres, paragraphes, questions et choix via le pipeline de localisation. Ne pas hardcoder le contenu dans `ScenarioPanelControlBase`.

### 4. Ajouter un composant game-specific si nécessaire

Le socle Scenario est commun, mais certains jeux possèdent des rendus propres :

- MK1/MK2/HR1 : `ScenarioSegGridControl`;
- MGT1 : tables scenario spécialisées pour segments, employés, features et discipline.

Un nouveau rendu métier reste sous `Assets/GameSpecific/<gameUid>/Src/UI`.

### 5. Vérifier InitRuntimePages()

`ScenarioPanelControlBase.InitRuntimePages()` construit les pages runtime. En By Year, il peut insérer les segments dans la séquence lorsque `useSegmentsInScenario` est activé.

### 6. Sauvegarder les réponses de questions

```mermaid
flowchart LR
UI[ScenarioPanelControlBase] --> STUD[Student.SaveScenarioAnswers]
STUD --> BE[BackEnd.SaveScenarioAnswers]
BE --> CMD[_command/save_scenario_answers]
CMD --> E[(evaluation.scenario.answers)]

```

`save_scenario_answers.js` merge les clés reçues dans `evaluation.scenario.answers`, puis sauvegarde le document `evaluation`.

### 7. Sauvegarder les segments

`SaveEvalSegment` appelle `_command/save_eval_segment`. Le script :

1. écrit le segment dans `evaluation.scenario[segmentUid]`;
2. sauvegarde `evaluation`;
3. envoie au professeur un message `get_data` qui devient `update_eval`.

### 8. Calculer les scores

Le client appelle les commandes game-specific :

- `<gameUid>_compute_scenario_score`;
- `<gameUid>_compute_segment_score`.

Elles délèguent au moteur `Eval<Game>`, sauvegardent dans `evaluation.scores`, puis retournent les informations utilisées par `ScenarioEval`.

### 9. Marquer la fin

```csharp
Game.Student.SetScenarioStep(
    Scenario.eScenarioStep.eFinishQuestions
);
```

**`eFinishQuestions` doit rester la valeur 1.** Le commentaire du code indique que le serveur suppose explicitement cette valeur.

### 10. Tester la correction

Tester `GetScenarioEvaluation`, `ScenarioEval.Deserialize()`, la vue corrigée et la vue professeur. Ajouter une question sans corriger ce chemin laisse la feature incomplète.

## ScenarioStep — progression persistée

`Scenario.eScenarioStep` est un enum de flags stocké sous forme de bitmask. Il suit la progression utilisateur, pas les réponses de Scenario.

Exemples :

- `eFinishQuestions`;
- `eFinishFirstProduct`;
- `eStudentAfterFirstResults`;
- `eFinishFirstRealLaunch`;
- `eStudentFirstModule`;
- `eStudentFirstCorrection`;
- `eByModuleHomepageTutorial`;
- `eStudentFirstFormula`;
- `eStudentFirstFormulaActivation`.

## Ajouter un ScenarioStep

1. Ajouter un nouveau bit libre avec `1 << n`.
2. **Ne jamais renuméroter un ancien bit** déjà persisté.
3. Tester `IsScenarioStepDone()` avant le flow concerné.
4. À la fin, appeler `SetScenarioStep()`.
5. Si la séquence peut être rejouée volontairement, décider si `UnSetScenarioStep()` est nécessaire.

`User.SetScenarioStep()` OR le nouveau bit dans le masque local puis appelle `_command/set_scenario_step`, qui écrit le masque complet dans `userDetails.scenarioStep`.

## States Scenario

- `StudentLoadScenarioState` charge l'évaluation;
- `StudentPlayScenarioByYearState` attend `eFinishQuestions` puis choisit le state suivant;
- `StudentPlayScenarioByModuleState` lance le welcome By Module puis attend le même flag.

## Scenario réouvert après le début

`ScenarioPopupControl` permet de consulter le scénario après le flow initial. Il conserve la dernière page consultée et réutilise `ScenarioPanelControl`. En By Module, `ScenarioWindowControl` adapte les titres selon le module et ses settings.

## Debug Scenario

<table id="bkmrk-sympt%C3%B4me-v%C3%A9rifier-pa"><thead><tr><th>Symptôme</th><th>Vérifier</th></tr></thead><tbody><tr><td>Page absente</td><td>Nom/path de `ScenarioPages`, `pagesDefinitions`, asset dans Resources.</td></tr><tr><td>Question visible mais non persistée</td><td>`question_N` → SaveScenarioAnswers → `evaluation.scenario.answers`.</td></tr><tr><td>Segment non mis à jour chez le prof</td><td>`save_eval_segment` → `get_data/update_eval`.</td></tr><tr><td>Score faux</td><td>Good answers static data + `Eval<Game>`.</td></tr><tr><td>Étudiant bloqué après validation</td><td>`userDetails.scenarioStep` et bit `eFinishQuestions`.</td></tr><tr><td>Correction vide</td><td>`get_scenario_evaluation`, `ScenarioEval`, corrected popup.</td></tr></tbody></table>

## Checklist avant merge

- ScenarioPages au bon nom/path;
- textes FR/EN;
- réponses sauvegardées puis relues après relog;
- segments synchronisés professeur;
- score scenario correct;
- score segments correct si utilisé;
- correction correcte;
- `eFinishQuestions` déclenche le bon state;
- aucun ancien ScenarioStep renuméroté;
- By Year / By Module testés selon le scope.