# Tutoriel 10 — Salle puzzle scriptée

Construis une salle où le joueur doit collecter **10 jetons** éparpillés dans le donjon. Quand tous les jetons sont ramassés, une clé apparaît — permettant d'ouvrir la porte de sortie.

Ce tutoriel va au-delà de l'approche marqueurs-only et montre comment ajouter de la logique C# personnalisée dans tes salles via un **mod compagnon** séparé.

---

## Pourquoi un mod compagnon ?

Les asset bundles peuvent contenir des composants `MonoBehaviour`, mais la **classe doit exister dans une DLL chargée au runtime**.
La classe `Token` ou `TokenGate` n'existe pas dans le jeu — tu dois la fournir dans un mod BepInEx.

Ce mod n'a pas besoin de patcher le jeu. Il suffit qu'il soit **chargé** par BepInEx pour que les types soient disponibles quand Unity résout les composants du bundle.

---

## Étape 1 — Créer le mod compagnon

### Depuis le template

Copie le dossier `project-templates/new-bepinex-mod/` vers un nouveau répertoire hors de ce dépôt :

```
Copier project-templates\new-bepinex-mod\ → C:\mes-mods\token-puzzle\
```

Renomme les fichiers :
```
token-puzzle/
  GamePath.props.template
  .gitignore
  TokenPuzzle/
    TokenPuzzle.csproj     ← renommé depuis MyMod.csproj
    TokenPuzzlePlugin.cs   ← renommé depuis MyModPlugin.cs
```

### Configurer le chemin du jeu

```
cd token-puzzle
copy GamePath.props.template GamePath.props
```

Ouvre `GamePath.props` et remplace la valeur par ton chemin :
```xml
<GamePath>C:\Program Files (x86)\Steam\steamapps\common\VR_DungeonKnight</GamePath>
```

### Mettre à jour le .csproj

Dans `TokenPuzzle.csproj`, change `AssemblyName` et `RootNamespace` :
```xml
<AssemblyName>TokenPuzzle</AssemblyName>
<RootNamespace>TokenPuzzle</RootNamespace>
```

Ajoute la référence `UnityEngine.AIModule` si tu as des ennemis (NavMesh) :
```xml
<Reference Include="UnityEngine.AIModule">
  <HintPath>$(GamePath)\VR DungeonKnight_Data\Managed\UnityEngine.AIModule.dll</HintPath>
  <Private>False</Private>
</Reference>
```

### Mettre à jour le plugin

Dans `TokenPuzzlePlugin.cs` (renommé depuis `MyModPlugin.cs`) :
```csharp
using BepInEx;

namespace TokenPuzzle {
    [BepInPlugin("com.tonpseudo.token-puzzle", "TokenPuzzle", "1.0.0")]
    public class TokenPuzzlePlugin : BaseUnityPlugin {
        protected void Awake() {
            Logger.LogInfo("TokenPuzzle loaded.");
        }
    }
}
```

---

## Étape 2 — Ajouter les composants de logique

Crée deux nouveaux fichiers dans `TokenPuzzle/` :

**`TokenGate.cs`**
```csharp
using UnityEngine;

namespace TokenPuzzle {
    public class TokenGate : MonoBehaviour {
        public int TotalTokens = 10;
        public GameObject KeySpawnPoint;

        private int _collected;

        public void RegisterToken() {
            _collected++;
            if (_collected >= TotalTokens && KeySpawnPoint != null) {
                KeySpawnPoint.SetActive(true);
            }
        }
    }
}
```

**`Token.cs`**
```csharp
using UnityEngine;

namespace TokenPuzzle {
    [RequireComponent(typeof(Collider))]
    public class Token : MonoBehaviour {
        public TokenGate Gate;

        private void OnTriggerEnter(Collider other) {
            if (Gate == null) return;
            Gate.RegisterToken();
            gameObject.SetActive(false);
        }
    }
}
```

---

## Étape 3 — Builder et déployer le mod

```
dotnet build -c Release
```

Copie `bin/TokenPuzzle.dll` dans le jeu :
```
VR_DungeonKnight\BepInEx\plugins\token-puzzle\TokenPuzzle.dll
```

Lance le jeu une fois pour vérifier que le mod charge (cherche `TokenPuzzle loaded.` dans `BepInEx\LogOutput.log`).

---

## Étape 4 — Configurer la salle dans Unity

Pour que Unity puisse référencer `TokenGate` et `Token`, la DLL du mod doit être dans `Assets/Plugins/` du projet Unity.

