# Généralités

# Présentation

Ce chapitre présente MasterLadder, l'échelle pivotante pompiers (EPAN / EPA) de MasterMods pour FiveM.

MasterLadder transforme un véhicule à échelle en véritable engin d'intervention : calage au sol, manœuvre de l'échelle depuis le poste de la tourelle ou depuis la nacelle, montée à pied par l'échelle et deux pupitres de commande au choix. Toute l'échelle est synchronisée pour l'ensemble des joueurs, sans saccades.

## Ce que fait le script

- **Déploiement réaliste** : calage des 4 stabilisateurs, contrôle de la pente du terrain, véhicule immobilisé et portes verrouillées pendant l'intervention.
- **Manœuvre** : rotation, inclinaison, longueur et bras de nacelle, avec inertie hydraulique et ralentissement près des butées. Zone interdite à l'arrière et protection de la cabine.
- **Équipage** : un poste de commande sur la tourelle, une nacelle jusqu'à 3 personnes, et jusqu'à 2 personnes sur l'échelle.
- **Montée à pied** : du pied de l'échelle (sur le porteur) jusqu'à la nacelle, et retour.
- **Deux pupitres** : écran tactile moderne ou pupitre années 2000, au choix de chaque joueur (ou imposé par le serveur).
- **Équipements** : projecteur orientable, caméra opérateur, arrêt d'urgence, verrouillage de la nacelle et des portes, coffres latéraux, écran de commande arrière.
- **Interactions** : ox_target / qb-target, ou touches avec aide à l'écran.
- **Sécurité** : le serveur valide chaque action (distances, permissions, état de l'échelle) et refuse les tentatives de triche.

## Compatibilité

- **Frameworks** : ESX, QBCore, QBox, ox_core, Standalone
- **Target** : ox_target, qb-target, aucun
- **Notifications** : ox_lib, ESX, QBCore, okok, GTA
- **Langues** : français, anglais

## Licence

MasterLadder est **gratuit**. Il nécessite une **MasterKey**, gratuite elle aussi : voir [Installation](installation).

Support : [discord.mastermods.dev](https://discord.mastermods.dev)

# Dépendances

Ce document liste ce dont MasterLadder a besoin pour fonctionner.

## Obligatoire

- **OneSync** activé sur le serveur (`set onesync on` dans `server.cfg`, ou via txAdmin).
- **Un véhicule à échelle et ses props**, streamés par une autre ressource (non inclus dans MasterLadder). Les noms des modèles doivent correspondre à ceux de `config/ladders.lua` (voir [Configuration des échelles](configuration-des-echelles)).
  - Exemple : le mod **Renault D16 EPAN BSPP** fournit le véhicule et les props `prop_tl2_*` utilisés par l'entrée `epan`.
- **Une MasterKey** gratuite : [ressources.mastermods.dev/CreerMasterKey.php](https://ressources.mastermods.dev/CreerMasterKey.php)

## Optionnel

- **Framework** (pour la restriction par métier) : `es_extended`, `qb-core`, `qbx_core` ou `ox_core`.
- **Target** : `ox_target` ou `qb-target`. Sans target, tout se fait aux touches.
- **Notifications** : `ox_lib` ou `okok` si vous les choisissez dans `Config.NotifySystem`.

⚠️ Démarrez le framework, le target et la ressource du véhicule **avant** MasterLadder dans `server.cfg`.

# Installation

Ce chapitre décrit la mise en place de MasterLadder sur votre serveur.

## 1. Fichiers

1. Téléchargez `MasterLadder-vX.Y.Z.zip`.
2. Décompressez le dossier `MasterLadder` dans votre dossier `resources/` (par exemple `resources/[mastermods]/MasterLadder`).

⚠️ Ne renommez pas les fichiers à l'intérieur du dossier.

## 2. server.cfg

```cfg
ensure ox_target          # si vous utilisez un target
ensure votre-vehicule-epan # la ressource qui stream le véhicule et les props
ensure MasterLadder
```

## 3. MasterKey

Créez votre clé gratuite sur [ressources.mastermods.dev/CreerMasterKey.php](https://ressources.mastermods.dev/CreerMasterKey.php), puis renseignez-la **à un seul de ces deux endroits** :

- dans `server.cfg` (recommandé, prioritaire) :
  ```cfg
  set mastermods_key "MM-XXXXXXXX"
  ```
- ou dans `config/config.lua` :
  ```lua
  Config.MasterModsKey = "MM-XXXXXXXX"
  ```

Au démarrage, la console serveur affiche `Licence MasterMods validée pour : <nom du serveur>`. La clé est revérifiée toutes les 30 minutes.

⚠️ Une même MasterKey peut servir sur **3 serveurs différents maximum par 24 h**. Au-delà, elle est bloquée 1 jour.

En cas de problème, voir [En cas d'erreur](en-cas-derreur).

## 4. Configuration

- `config/config.lua` : framework, permissions, interface, touches, vitesses, sons… voir [Configuration générale](configuration-generale).
- `config/ladders.lua` : vos véhicules à échelle (props, butées, extras, places)… voir [Configuration des échelles](configuration-des-echelles).

## 5. Administration (optionnel)

Pour autoriser vos administrateurs à utiliser `/mladmin` :

```cfg
add_ace group.admin command.mladmin allow
```

## Mise à jour

Remplacez tout le dossier **sauf** `config/config.lua` et `config/ladders.lua`, puis comparez-les avec ceux de la nouvelle version : les nouvelles options sont listées dans les [Journaux des changements](journaux-des-changements). Une option absente de votre config prend sa valeur par défaut.

# Guide d'utilisation

Ce chapitre explique comment utiliser l'échelle en jeu, du calage au repli. Les touches indiquées sont celles par défaut : chaque joueur peut les changer dans **Paramètres > Raccourcis > FiveM**, et le serveur peut modifier les valeurs par défaut (voir [Configuration générale](configuration-generale)).

Avec un système de visée (ox_target / qb-target), les actions « à pied » se font à l'**œil (ALT)** sur le véhicule ou sur l'échelle. Sans target, une aide en haut de l'écran indique la touche à utiliser.

## 1. Déployer l'échelle

1. Garez le véhicule sur un sol le plus plat possible (pente maximale : 8° par défaut).
2. **À l'arrière du véhicule**, allumez l'écran de commande : visée **« Allumer / éteindre l'écran »** ou touche **E**.
3. Déployez : visée **« Déployer l'échelle »** ou touche **U** devant l'écran.
   - Depuis la cabine, **U** déploie aussi directement.
4. Les stabilisateurs se calent (7 secondes par défaut). Le véhicule est immobilisé et ses portes verrouillées.

⚠️ Le déploiement est refusé si la pente est trop forte ou si le sol n'est pas trouvé sous un stabilisateur.

## 2. Prendre place

| Place | Comment |
|---|---|
| **Poste de commande** (tourelle) | Visée sur la tourelle **« Monter au poste de commande »**, ou **F** près de la tourelle |
| **Nacelle** (jusqu'à 3) | Visée sur la nacelle **« Monter dans la nacelle »**, ou **F** près de la nacelle |
| **Échelle** (jusqu'à 2) | Voir « 4. Monter par l'échelle » ci-dessous |

- **F** (ou `/mlenter`) permet aussi de descendre. `/mlenter b2` choisit une place précise (`seat`, `b1`, `b2`, `b3`).
- Pour sortir de la nacelle sur le côté, maintenez **← ou →** en appuyant sur **F**.
- 🔒 Par défaut, la **nacelle est verrouillée** à la fin du calage : l'opérateur la déverrouille pendant la manœuvre (**U**). On peut toujours y arriver par l'échelle.

## 3. Manœuvrer

Depuis le poste ou la nacelle, appuyez sur **R** pour prendre les commandes (une seule personne à la fois). Le pupitre s'affiche.

| Touche | Action |
|---|---|
| **Q / D** | Rotation gauche / droite |
| **Z / S** | Monter / baisser l'échelle (inclinaison) |
| **Maj / Ctrl** | Sortir / rentrer l'échelle (longueur) |
| **E / A** | Lever / baisser le bras de nacelle |
| **Flèches** | Orienter le projecteur |
| **Y** | Allumer / éteindre le projecteur |
| **U** | Verrouiller / déverrouiller la nacelle |
| **H** | Caméra opérateur (molette : distance) |
| **R** | Lâcher les commandes |

Les mouvements démarrent et s'arrêtent progressivement, et ralentissent à l'approche des butées. Le pupitre affiche :

- les valeurs (rotation, inclinaison, longueur, bras), la hauteur, le déport et la portée ;
- la position de l'échelle vue de côté et de dessus, avec les zones interdites ;
- les voyants : calage, verrou nacelle, contact sol, projecteur, butées ;
- le nombre de personnes dans la nacelle.

**Sécurités automatiques :**
- Zone interdite à l'arrière du véhicule et pas d'inclinaison sous l'horizontale au-dessus de la cabine.
- Arrêt avant que la nacelle ne touche le sol.
- Échelle bloquée tant que quelqu'un y grimpe (le projecteur reste libre).

## 4. Monter par l'échelle

1. Échelle déployée, placez-vous **au pied de l'échelle, sur le porteur**.
2. Visée **« Gravir l'échelle »** ou touche **G**.
3. **Z** pour monter, **S** pour descendre.
4. Arrivé en haut, **Z** fait entrer dans la nacelle, même si elle est verrouillée.

Pour **redescendre depuis la nacelle** : visée **« Redescendre par l'échelle »** (au bord de la nacelle, côté échelle) ou touche **G**. En bas, **S** fait descendre de l'échelle.

💡 En cas de blocage, `/mlexit` détache le joueur (échelle, poste ou nacelle).

## 5. Coffres, portes et écran

- **Coffres latéraux** : visée **« Coffres gauche / droite »** ou **E** à côté d'un coffre.
- **Portes du véhicule** : visée **« Verrouiller / déverrouiller »** ou `/mllock` (échelle déployée).

## 6. Replier l'échelle

1. Ramenez l'échelle en position de route : **rotation à 0°**, **inclinaison à 0°**, **longueur rentrée**, **bras de nacelle relevé**.
2. Tout le monde descend (poste, nacelle, échelle).
3. À l'arrière : visée **« Replier l'échelle »** ou **U** devant l'écran (ou **U** depuis la cabine).

Le repli est refusé tant qu'une condition n'est pas remplie, avec un message qui précise quoi corriger (par exemple « L'échelle n'est pas rangée (rot, ext) »).

## 7. Choisir son interface

`/mlui` ouvre les réglages du pupitre :

- **Interface** : moderne (écran tactile) ou années 2000 (pupitre LCD) ;
- **Position** à l'écran, **taille**, **mode compact** ;
- **Volume** des sons et **aide aux touches**.

Les réglages sont gardés d'une session à l'autre. Le serveur peut imposer une interface pour certaines échelles.

# Configuration générale

Ce chapitre détaille toutes les options de `config/config.lua`. C'est ici que vous adaptez MasterLadder à votre serveur : framework, permissions, interface, touches, vitesses, sons et distances. Les échelles elles-mêmes se règlent dans `config/ladders.lua` (voir [Configuration des échelles](configuration-des-echelles)).

💡 Toute option absente ou invalide reprend sa valeur par défaut, avec un avertissement dans la console : une faute de frappe ne fait jamais planter le script.

## 1. Licence

- **`Config.MasterModsKey`** : votre MasterKey (`"MM-XXXXXXXX"`). Une clé mise dans `server.cfg` avec `set mastermods_key "…"` est prioritaire. Voir [Installation](installation).

## 2. Langue

- **`Config.Locale`** (défaut `"fr"`) : langue des messages et de l'interface.
  - `"fr"` : français
  - `"en"` : anglais

## 3. Framework & permissions

- **`Config.FrameworkMetier`** (défaut `"standalone"`) : framework utilisé pour lire le métier des joueurs.
  - `"esx"`, `"qb"`, `"qbx"`, `"ox"`, `"standalone"`
- **`Config.NotifySystem`** (défaut `"gta"`) : système de notifications.
  - `"ox"`, `"esx"`, `"qb"`, `"okok"`, `"gta"`
- **`Config.TargetSystem`** (défaut `"ox"`) : système de visée (œil ALT).
  - `"ox"` : ox_target
  - `"qb"` : qb-target
  - `"none"` : touches et aide à l'écran
  - Si la ressource choisie n'est pas démarrée, le script passe automatiquement aux touches.
- **`Config.TargetDistance`** (défaut `2.0`) : portée des options de visée, en mètres.
- **`Config.JobRestriction`** (défaut `false`) : active la restriction par métier (ignorée en standalone).
- **`Config.RequireOnDuty`** (défaut `true`) : le joueur doit être en service (QBCore / QBox uniquement).
- **`Config.AuthorizedJobs`** : grade minimum par métier et par action. Un métier absent de la liste n'a accès à rien.

```lua
Config.AuthorizedJobs = {
    ['pompier'] = {
        deploy  = 1, -- déployer / replier
        enter   = 0, -- monter au poste ou dans la nacelle
        control = 1, -- manœuvrer l'échelle
        lock    = 0, -- verrouiller les portes
        locker  = 0, -- coffres et écran arrière
    },
}
```

Le chiffre correspond au **grade minimum** requis.

- **`Config.CustomPermission`** (défaut `nil`) : votre propre fonction de permission, qui remplace la restriction par métier. Elle reçoit `source`, l'action (`deploy`, `enter`, `control`, `lock`, `locker`) et le nom de l'échelle. Retourner `false` refuse l'action.

```lua
Config.CustomPermission = function(source, action, ladder)
    return IsPlayerAceAllowed(source, 'masterladder.use')
end
```

## 4. Interface

- **`Config.DefaultInterface`** (défaut `"modern"`) : pupitre par défaut.
  - `"modern"` : écran tactile
  - `"retro"` : pupitre années 2000
- **`Config.AvailableInterfaces`** (défaut `{ modern = true, retro = true }`) : interfaces que les joueurs peuvent choisir.
- **`Config.AllowPlayerUiSettings`** (défaut `true`) : `false` désactive `/mlui`, tout le monde garde les réglages ci-dessous.
- **`Config.DefaultUiCorner`** (défaut `"br"`) : position du pupitre (`"br"` bas droite, `"bl"` bas gauche, `"tr"` haut droite, `"tl"` haut gauche).
- **`Config.DefaultUiScale`** (défaut `1.0`) : taille, de `0.6` à `1.6`.
- **`Config.DefaultUiCompact`** (défaut `false`) : mode compact (relevés et voyants seulement).
- **`Config.DefaultUiVolume`** (défaut `0.6`) : volume des sons du pupitre, de `0` à `1`.
- **`Config.ShowKeyHints`** (défaut `true`) : aide aux touches en bas d'écran pendant la manœuvre.
- **`Config.UiRefreshRate`** (défaut `100`) : millisecondes entre deux mises à jour du pupitre.

Une échelle peut aussi imposer son interface : voir `interface` dans [Configuration des échelles](configuration-des-echelles).

## 5. Commandes & touches

- **`Config.Commands`** : noms des commandes du chat (sans le `/`).

| Clé | Défaut | Action |
|---|---|---|
| `set` | `mlset` | Déployer / replier (verrou nacelle pendant la manœuvre) |
| `enter` | `mlenter` | Monter / descendre / changer de place |
| `control` | `mlcontrol` | Prendre / lâcher les commandes |
| `light` | `mllight` | Projecteur |
| `lock` | `mllock` | Verrouiller les portes |
| `camera` | `mlcam` | Caméra opérateur |
| `ui` | `mlui` | Réglages de l'interface |
| `climb` | `mlclimb` | Gravir / redescendre l'échelle |
| `exit` | `mlexit` | Dépannage : se détacher de l'échelle |
| `admin` | `mladmin` | Administration |

- **`Config.DefaultKeys`** : touches par défaut des commandes (`set = 'U'`, `enter = 'F'`, `control = 'R'`, `light = 'Y'`, `camera = 'H'`, `climb = 'G'`). Chaque joueur peut les changer dans **Paramètres > Raccourcis > FiveM**.

⚠️ FiveM lie les touches au **nom** de la commande : si vous renommez une commande, les touches personnalisées des joueurs reviennent à la valeur par défaut.

- **`Config.ManeuverControls`** : contrôles GTA utilisés pendant la manœuvre ([liste des contrôles](https://docs.fivem.net/docs/game-references/controls/)).
  - `rotateRight` / `rotateLeft` (défaut `35` / `34`, D / Q)
  - `raise` / `lower` (défaut `32` / `33`, Z / S)
  - `extend` / `retract` (défaut `131` / `132`, Maj / Ctrl)
  - `armUp` / `armDown` (défaut `38` / `44`, E / A)
  - `lightRight`, `lightLeft`, `lightUp`, `lightDown` (défaut flèches)
  - `exitLeft` / `exitRight` (défaut `174` / `175`) : maintenir pour sortir de la nacelle sur le côté
  - `climbUp` / `climbDown` (défaut `32` / `33`, Z / S) : monter / descendre l'échelle
  - `interact` (défaut `51`, E) : coffres et écran arrière sans target

## 6. Gameplay & mouvement

**Vitesses maximales**
- **`Config.RotationSpeed`** (défaut `2.25`) : m/s en bout d'échelle (la vitesse de rotation s'adapte à la longueur sortie).
- **`Config.ElevationSpeed`** (défaut `1.5`) : m/s en bout d'échelle.
- **`Config.ExtendSpeed`** (défaut `1.5`) : m/s.
- **`Config.ArmSpeed`** (défaut `19.36`) : °/s, bras de nacelle.
- **`Config.LightSpeed`** (défaut `5.73`) : °/s, projecteur.

**Inertie et butées**
- **`Config.EnableInertia`** (défaut `true`) : démarrage et arrêt progressifs.
- **`Config.AccelerationTime`** (défaut `0.35`) / **`Config.BrakingTime`** (défaut `0.25`) : secondes pour atteindre la vitesse maximale / pour s'arrêter.
- **`Config.SlowDownNearLimits`** (défaut `true`) : ralentit à l'approche des butées.
- **`Config.SlowDownZone`** : distance avant la butée où le ralentissement commence (° ou m) pour `rotation`, `elevation`, `length`, `arm`, `light`.
- **`Config.SlowDownMinSpeed`** (défaut `0.15`) : vitesse minimale dans cette zone (fraction de la vitesse max).

**Nacelle**
- **`Config.BasketLockedOnDeploy`** (défaut `true`) : nacelle verrouillée à la fin du calage ; l'opérateur la déverrouille pendant la manœuvre (**U**). `false` = accessible dès la fin du calage.
- **`Config.GroundClearanceLower`** (défaut `0.2`) / **`Config.GroundClearanceExtend`** (défaut `0.1`) : garde au sol minimale de la nacelle (m) pour descendre / sortir l'échelle.

**Montée par l'échelle**
- **`Config.EnableLadderClimb`** (défaut `true`) : active la montée à pied.
- **`Config.MaxClimbers`** (défaut `2`) : personnes sur l'échelle en même temps (1 ou 2).
- **`Config.ClimbSpeed`** (défaut `0.6`) : m/s le long de l'échelle.
- **`Config.BlockLadderWhileClimbing`** (défaut `true`) : l'échelle ne peut pas être manœuvrée quand quelqu'un y grimpe (le projecteur reste libre).
- **`Config.ClimbAnimation`** (défaut `{ dict = "laddersbase", clip = "climb_up", cycle = 0.6 }`) : animation d'escalade ; `cycle` = mètres parcourus par cycle d'animation. Augmentez-le si les mains « patinent » sur les barreaux.
- **`Config.ClimbOffset`** (défaut `{ normal = 0.70, height = 0.95 }`) : position du joueur sur l'échelle.
  - `normal` : distance aux barreaux. Joueur dans ou sous l'échelle → augmenter (pas de `0.05`).
  - `height` : décalage le long de l'échelle (position des mains sur les barreaux).
- **`Config.ClimbTilt`** (défaut `{ axis = "x", invert = false }`) : inclinaison du joueur comme l'échelle. `invert = true` s'il se penche en arrière ; `axis = "y"` s'il part sur le côté.
- **`Config.ClimbHelperModel`** (défaut `"prop_golf_ball"`) : petit prop invisible servant d'ancrage au joueur.
- **`Config.ClimbDownTarget`** (défaut `{ distance = 0.6, height = 1.1, reach = 3.0, model = "prop_cs_cardbox_01" }`) : point de visée « Redescendre par l'échelle » dans la nacelle (écart au centre, hauteur, portée, prop invisible qui sert de surface à viser).

**Caméra opérateur**
- **`Config.CameraDistance`** (défaut `7.0`), **`Config.CameraMinDistance`** (`3.0`), **`Config.CameraMaxDistance`** (`18.0`) : distance de la caméra (m), réglable à la molette.
- **`Config.CameraSensitivity`** (défaut `4.0`).

## 7. Audio

- **`Config.EnablePanelSounds`** (défaut `true`) : sons du pupitre (moteur hydraulique, bip de butée, déclic du verrou).
- **`Config.LockerSoundDistance`** (défaut `10.0`) : portée du son des coffres (m).
- **`Config.LockerSoundVolume`** (défaut `0.45`).
- **`Config.InVehicleSoundFactor`** (défaut `0.4`) : atténuation quand le joueur est dans un véhicule.

## 8. Rendu & réseau

- **`Config.LadderDrawDistance`** (défaut `250.0`) : distance d'affichage des échelles déployées (m).
- **`Config.PropLodDistance`** (défaut `300`) : distance de détail des props (m).
- **Projecteur** : **`Config.SpotlightDistance`** (`150.0`), **`Config.SpotlightColor`** (`{ 255, 255, 255 }`), **`Config.SpotlightBrightness`** (`80.0`), **`Config.SpotlightRadius`** (`25.0`).
- **`Config.NetworkRate`** (défaut `100`) : ms entre deux envois de position par l'opérateur.
- **`Config.InterpolationDelay`** (défaut `160`) : ms de retard d'affichage chez les autres joueurs, pour un mouvement parfaitement lisse.
- **`Config.PropHierarchy`** (défaut `true`) : sections attachées à la tourelle. `false` = placement individuel (solution de repli).
- **`Config.LocalAttachOthers`** (défaut `true`) : les autres occupants sont attachés localement (supprime leurs tremblements).

## 9. Distances

**Côté joueur**
- **`Config.PanelDistance`** (défaut `2.0`) : distance à l'écran arrière pour déployer.
- **`Config.EnterHelpDistance`** (`3.0`) / **`Config.EnterDistance`** (`4.0`) : affichage de l'aide / portée de la commande « monter ».
- **`Config.LockerDistance`** (`1.0`) / **`Config.LockerHelpDistance`** (`1.75`) : ouverture / aide des coffres.
- **`Config.NearVehicleDistance`** (`7.0`) : véhicule considéré à proximité.

**Côté serveur (anti-triche)** : distances maximales tolérées, un peu plus larges que côté joueur.
- **`Config.MaxPanelDistance`** (`3.0`), **`Config.MaxEnterDistance`** (`5.0`), **`Config.MaxInteractionDistance`** (`7.0`).

## 10. Debug

- **`Config.Debug`** (défaut `false`) : journal complet dans la console serveur et dans F8. Voir [En cas d'erreur](en-cas-derreur).
- **`Config.DebugCategories`** (défaut `nil` = tout) : limite le journal à certaines catégories, par exemple `{ "license", "deny" }`.

⚠️ Laissez `Config.Debug = false` en production : le journal est très bavard.

# Configuration des échelles

Ce chapitre explique `config/ladders.lua` : la liste des véhicules à échelle reconnus par le script, avec leurs props, leurs butées, leurs extras et leurs places. C'est le chapitre le plus technique, mais c'est lui qui permet d'utiliser MasterLadder avec n'importe quel véhicule à échelle.

## Principe

- Une entrée par véhicule. **La clé est le nom de spawn du véhicule** (ex. `['epan']`).
- Tout réglage absent d'une entrée reprend celui de **`Config.LadderDefaults`** (en bas du fichier). Une entrée peut donc se limiter à son nom, ses props et ce qui diffère.
- **Unités** : angles en degrés, distances en mètres, durées en millisecondes.
- **Repère de rotation** : 0° = échelle vers l'avant (au-dessus de la cabine), sens horaire vu de dessus.

```lua
Config.Ladders = {
    ['epabspp'] = {
        label = "EPA BSPP",
        props = {
            turntable = "prop_tl2_base",
            D         = "prop_tl2_ladder1",
            C         = "prop_tl2_ladder2",
            B         = "prop_tl2_ladder3",
            A         = "prop_tl2_ladder4",
            S         = "prop_tl2_ladder5",
            basket    = "prop_tl2_cage",
            stab      = "prop_tl2_outriggers",
        },
        interface = { theme = nil, forced = false, model = "ML 32", serial = "N° de série 2004-1187" },
        seat = { angle = 143.24, distance = 1.3, height = 0.24 },
        -- le reste reprend Config.LadderDefaults
    },
}
```

## Identité et props

- **`label`** : nom affiché (pupitre, messages).
- **`props`** : noms des modèles de l'échelle, streamés par la ressource du véhicule. **Les 8 sont obligatoires** ; une entrée incomplète est ignorée, avec un avertissement dans la console.
  - `turntable` : tourelle
  - `D` : plan fixe
  - `C`, `B`, `A` : plans coulissants
  - `S` : bras de nacelle
  - `basket` : nacelle
  - `stab` : stabilisateur (utilisé 4 fois)

## Déploiement

- **`deployTime`** (défaut `7000`) : durée du calage et du repli (ms).
- **`maxSlope`** (défaut `8.0`) : pente maximale du véhicule pour déployer (°).

## Butées

- **`elevation`** (défaut `{ min = -15.0, max = 75.0 }`) : inclinaison de l'échelle (°).
- **`length`** (défaut `{ min = 0.0, max = 23.0 }`) : longueur sortie (m), en plus de la longueur repliée.
- **`arm`** (défaut `{ min = -90.0, max = 0.0, floor = -50.0 }`) : bras de nacelle (°). `floor` : le bras ne descend jamais sous `floor` moins l'inclinaison de l'échelle (la nacelle reste horizontale).
- **`light`** (défaut `{ left = -90.0, right = 90.0, down = -85.0, up = 85.0 }`) : débattement du projecteur (°).
- **`rotation`** : zone interdite à l'arrière du véhicule.
  - `stopRight` / `stopLeft` : butées en tournant à droite / à gauche.
  - `resumeRight` / `resumeLeft` : au-delà, la rotation est de nouveau possible (pour ressortir de la zone).
- **`cabZone`** (défaut `{ from = 324.0, to = 34.0 }`) : secteur au-dessus de la cabine où l'échelle ne peut pas descendre sous l'horizontale.

## Extras du véhicule

- **`extras`** : numéros des extras du modèle.
  - `ladder` (défaut `{ 5, 10 }`) : extras de l'échelle repliée, masqués quand elle est déployée.
  - `left` / `right` (défaut `{ open = 6, closed = 7 }` / `{ open = 12, closed = 11 }`) : coffres gauche / droite.
  - `screen` (défaut `{ on = 9, off = 8 }`) : écran de commande arrière.
- **`spawnExtras`** : état du véhicule à sa première apparition.
  - `left`, `right` : `"open"` ou `"closed"`
  - `screen` : `"on"` ou `"off"`
  - `others` : autres extras, `[numéro] = true` (visible) ou `false` (masqué). Ex. `{ [1] = true, [3] = false }`.

💡 Les extras sont appliqués sans réparer le véhicule : les dégâts et les portes ouvertes sont conservés.

## Places

- **`seat`** (défaut `{ angle = 131.78, distance = 1.0, height = -0.28 }`) : position du poste de commande autour de la tourelle (angle en °, distance et hauteur en m).
- **`basketPlaces`** (défaut `3`) : nombre de places dans la nacelle (1 à 3).
- **`basketSpots`** : position de chaque place autour du centre de la nacelle (`angle` en °, `distance` en m).

## Collisions des props

- **`collisions`** (défaut `{ sections = false, basket = true, stabs = true }`) : active les collisions des sections, de la nacelle et des stabilisateurs. À n'activer que si les modèles en possèdent.

## Interface

- **`interface`**
  - `theme` : `nil` (choix du joueur), `"modern"` ou `"retro"` (interface suggérée pour cette échelle).
  - `forced` : `true` impose `theme` à tous les joueurs pour cette échelle.
  - `model`, `serial` : textes de la plaque constructeur du pupitre années 2000.

## Ajouter un véhicule

1. Vérifiez que la ressource du véhicule stream bien **le véhicule et les 8 props** de l'échelle.
2. Copiez une entrée existante et renommez la clé avec le **nom de spawn** du véhicule.
3. Renseignez `label` et `props`.
4. Ajustez les **numéros d'extras** du modèle (`extras`) et l'état de spawn (`spawnExtras`).
5. Redémarrez la ressource, déployez, puis ajustez en jeu `seat`, `basketSpots` et les butées.

💡 Avec `Config.Debug = true`, la console signale les props introuvables par leur nom, et `/mldebug` affiche au-dessus de l'échelle son état complet.

# Permissions & Administration

Ce chapitre explique qui peut faire quoi avec l'échelle, et les outils des administrateurs.

## Actions contrôlées

| Action | Ce qu'elle autorise |
|---|---|
| `deploy` | Déployer et replier l'échelle |
| `enter` | Monter au poste, dans la nacelle ou sur l'échelle |
| `control` | Manœuvrer l'échelle |
| `lock` | Verrouiller les portes du véhicule |
| `locker` | Ouvrir les coffres, allumer l'écran arrière |

## Trois façons de gérer les permissions

1. **Tout le monde** : `Config.JobRestriction = false` (par défaut), ou framework `standalone`.
2. **Par métier et par grade** : `Config.JobRestriction = true` et `Config.AuthorizedJobs` (voir [Configuration générale](configuration-generale)). Avec QBCore / QBox, `Config.RequireOnDuty = true` exige d'être en service.
3. **Votre propre règle** : `Config.CustomPermission`, une fonction qui reçoit le joueur, l'action et l'échelle, et retourne `false` pour refuser. Elle remplace la restriction par métier.

💡 Toutes les vérifications sont faites **côté serveur** : un joueur ne peut pas les contourner en modifiant son client.

## Commande d'administration

Autorisation (dans `server.cfg`) :

```cfg
add_ace group.admin command.mladmin allow
```

| Commande | Effet |
|---|---|
| `/mladmin list` | Liste les échelles déployées et leurs occupants |
| `/mladmin evict <netId\|cl> [all\|op\|seat\|b1\|b2\|b3\|c1\|c2]` | Fait descendre les occupants (tous par défaut) ; `op` retire l'opérateur |
| `/mladmin del <netId\|cl>` | Replie instantanément l'échelle et libère le véhicule |

`cl` désigne l'échelle la plus proche de l'administrateur. La commande fonctionne aussi depuis la console serveur (avec un `netId`).

## Dépannage joueur

`/mlexit` détache le joueur (échelle, poste ou nacelle) s'il reste bloqué.

# Débogage & Erreurs

Ce chapitre regroupe les problèmes les plus courants et l'outil de diagnostic intégré.

## Le mode debug

Passez **`Config.Debug = true`** dans `config/config.lua` et redémarrez la ressource. MasterLadder écrit alors tout ce qu'il fait :

- **console serveur** : vérification de la licence (requête et réponse), chaque action reçue d'un joueur et son résultat, **chaque refus avec sa raison précise** (distance, phase de l'échelle, place occupée, permission, grade…), chaque changement d'état de l'échelle ;
- **console F8** (client) : synchronisation, places, commandes, montée, target, extras, props manquants, interface, performances.

Exemples de lignes :

```
[ML:deny] mladder:enter ← Jean #12 : pied de l'échelle à 6.2 m (max 5.0 m)
[ML:deny] mladder:set ← Jean #12 : déploiement : pente 9.4° (véhicule 9.1°) > 8.0° max
[ML:deny] mladder:control ← Jean #12 : « control » : pompier grade 0 < 1 requis
[ML:state] EPAN 42 tl (rév 18) : occ.b1: 0 → 12
```

**Commandes de diagnostic**
- `mldebug` (console serveur) : état complet de chaque échelle (phase, opérateur, places, valeurs, propriétaire réseau). `mldebug 42` pour une seule.
- `/mldebug` (F8) : état côté client et **surimpression 3D** au-dessus des échelles. Retapez la commande pour la masquer.

Pour ne garder qu'une partie du journal : `Config.DebugCategories = { "license", "deny", "perm" }`.

⚠️ Remettez `Config.Debug = false` une fois le problème trouvé.

## Problèmes fréquents

**« Licence MasterMods refusée : script inactif »**
- La console affiche un rapport : clé envoyée (masquée), d'où elle a été lue, et la raison donnée par le serveur.
- « Clé inconnue » : vérifiez la saisie (copier-coller depuis le portail, sans espace).
- « Aucune clé personnelle trouvée » : la clé n'est ni dans `server.cfg` (`set mastermods_key`) ni dans `Config.MasterModsKey`.
- Clé bloquée : elle a été utilisée sur plus de 3 serveurs différents en 24 h ; elle se débloque seule au bout d'un jour.

**« API MasterMods injoignable (code 0) »**
- Le serveur ne peut pas joindre `ressources.mastermods.dev` (pare-feu, DNS, hébergeur qui bloque les connexions sortantes). Le script reste actif pendant environ 1 h 30 avant de se couper.

**Les props de l'échelle n'apparaissent pas**
- La console F8 affiche « Props non chargés ». Vérifiez que la ressource du véhicule est démarrée **avant** MasterLadder et que les noms de `props` dans `config/ladders.lua` sont exacts. En mode debug, les modèles manquants sont listés.

**Rien ne se passe en visant le véhicule**
- `Config.TargetSystem` ne correspond pas à votre target, ou celui-ci démarre après MasterLadder. La console F8 l'indique ; le script passe alors aux touches.

**« Pente trop forte » / déploiement refusé**
- Déplacez le véhicule sur un sol plus plat, ou augmentez `maxSlope` de l'échelle.

**Impossible de replier**
- Le message précise ce qui manque : rotation, inclinaison, longueur ou bras pas en position de route, ou quelqu'un encore à bord.

**Le joueur est mal placé sur l'échelle** (dans les barreaux, flotte, penché en arrière)
- Ajustez `Config.ClimbOffset` (par pas de `0.05`) et `Config.ClimbTilt` (voir [Configuration générale](configuration-generale)).

**Un joueur est bloqué** (attaché, figé)
- Le joueur tape `/mlexit`. Un administrateur peut aussi utiliser `/mladmin evict cl`.

**Les portes du véhicule se referment toutes seules**
- Corrigé depuis la 5.0.0 : mettez la ressource à jour.

## Support

Si le problème persiste, passez sur [discord.mastermods.dev](https://discord.mastermods.dev) avec :
- la version de MasterLadder (dans `fxmanifest.lua`) ;
- les lignes de la console avec `Config.Debug = true` au moment du problème.

⚠️ Ne partagez jamais votre MasterKey en entier : les journaux l'affichent toujours masquée.

# Formation pour vos joueurs

[Voir pièce jointe](https://docs.raph-dev.fr/attachments/1)