### Copier la DLL dans le projet Unity

Copie `bin/TokenPuzzle.dll` dans :
```
room-template\Assets\Plugins\TokenPuzzle.dll
```

Unity détecte automatiquement la DLL et expose ses types dans l'éditeur.

### Structure de la salle

Tu as besoin de trois types d'objets :

| Objet | Composant | Rôle |
|---|---|---|
| Racine | `TokenGate` | Suit le nombre de collectés / active le spawn de la clé |
| `DoorKeySpawner` | `DoorKeySpawner` (marqueur) | Où la clé apparaît — commence **désactivé** |
| Objets jeton ×10 | `Token` | Ramassé au contact du joueur |

### Créer le DoorKeySpawner (désactivé)

1. Clic droit sur la racine → **Create Empty** → renomme `DoorKeySpawner`
2. Place-le près de la décoration "marchand"
3. Dans l'Inspector : **décoche la case** en haut — il démarre inactif

### Ajouter TokenGate à la racine

1. Sélectionne l'objet racine
2. **Add Component** → cherche `TokenGate` (namespace `TokenPuzzle`)
3. Règle **Total Tokens** sur `10`
4. Glisse `DoorKeySpawner` dans le champ **Key Spawn Point**

### Créer les jetons

1. Clic droit sur la racine → **Create Empty** → renomme `Token_01`
2. **Add Component** → `Sphere Collider` — coche **Is Trigger**, Radius à `0.4`
3. **Add Component** → `Token` (namespace `TokenPuzzle`)
4. Glisse l'objet racine dans le champ **Gate**
5. Ajoute un visuel enfant (une Sphere avec matériau émissif doré, scale `0.3`)
6. Positionne sur le sol
7. Duplique (`Ctrl+D`) neuf fois → renomme `Token_02` … `Token_10` → éparpille

---

## Étape 5 — Ajouter la décoration du marchand

Le "marchand" est purement visuel :

1. Cube fin et haut (Scale `(0.5, 1.8, 0.5)`) pour la silhouette
2. `DoorKeySpawner` positionné devant lui
3. Cube plat "comptoir" + Point Light chaud (range 4) pour le mettre en valeur

---

## Étape 6 — Utiliser une porte à clé

Sous `WhatLockIsNeeded`, crée `KeyLock` (pas UnbarredDoor ni MonsterLock).

Hiérarchie complète :

```
mon-pack_SalleJetons
├── SpawnHere
├── Token_01 … Token_10  (Sphere Collider + Token)
├── DoorKeySpawner  [DÉSACTIVÉ]
│   └── [Décoration marchand]
├── LootSpawner (×3, optionnel)
└── WhatLockIsNeeded
    └── KeyLock
```

Racine : composant `TokenGate` avec Total Tokens = `10`, Key Spawn Point = `DoorKeySpawner`.

---

## Étape 7 — Pool et rooms.json

```json
{
  "pool": "PuzzleRoomStructures",
  "author": "ton-pseudo",
  "description": "Ramasse 10 jetons pour acheter une clé au marchand"
}
```

---

## Idées de design

### Jetons dans des endroits difficiles
- Couloirs étroits, plateformes surélevées, près de pièges

### Visuel des jetons
- Sphere émissive (couleur or) + Point Light enfant (range 2, intensity 1, doré)

### Mélange avec des ennemis
- Ajoute des `EnemySpawn` → le joueur combat et collecte simultanément
- Remplace la porte par `MonsterLock` + étend `TokenGate` pour vérifier les deux conditions

### Moins de jetons, placement plus difficile
- 3 jetons plutôt que 10, chacun gardé par un piège ou une zone dangereuse
- Donne l'impression de "trois fragments de clé"

---

## Problèmes courants

| Problème | Solution |
|---|---|
| Composant `Token` introuvable dans Unity | `TokenPuzzle.dll` absent de `Assets/Plugins/` dans Unity |
| `Token` apparaît mais le composant est "missing" en jeu | DLL non copiée dans `BepInEx/plugins/token-puzzle/` |
| La clé ne spawne jamais | Vérifie que `DoorKeySpawner` est assigné dans `TokenGate.KeySpawnPoint` |
| Le joueur traverse les jetons | `Is Trigger` doit être coché sur le Sphere Collider |

---

## Suite

→ [11-lods.md](11-lods.md) — optimiser les grandes salles avec les LOD groups
