Aller au contenu

Guide du créateur de missions — VEAF Mission Creation Tools

Ce guide s'adresse aux concepteurs de missions DCS World qui souhaitent intégrer le framework VEAF dans leurs missions.


Table des matières

  1. Ce que vous obtenez
  2. Prérequis
  3. Installation et mises à jour
  4. Configuration globale utilisateur
  5. Créer une nouvelle mission
  6. Comment les scripts sont chargés
  7. Configurer les modules
  8. Configurer le pipeline de build
  9. Outils de conception
  10. Workflow de build typique
  11. Profils de build
  12. Référence des scripts
  13. Exemples de configuration
  14. Intégration CTLD et CSAR
  15. DCS Bridge
  16. Journalisation de débogage
  17. Ressources

Migration d'une mission existante ? Consultez le Guide de migration — couvre à la fois VEAF MCT v5 → v6 et DCS vanilla → VEAF MCT.


Ce que vous obtenez

Une mission VEAF est un fichier DCS .miz standard qui charge le framework Lua VEAF au démarrage. Cela offre aux joueurs et aux contrôleurs :

  • Commandes via marqueurs — les joueurs tapent des commandes sur la carte F10 (faire apparaître des unités, créer des zones CAS, déplacer des groupes…)
  • Menus radio F10 — menus dynamiques pour chaque fonctionnalité activée
  • Types de missions préconstruits — CAS, transport, opérations porte-avions, QRA, vagues aériennes, zones de combat
  • Gestion des ressources — ravitailleurs, AWACS, porte-avions avec suivi d'état automatique et menus radio
  • Points nommés — positions cartographiques réutilisables avec services ATC/TACAN optionnels
  • Intégrations — Skynet IADS, CTLD/CSAR

Prérequis

Outil Rôle Obligatoire
DCS World Le simulateur Oui
Éditeur de missions DCS Créer le .miz de base (inclus avec DCS) Oui
Git Contrôle de version pour votre projet de mission Recommandé
veaf-tools-updater.exe Télécharge et installe la dernière release VEAF MCT Oui
veaf-tools.exe CLI de manipulation de .miz au moment du build Oui (pour le pipeline de build)
VS Code ou Notepad++ Édition des fichiers Lua/YAML de configuration Recommandé
ctld-tools.exe Éditeur de la configuration CTLD — fourni avec CTLD, pas avec VEAF MCT (où le télécharger) Seulement si votre mission utilise CTLD

Coalitions de la mission de base : chaque coalition (bleue/rouge) a besoin d'au moins une unité au sol, sinon ses tables Lua de coalition sont incomplètes et DCS supprime le camp vide — ce qui obligeait auparavant à placer un groupe terrestre bleu et un rouge à la main. Le build s'en charge désormais : si une coalition n'a aucune unité, il injecte un unique groupe terrestre placeholder caché (sur le bullseye de la coalition) pour que DCS reconnaisse le camp. Vous pouvez toujours placer vos propres groupes — le placeholder n'est ajouté que si un camp est vide.


Installation et mises à jour

PowerShell ou invite de commandes ?

Sous Windows, le terminal que vous obtenez par défaut — celui du menu contextuel Ouvrir dans le terminal, celui intégré à VS Code — est PowerShell. Tous les exemples de cette documentation sont écrits pour lui.

Un exécutable posé dans le dossier courant s'appelle .\veaf-tools.exe, jamais veaf-tools.exe. PowerShell ne cherche pas dans le dossier courant, et c'est volontaire : c'est une protection contre le détournement de commande — déposer un faux git.exe dans un dossier pour qu'il s'exécute à la place du vrai. Sans le .\, vous obtenez :

veaf-tools.exe is not recognized as a name of a cmdlet, function, script file, or executable program.

(le libellé exact dépend de la version et de la langue de PowerShell). L'erreur nomme le fichier que vous avez sous les yeux, dans le dossier où vous êtes : elle se lit « l'outil est cassé » alors qu'il ne manque que deux caractères.

L'invite de commandes (cmd.exe), elle, cherche dans le dossier courant et accepte les deux formes. .\veaf-tools.exe marche donc dans les deux shells : c'est la forme portable, et la seule que cette documentation écrit.

Les trois écarts entre les deux shells qui mordent vraiment :

PowerShell cmd.exe
Lancer un exécutable du dossier courant .\veaf-tools.exe (obligatoire) les deux formes
Définir une variable d'environnement $env:VEAF_LANG = "fr" set VEAF_LANG=fr
Couper une commande sur plusieurs lignes accent grave ` en fin de ligne accent circonflexe ^

Première installation

Téléchargez veaf-tools-updater.exe depuis la dernière release GitHub et placez-le dans le dossier de votre projet de mission.

Sécurité Windows : Windows peut bloquer les fichiers .exe téléchargés depuis Internet. Si le fichier ne s'exécute pas, cliquez droit dessus → Propriétés → onglet Général → cochez Débloquer en bas de la fenêtre → OK.

Puis exécutez :

.\veaf-tools-updater.exe

Cela télécharge published.zip, vérifie le checksum SHA256 et extrait tous les scripts et outils dans votre dossier de mission.

Mises à jour

Exécutez la même commande dès qu'une nouvelle release est disponible :

.\veaf-tools-updater.exe

La mise à jour n'est effectuée que si la version distante est plus récente. Pour forcer une réinstallation :

.\veaf-tools-updater.exe --force

Pour épingler une version spécifique :

.\veaf-tools-updater.exe --tag published-v6.1.0

Référence CLI complète : Référence CLI


Configuration globale utilisateur

Créez ~/veafmct.yaml (soit C:\Users\VotreNom\veafmct.yaml sous Windows) pour définir des valeurs par défaut persistantes applicables à tous vos projets VEAF sur cette machine :

# ~/veafmct.yaml
lang: fr                 # Langue des outils : "en" (défaut) ou "fr"
check_updates: true      # Vérifier les nouvelles versions de veaf-tools au démarrage
scripts_path: D:/dev/_VEAF/VEAF-Mission-Creation-Tools   # Chemin local du dépôt (pour --dev-mode)

Toutes les clés sont optionnelles. La clé servers: (journaux d'un serveur DCS suivis par SSH dans veaf-logs) est décrite dans Lire les journaux de DCS. Pour initialiser le fichier depuis la CLI :

.\veaf-tools.exe user-config --init

Ou inspecter/modifier les valeurs de manière interactive :

# Afficher la configuration effective et sa source
.\veaf-tools.exe user-config

# Définir une valeur
.\veaf-tools.exe user-config --set lang=fr

# Supprimer une valeur (revenir au défaut)
.\veaf-tools.exe user-config --unset lang

Ordre de détection de la langue (le premier qui correspond gagne) : 1. Option CLI --lang 2. Variable d'environnement VEAF_LANG 3. ~/veafmct.yaml → clé lang: 4. Locale du système (registre Windows / locale système sur Linux–macOS) 5. en (fallback intégré)


Créer une nouvelle mission

Recommandé : mission prepare

Pour une mission neuve, laissez les outils créer le dossier : prepare pose la structure, un mission.yaml documenté avec le jeu de modules choisi et, si vous donnez la carte, une mission vierge pour ce théâtre — sans passer par DCS.

.\veaf-tools.exe mission prepare c:\ma-mission --template standard --theatre Caucasus

Sans option, l'assistant demande le dossier et le jeu de modules. Les options sont détaillées dans les outils de conception.

La mission de démo

La mission de démo v6 (Caucase) montre chaque fonctionnalité en jeu. Une visite guidée (F10 > Autre > Visite guidée) mène d'une étape à l'autre, dit quoi faire et quoi observer, et pose un repère sur votre carte. Elle existe en version française et en version anglaise.

C'est aussi la recette des outils : elle reçoit une étape à chaque nouvelle fonctionnalité, et sa liste de contrôle (docs/recette.md) est rejouée avant chaque release.

Son dossier est un bon exemple de mission.yaml complet à lire. Pour démarrer votre propre mission, partez plutôt de mission prepare que d'une copie de la démo : vous auriez à retirer tout ce qu'elle montre.

Depuis zéro

  1. Créez un dossier pour votre projet de mission (c'est votre dépôt Git)
  2. Copiez votre fichier .miz existant dedans
  3. Exécutez .\veaf-tools-updater.exe pour récupérer tous les scripts VEAF
  4. Extrayez votre mission : .\veaf-tools.exe mission extract ma-mission.miz
  5. Configurez les modules dans mission.yaml et éventuellement src/scripts/mission-script.lua

Structure de projet recommandée :

MyMission/
├── src/
│   ├── mission/                  # Données DCS extraites (via extract)
│   ├── scripts/
│   │   ├── mission-script.lua    # Votre code Lua personnalisé (optionnel)
│   │   └── veafDynamicConfig.lua # Config de chargement dynamique des scripts (dev/test)
│   ├── options                  # Table d'options DCS injectée dans le .miz
│   ├── presets.yaml             # Préréglages de fréquences radio (étape presets)
│   ├── spawnables.yaml          # Groupes d'avions spawnables (préfixe veafSpawn-, étape spawnable_aircrafts)
│   ├── dynamic-slot-templates.yaml # Modèles de Dynamic Slots (dynSpawnTemplate=true, étape dynamic_slot_templates)
│   ├── warehouses.yaml          # Dynamic Slots par coalition (étape warehouses, optionnel)
│   ├── spawn-groups.yaml        # Extension/override de la base de spawn (étape spawn_data, optionnel)
│   ├── versions.yaml            # Variantes météo/horaires (étape weather)
│   └── waypoints.yaml           # Points de navigation par plan de vol (étape waypoints)
├── published/                    # Scripts & outils VEAF (auto-installés)
├── mission.yaml                  # Configuration de build
├── .gitignore                    # Exclut les fichiers générés/téléchargés
├── veaf-tools.exe                # Outil CLI (auto-installé)
└── veaf-tools-updater.exe

Chaque fichier listé sous src/ (hormis la sortie d'extraction mission/) provient du gabarit defaults/mission-folder/ de l'outil et est consommé dès le premier build — les *.yaml par leur étape de pipeline/module, options par injection dans le .miz, et les scripts/*.lua par le chargement de scripts.


Comment les scripts sont chargés

La commande build injecte automatiquement un trigger DO SCRIPT FILE au démarrage de la mission qui charge tous les scripts VEAF. Vous n'avez pas besoin d'ajouter manuellement un trigger dans l'éditeur de missions DCS.

Si vous avez un src/scripts/mission-script.lua personnalisé, il est aussi injecté automatiquement par le builder.

Ce que fait le builder

  1. Lit src/mission/ (les données DCS extraites)
  2. Supprime tous les triggers VEAF existants
  3. Injecte de nouveaux triggers DO SCRIPT FILE pour tous les scripts VEAF + vos scripts personnalisés
  4. Écrit le .miz final

Le build complet exécute ensuite les étapes optionnelles du pipeline dont les fichiers de configuration sont présents (presets, waypoints, groupes d'aéronefs, météo) :

flowchart TD
    subgraph Entrées
        YAML[mission.yaml]
        SRC[src/mission + src/scripts]
        LUA[Scripts Lua VEAF]
    end
    YAML --> BUILD[veaf-tools mission build]
    SRC --> BUILD
    LUA --> BUILD
    BUILD --> GEN[Génère veaf-config.lua depuis mission.yaml]
    GEN --> TRIG[Injecte les triggers DO SCRIPT FILE]
    TRIG --> PIPE{Étapes optionnelles du pipeline}
    PIPE -->|presets.yaml| P1[inject-presets]
    PIPE -->|waypoints.yaml| P2[inject-waypoints]
    PIPE -->|spawnables.yaml| P3[inject spawnable aircraft]
    PIPE -->|dynamic-slot-templates.yaml| P3b[inject Dynamic-Slot templates]
    PIPE -->|warehouses.yaml| P5[wire Dynamic Slots]
    PIPE -->|spawn-groups.yaml| P6[inject spawn data]
    PIPE -->|versions.yaml| P4[inject-weather]
    P1 --> OUT[.miz final prêt à voler]
    P2 --> OUT
    P3 --> OUT
    P3b --> OUT
    P5 --> OUT
    P6 --> OUT
    P4 --> OUT

Note — templates et slots multijoueur : les groupes injectés depuis spawnables.yaml et dynamic-slot-templates.yaml sont des modèles réutilisables. Pour éviter qu'ils n'apparaissent comme slots sélectionnables dans le briefing multijoueur, le build les masque automatiquement de la liste des slots (hiddenOnPlanner/hiddenOnMFD) et les verrouille par un mot de passe. Le spawn dynamique (qui référence le template par son nom) reste pleinement fonctionnel.

Les modèles fournis sont un point de départ, pas un catalogue prêt à l'emploi. Quand un pilote prend un slot dynamique, DCS lui donne l'appareil tel qu'il est décrit dans le modèle : emport, livrée, fréquences. Or sur les 52 modèles livrés par défaut, 9 seulement ont un emport — un A-10C II ou un F-14B sortent armés et peints, un UH-1H, un F/A-18C ou un M-2000C sortent nus. Ce n'est pas un défaut du build : le lien modèle → appareil fonctionne, c'est le modèle qui est vide.

Pour donner à vos pilotes des appareils équipés, configurez-les une fois dans une mission (dans l'éditeur DCS, avec l'emport et la livrée que vous voulez), puis régénérez le fichier depuis cette mission :

.\veaf-tools.exe content extract-aircraft-groups ma-mission.miz --kind dynamic-template

Cela réécrit src/dynamic-slot-templates.yaml avec vos modèles. Le prochain build les injecte, et les slots dynamiques proposent des appareils prêts à décoller.

Ajoutez --merge pour enrichir le catalogue au lieu de le repartir de zéro. Sans cette option le fichier est régénéré à partir de la seule mission, donc les modèles d'une deuxième mission — ou un modèle que vous avez retouché à la main — sont perdus. Avec elle, la mission gagne sur un groupe de même nom et chaque remplacement est nommé dans le compte rendu, tandis que tout ce que la mission ne porte pas est conservé :

.\veaf-tools.exe content extract-aircraft-groups deuxieme-mission.miz --kind dynamic-template --merge

Configurer les modules

VEAF MCT a deux niveaux de configuration :

  • mission.yaml (à la racine du projet) — configuration de build : quels modules activer/désactiver, niveaux de log, sécurité, déclarations d'assets
  • src/scripts/mission-script.lua (optionnel) — code Lua personnalisé exécuté au démarrage de la mission : alias, fonctions utilitaires, intégration de scripts tiers (CTLD, CSAR). L'initialisation et la configuration des modules sont générées automatiquement depuis mission.yaml.

Pour la plupart des missions, mission.yaml suffit. N'utilisez mission-script.lua que pour du code Lua personnalisé qui ne peut pas être exprimé en YAML.

Exemple mission.yaml

mission:
  name: "My-Mission"

modules:
  SECURITY: true        # raccourci : activer simplement le module
  SPAWN:
    logLevel: debug     # un module avec configuration utilise un bloc
  ASSETS:
    enabled: true
    assets:
      - sort: 1
        name: "T1-Arco-1"
        description: "Arco-1 (KC-135)"
        information: "Tacan 64Y\nU290.50 (20)"

Le bloc unifié modules: remplace les anciennes clés lua_modules: + community_scripts:, et enabled: remplace enable:. Les clés héritées fonctionnent toujours mais émettent un avertissement de dépréciation. Voir la Référence mission.yaml pour la syntaxe complète.

Exemple mission-script.lua

-- mission-script.lua — code Lua personnalisé au niveau mission
-- L'initialisation des modules est gérée automatiquement par veaf-config.lua (généré depuis mission.yaml).
-- Mettez ici vos alias, fonctions utilitaires et intégrations de scripts tiers.

-- Exemple : alias de raccourci personnalisé
-- veafShortcuts.AddAlias(VeafAlias:new():setName("-cas1"):setVeafCommand("_cas"))

-- Note : rien à écrire ici pour CTLD — il se configure dans ctld-config.yaml
-- (voir la section Intégration CTLD et CSAR)

MiST : injecté seulement si vous en avez besoin

MiST était chargé dans toutes les missions, parce que les scripts VEAF s'en servaient partout. Ils ne l'appellent plus du tout, et aucun script communautaire livré ici non plus. Une mission qui n'en a pas besoin n'emporte donc plus ses 336 Ko.

Vous n'avez rien à faire : au build, VEAF lit vos propres scripts dans src/scripts/ et, s'il en trouve un qui appelle mist., il réinjecte MiST en vous disant lequel :

MiST n'est plus injecté par défaut, mais 'src/scripts/HoundElint.lua' l'utilise :
il est injecté pour cette mission.

C'est le cas courant : un script tiers comme HoundElint appelle MiST, la détection le voit, tout continue de fonctionner. La conversion depuis la v5 fait la même lecture, donc une mission convertie garde MiST si et seulement si elle s'en sert.

Ce que la détection ne peut pas voir : un script qui en charge un autre, ou qui atteint MiST par _G["mist"]. Dans ce cas seulement, demandez-le explicitement :

modules:
  MIST: true

Un MIST: false ne l'emporte pas sur la détection : si l'un de vos scripts appelle MiST, il est injecté quand même. Honorer le drapeau reviendrait à casser la mission en vol pour respecter une ligne de configuration.

Si votre mission.yaml contient déjà une ligne MIST: sans valeur, elle voulait dire « module obligatoire, toujours actif » ; elle veut maintenant dire « pas demandé ». C'est le cas de toutes les missions créées jusqu'ici, puisque le modèle livré contenait cette ligne. Vous n'avez rien à changer : votre mission s'allège de 336 Ko, et si l'un de vos scripts appelle MiST, la détection le réinjecte.

Niveaux de sécurité

Palier Constante Passe sans mot de passe si le niveau du pilote est
KNOWN_PILOT veafSecurity.LEVEL_KNOWN_PILOT = 1 ≥ 1 — tout pilote inscrit dans le veaf-pilots.txt du serveur
SENIOR_PILOT veafSecurity.LEVEL_SENIOR_PILOT = 10 ≥ 10 — un membre de confiance
ADMIN veafSecurity.LEVEL_ADMIN = 90 ≥ 90 — un administrateur du serveur
MM (aucun niveau) jamais — seul le mot de passe Mission Master ouvre
OPEN (aucun contrôle) toujours — la commande est délibérément ouverte à tous

L9, L1 et L0 sont des alias dépréciés — et ils se lisent à l'envers

Les anciens noms se lisent à l'envers de ce qu'ils suggèrent : L0 est le palier le plus strict (ADMIN), pas le plus permissif ; L9 est le plus ouvert (KNOWN_PILOT).

L9, L1 et L0 restent acceptés comme alias dépréciés et disparaîtront dans une version ultérieure. Les valeurs sont inchangées (1, 10, 90) : renommer ne change le comportement d'aucune mission, seulement ce que vous écrivez.

Deux choses satisfont un contrôle. Soit le niveau de pilote du joueur, publié par le hook serveur depuis veaf-pilots.txt, atteint le palier — c'est la voie par l'identité, sans mot de passe — soit le mot de passe du palier figure dans le texte du marqueur. Sans le hook, personne n'a de niveau et tout retombe sur les mots de passe.

Définissez les mots de passe (hachages SHA-1 — c'est ce que veafSecurity compare) dans mission.yaml :

security:
  disabled: false
  password_hashes:
    - "<hachage SHA-1 de votre mot de passe>"

Configurer le pipeline de build

Au-delà des modules Lua exécutés dans DCS, veaf-tools mission build peut enchaîner des étapes de pipeline au moment du build : elles injectent des données dans le .miz (préréglages radio, points de cheminement, groupes d'aéronefs, variantes météo) à partir de fichiers YAML séparés placés dans src/. Chaque étape est auto-détectée (elle s'exécute si son fichier de config existe) et se pilote depuis la section pipeline: de mission.yaml.

Étape Rôle Schéma détaillé
presets Injecte les préréglages de fréquences radio dans les groupes d'avions pilotés par des humains et génère les planchettes (kneeboards) PNG associées presets.yaml
waypoints Injecte des modèles de points de cheminement (bullseye, navigation) dans les groupes d'avions humains waypoints.yaml
spawnable_aircrafts / dynamic_slot_templates Injecte les groupes d'aéronefs spawnables et les modèles de slot dynamique groupes d'aéronefs
weather Crée plusieurs variantes de mission avec différentes météos et heures versions.yaml

Chaque étape accepte la forme scalaire (true/false pour activer ou ignorer) ou la forme mapping (options détaillées). Par exemple, l'étape presets peut conserver l'injection radio tout en supprimant les planchettes PNG globalement :

pipeline:
  presets:
    enabled: true       # défaut true — injecte les préréglages radio
    kneeboards: false   # défaut true — si false, aucune planchette PNG n'est générée

Voir la Référence Pipeline pour le schéma complet de chaque étape et la Référence mission.yaml pour tous les champs de pipeline:.


Quel plan de vol pour quel appareil ?

src/waypoints.yaml déclare des plans de vol, chacun avec des critères : coalition, catégorie (plane / helicopter), type d'appareil, pays. Les critères qu'un plan ne pose pas sont des jokers.

Le plan le plus précis gagne. Parmi ceux qui correspondent, celui qui pose le plus de critères est retenu — où qu'il soit écrit dans le fichier.

settings:
  all_blue_planes:
    coalition: blue
    category: plane
    waypoints: { ... }

  f16_flight_plan:          # plus précis : il nomme aussi le type
    coalition: blue
    category: plane
    type: F-16C_50
    waypoints: { ... }

Un F-16C bleu correspond aux deux et reçoit f16_flight_plan. Un autre avion bleu reçoit all_blue_planes. Un plan sans aucun critère est le repli : il correspond à tout et perd contre tout. L'ordre de déclaration ne tranche qu'une égalité de précision, et seulement dans ce cas.

Ce comportement a changé en 6.15.42

Avant, c'était le premier plan compatible qui gagnait, donc l'ordre de déclaration décidait — et un plan précis écrit après un plan large était inatteignable. Ce fichier et le code annonçaient tous deux la règle de précision depuis des années sans qu'elle soit implémentée ; c'est elle qui l'est désormais.

Si vous aviez rangé vos plans du plus étroit au plus large pour contourner le problème, rien ne change pour vous. Si vous vous appuyiez sciemment sur l'ordre pour qu'un plan large en masque un précis, ce plan précis va maintenant s'appliquer.

Seuls les groupes pilotés par un humain reçoivent des waypoints — et depuis la 6.15.43, tous les reçoivent.

Avant la 6.15.43, votre plan de vol n'atteignait presque aucun slot

L'étape waypoints tournait avant l'injection des appareils (spawnables.yaml, dynamic-slot-templates.yaml). Les slots que ces fichiers créent n'existaient donc pas encore quand les waypoints étaient injectés.

Mesuré sur la mission de fumée du dépôt : 105 groupes pilotés par un humain, 1 seul portait un waypoint du plan — celui qui était déjà dans le .miz source. À la position corrigée : 105 sur 105.

Ça ne concernait pas qu'un bullseye automatique : c'était votre plan de vol déclaré, appliqué à une poignée de slots et à rien d'autre. Et le build ne le disait pas — il annonçait « 1 injecté, 0 sans plan », ce qui est exact et parfaitement sain à lire. Le compte était pris avant que le monde soit fini.

Ce que ça change pour vous : si votre mission utilise des slots dynamiques ou des appareils spawnables, vos waypoints déclarés vont maintenant s'appliquer à ces slots — c'est-à-dire ce que vous demandiez déjà. Si votre mission n'a que des slots posés dans l'éditeur, rien ne change.

Le bullseye, injecté tout seul

Depuis la 6.15.44, chaque plan de vol reçoit en plus un waypoint BULLSEYE aux coordonnées du bullseye de votre mission — plus besoin de le déclarer, et plus de risque de recopier celles d'une autre carte.

La coalition est prise en compte : un vol rouge reçoit le bullseye rouge, tout le reste reçoit le bleu. C'est la même règle que les scripts VEAF appliquent en jeu depuis #304, et ce n'est pas un raccourci : dans les vraies missions, le bullseye « neutre » vaut souvent {0, 0} ou {100, 100}, donc un vol neutre serait envoyé à l'origine de la carte.

Le waypoint est ajouté à la fin du plan, donc la numérotation de vos points existants ne bouge pas.

Un plan qui ne déclare aucun waypoint (waypoints: {}) le reçoit aussi : c'est la façon d'écrire « juste le bullseye » pour un type d'avion. Seul un groupe sans plan de vol n'en reçoit pas.

Votre déclaration gagne toujours

Si votre plan de vol déclare déjà un waypoint nommé BULLSEYE, c'est le vôtre qui est utilisé, avec vos coordonnées. Rien n'est ajouté et rien n'est remplacé.

Pour le désactiver :

pipeline:
  waypoints:
    bullseye: false

Et il ne s'applique qu'aux missions qui injectent déjà des waypoints : une mission sans src/waypoints.yaml n'est pas touchée, et un groupe auquel aucun plan de vol ne correspond ne reçoit rien — le bullseye accompagne un plan, il n'en crée pas.

Le build vous dit combien il en a ajouté.

Outils de conception

veaf-tools.exe manipule les fichiers .miz au moment du build — avant de les charger dans DCS.

Les commandes sont rangées par thème. veaf-tools mission build, veaf-tools content inject-presets, veaf-tools convert v5… veaf-tools --help liste les groupes, et veaf-tools <groupe> --help leur contenu. Le groupe dcs regroupe ce qui exige DCS lancé. Les groupes sont : mission, convert, content, campaign, cockpit et dcs. Une commande dont le nom commence par celui de son groupe le perd à l'intérieur : on écrit veaf-tools convert v5 et veaf-tools convert other, pas convert convert-v5.

Les anciens noms courts fonctionnent toujours : veaf-tools build fait exactement la même chose que veaf-tools mission build. Ils ne sont plus affichés dans l'aide et sont considérés comme dépréciés — un script ou un message de forum écrit avant ce changement continue de marcher.

Commande Ce qu'elle fait
prepare Initialise/rafraîchit un dossier de mission depuis le scaffold par défaut ; --template minimal\|standard\|full\|custom génère un mission.yaml avec le jeu de modules correspondant (custom = choix interactif) ; --list-templates pour les lister. --theatre <nom> génère aussi une mission vierge synthétique pour cette carte DCS dans src/mission/ (sans passer par DCS pour démarrer) ; --list-theatres pour lister les cartes supportées. Le fichier généré inclut le même préambule documenté que convert-v5 (guide de syntaxe YAML, global_log_level:, mission:, security:, pipeline:)
build Construit la mission depuis src/ — injecte les triggers VEAF, produit un .miz. Valide au passage les références de mission.yaml vers le Mission Editor (zones de déclenchement, groupes, unités, aérodromes) et affiche un récapitulatif bien visible en fin de build pour les références absentes — sans bloquer (le .miz est généré quand même, pour que vous puissiez corriger dans le Mission Editor et itérer). Le zone_name d'une opération COMBATZONE n'est pas vérifié (ce n'est qu'un libellé, pas une trigger zone requise)
validate Vérifie le dossier de mission avant le build — signale les erreurs de config et les risques runtime sans builder (sortie non nulle en cas d'erreur ; --strict échoue aussi sur les avertissements)
ctld-upgrade Met ctld-config.yaml au niveau du catalogue CTLD livré avec les outils : ajoute les réglages absents à leur valeur par défaut, sans changer les vôtres ni toucher à vos listes — seule une liste que CTLD a ajoutée après la version de votre fichier, comme celles de la Fat Cow, est écrite (détail)
extract Extrait un .miz vers un dossier source (à exécuter une fois pour initialiser votre dépôt)
export Exporte un .miz en JSON (défaut), YAML ou Markdown (résumé lisible) : export mission.miz out.json --format json. L'analyse est purement Python (parser luadata) et n'exécute jamais de Lua — alternative sûre à l'interprétation d'un .miz non fiable (risque d'exécution de code). Sans fichier de sortie, écrit sur la sortie standard
password-hash Transforme un mot de passe en hash SHA-1 pour security.password_hashes, en saisie masquée ; seul le hash est affiché (référence)
combat-log Après la mission, le récap par pilote de son journal de combat (veaf-combat-log-*.jsonl, module COMBATLOG) : armes tirées, obus, coups au but, destructions (référence)
inject-presets Injecte des plans de fréquences radio pour tous les cockpits humains
inject-weather Crée des variantes météo/heure depuis une config YAML
inject-aircraft-groups Injecte des templates de groupes d'aéronefs
extract-aircraft-groups Extrait les groupes d'aéronefs d'une mission
pull-aircraft-groups Liste ce que le catalogue livré a et que votre dossier n'a pas, et recopie les entrées choisies (vos entrées ne sont jamais remplacées)
airfield-channels Liste les aérodromes de la mission avec les fréquences que DCS leur donne, et écrit ceux choisis dans la collection bases du plan radio (--apply)
inject-waypoints Injecte des waypoints (bullseye, points de navigation) pour les groupes humains
extract-waypoints Extrait les waypoints d'une mission
convert-v5 Migre un dossier mission v5 vers le format v6
user-config Affiche ou modifie la configuration globale utilisateur (~/veafmct.yaml)
about Affiche les informations sur VEAF Mission Creation Tools.
ask Pose une question sur la documentation VEAF (assistant IA). Sans question, démarre une session interactive.
capture-map Capture les aérodromes d'un théâtre depuis une mission-pont en cours (via dcs-serve) dans .json ; --parking ajoute les places de parking dans parking/<théâtre>.json.
clear-ground-check Vérifie dans DCS, sans les faire apparaître, si les véhicules au sol d'une mission construite sont dans le décor, et compare au catalogue de terrain dégagé.
scenery-objects Liste dans DCS les objets de la carte (ponts, bâtiments) autour de points, avec l'identifiant que prend le scenery_targets d'une zone de combat.
farp-spot Cherche dans DCS, près d'un point, les places plates et dégagées d'arbres et de bâtiments où poser un FARP — la commande que donne add_farp quand il n'a pas pu vérifier le pad.
terrain-sweep Relève dans DCS l'altitude du sol de tout un théâtre, que l'action MCP terrain_elevation lit ensuite sans DCS (altitude d'une cible, plancher d'une route, masquage par le relief).
clear-ground-sweep Sonde, pas à pas, le terrain dégagé autour des aérodromes et des combat zones d'un théâtre : écrit la mission d'arpentage, explique quoi faire dans DCS, balaie, puis écrit le catalogue ; reprend un balayage interrompu.
convert-other Adopte une mission .miz tierce (non-VEAF) sur la chaîne d'outils v6.
campaign-init Démarre une campagne multi-missions : crée son état à partir de campaign.yaml.
campaign-validate Vérifie un dossier de campagne : campaign.yaml, et l'état de campagne par rapport à lui.
campaign-next Crée, ou rafraîchit, le dossier de la mission suivante d'une campagne à partir de son état.
campaign-briefing Écrit le briefing stratégique de la campagne (PPTX) pour la mission suivante, à partir de la campagne et de briefing.yaml.
campaign-apply Applique à une campagne le fichier d'état d'une mission jouée, puis joue le tour entre les missions.
doctor Rassemble les versions, chemins et erreurs récentes qu'un rapport de bug exige, et produit un bloc caviardé à coller dans un signalement — voir Obtenir de l'aide.
explore-cockpit Explorer un cockpit : nommez un contrôle pour le voir, ou bougez-en un pour le faire nommer.
generate-config Génère un modèle mission.yaml documenté pour un dossier de mission.
inject-bridge Injecte le dcs-bridge + un trigger de démarrage dans un .miz (mission-pont).
ai-setup Branche les assistants IA du PC (Claude Desktop, Claude Code, Codex, Antigravity, Gemini CLI, OpenCode) sur les outils VEAF — voir Créer avec une IA.
mcp Démarre le serveur MCP d'édition de mission assistée par LLM (stdio). Déclaré dans votre assistant IA par ai-setup.
migrate-config Migre un fichier missionConfig.lua au format v6 (mission-script.lua).
resolve-checklist Complète les champs techniques d'une checklist guidée écrite en langage courant.
smoke-test Vérifie le comportement runtime VEAF dans la mission lancée dans DCS, par le bridge VEAF — voir la référence.
mission-check-prepare, mission-check Vérifie la mission lancée dans DCS (une copie portant le bridge VEAF) : libellés F10, chaque zone et mission de combat activée puis désactivée, chaque colonne vue en mouvement — voir la référence.
recon-prepare, recon-plan, recon-shoot, recon-render Photos de reconnaissance des objectifs prises dans DCS, marquées au feutre, pour le briefing — voir le déroulé.
verify-checklist Vérifie une checklist résolue dans un vrai cockpit (DCS doit tourner ici).

Référence complète : Référence CLI

Mode interactif (assistant)

Dans un terminal interactif, veaf-tools.exe ouvre un assistant guidé (TUI) plutôt que d'échouer sur une option manquante :

  • .\veaf-tools.exe (sans argument) → menu de sélection de commande, puis questions.
  • .\veaf-tools.exe mission prepare → l'assistant demande le dossier cible et le template de modules.
  • .\veaf-tools.exe mission prepare c:\ma-mission → le dossier est déjà fourni, l'assistant ne demande que le template.
  • --tui ajouté à n'importe quelle commande → ouvre l'assistant même si rien ne manque (ex. .\veaf-tools.exe mission build --tui).

Les options déjà passées sur la ligne de commande sont pré-remplies ; les options inconnues (ex. --verbose) sont conservées telles quelles. Hors terminal interactif (CI, sortie redirigée), l'assistant ne se déclenche jamais : la commande s'exécute normalement.

Navigation : Ctrl-B (ou Échap deux fois) revient au prompt précédent ; depuis le menu principal (ou le premier prompt d'une commande), il quitte l'assistant. Un rappel s'affiche en bas de chaque prompt.


Workflow de build typique

# Construire la mission — le pipeline intégré exécute toutes les étapes activées automatiquement
.\veaf-tools.exe mission build

La commande build lit mission.yaml et exécute chaque étape activée du pipeline (presets, waypoints, groupes d'aéronefs, météo) en une seule passe. Configurez les étapes actives sous la clé pipeline: dans mission.yaml.

Avancé : exécuter les étapes du pipeline individuellement Si vous devez exécuter une seule étape en isolation (ex : injecter la météo uniquement, sans rebuild complet) :
# Injecter les préréglages radio uniquement
.\veaf-tools.exe content inject-presets ma-mission.miz --presets-file src/presets.yaml

# Injecter les waypoints bullseye et de navigation uniquement
.\veaf-tools.exe content inject-waypoints ma-mission.miz --waypoints-file src/waypoints.yaml

# Créer des variantes météo/heure uniquement
.\veaf-tools.exe content inject-weather ma-mission.miz --config-file versions.yaml

Commitez le contenu de src/ dans Git — pas le .miz construit. Utilisez extract une fois pour initialiser le dossier source depuis une mission existante :

.\veaf-tools.exe mission extract ma-mission.miz

Profils de build

Les profils de build permettent de basculer entre différentes configurations nommées sans modifier mission.yaml. Définissez une section profiles: une seule fois, puis sélectionnez un profil au moment du build :

# mission.yaml
global_log_level: info
security:
  disabled: false
pipeline:
  weather: true

profiles:
  TEST:
    global_log_level: debug
    security:
      disabled: true
    pipeline:
      weather: false   # pas de variantes météo pendant les builds de test
  SERVER:
    global_log_level: info
    pipeline:
      weather: true
# Build pour les tests (pas de météo, sécurité désactivée, journalisation détaillée)
.\veaf-tools.exe mission build --profile TEST

# Build pour le déploiement serveur
.\veaf-tools.exe mission build --profile SERVER

# Build sans profil (config de base)
.\veaf-tools.exe mission build

Les clés du profil fusionnent en profondeur sur la config de base : seules les clés que vous spécifiez sont surchargées, tout le reste reste tel que défini en haut de mission.yaml. Passer un nom de profil inconnu émet un avertissement et revient à la config de base.

Un build avec --profile écrit son propre .miz, suffixé du nom du profil (MaMission_20261028_TEST.miz) : il n'écrase plus le build sans profil.

Voir profiles: dans la référence YAML pour la description complète.


Référence des scripts

Tous les modules Lua VEAF sont disponibles une fois veaf-scripts.lua chargé. Voir scripts/README.md pour la liste complète avec les guides de configuration.

Navigation rapide par catégorie :

Catégorie Modules
Cœur veafSpawn, veafMove, veafSecurity, veafNamedPoints
Types de missions veafCasMission, veafCombatZone, veafTransportMission, veafQraManager, veafAirWaves
Ressources veafAssets, veafCarrierOperations, veafGrass, veafWeather
Protection veafSanctuary, veafMissileGuardian
Intégrations veafSkynetIadsHelper

Exemples de configuration

Zone QRA

local northQra = VeafQRA:new()
  :setName("QRA-North")
  :setTriggerZone("ZONE-QRA-NORTH")
  :setCoalition(coalition.side.RED)
  :addGroup("MiG-29 QRA")
  :start()

Une QRA unique et fixe se dimensionne mal : une paire de MiG-29 est un défi pour deux joueurs, un exercice de tir pour six. Donnez-lui des paliers par nombre d'intrus (groups_by_enemy_count) jusqu'à la taille attendue du dispositif, et, si l'effectif varie, un niveau d'opposition qui suit les joueurs connectés.

Zone de combat

Une zone de combat se déclare dans mission.yaml. Son contenu ne se liste pas ici : la zone adopte tous les groupes situés à l'intérieur de la trigger zone DCS qu'elle nomme et dont le nom commence par le nom de la zone (la casse est ignorée). Vous tracez le cercle dans l'éditeur de mission, vous y placez les blindés et la DCA — nommés ZONE-STRIKE-ALPHA-ARMOR, ZONE-STRIKE-ALPHA-AAA — et la zone les détruit puis les fait réapparaître à l'activation. Un groupe posé dans le cercle mais nommé autrement est ignoré, en silence : voir la règle du préfixe.

modules:
  COMBATZONE:
    enabled: true
    combat_zones:
      - type: zone
        zone_name: ZONE-STRIKE-ALPHA    # la trigger zone DCS où se trouvent les groupes
        friendly_name: Strike Alpha     # libellé dans le menu F10
        briefing: Colonne blindée avançant sur Senaki. Détruisez tous les véhicules blindés ; attendez-vous à de la DCA.
        training: false

La façon dont chaque groupe apparaît — sa dispersion, sa probabilité, son délai — s'écrit dans les noms d'unités, avec les tags #spawnradius, #spawnchance, #spawncount, #spawndelay et #alarm. Voir veafCombatZone pour la liste complète des champs et pour ces tags.

Le Lua sert à ce que le YAML ne sait pas dire

VeafCombatZone:new():…:initialize() reste l'API sous-jacente, et mission.yaml génère exactement ces appels — l'écrire à la main n'apporte donc rien pour une zone ordinaire. Servez-vous en pour ce qui n'a pas de clé YAML, dans src/scripts/mission-script.lua, une fois la zone déclarée :

veafCombatZone.GetZone("ZONE-STRIKE-ALPHA"):setOnCompletedHook(myCallback)

Zone Air Waves

local defenseZone = AirWaveZone:new()
  :setName("AW-Defense")
  :setTriggerZone("ZONE-DEFENSE")
  :setDescription("Zone d'interception")
  :addPlayerCoalition(coalition.side.BLUE)
  :addWave({ "MiG-23 Wave 1", "MiG-23 Wave 1b" })
  :addWave({ "MiG-29 Wave 2" })
  :start()

Intégration CTLD et CSAR

Voir en jeu : étape 15 « Hélicoptères : FARP, CTLD, CSAR » de la mission de démo.

CTLD (transport de troupes et logistique) et CSAR (Combat Search and Rescue) sont des scripts tiers que VEAF supporte nativement : vous n'avez ni à les charger ni à les initialiser vous-même. Ils ne se configurent pas de la même façon — CSAR se règle dans mission.yaml, CTLD dans son propre fichier.

Configurer CTLD : ctld-config.yaml + ctld-tools

Dans mission.yaml, CTLD n'a plus qu'un interrupteur :

modules:
  CTLD: true

Tout le reste — distances, temporisations, caisses, groupes de troupes, zones, capacités par appareil — vit dans un fichier ctld-config.yaml, à côté de mission.yaml dans votre dossier mission. Vous l'éditez avec ctld-tools.exe, fourni avec CTLD : double-cliquez, l'outil s'ouvre dans votre navigateur, en local, sans installation. Il valide au fil de la saisie et affiche les libellés en clair plutôt que les noms de réglages.

Où récupérer ctld-tools

L'outil ne vient pas avec VEAF MCT. Il est publié avec CTLD : ouvrez les releases de VEAF/CTLD et téléchargez le fichier ctld-tools.exe attaché à la release.

Il n'apparaît pas en « Latest release »

Tant que CTLD 2 n'a pas de version stable, toutes ses releases sont publiées en pre-release — la page d'accueil du dépôt n'en affiche donc aucune, et le lien « Releases » est le seul chemin.

Ne vous fiez pas non plus au premier élément de la liste : l'entrée « CTLD dev build » n'est pas une release, mais la compilation du dernier commit fusionné, et elle repasse en tête à chaque reconstruction. Les vraies releases portent une étiquette published-v… — c'est parmi celles-là que vous choisissez, avec le critère ci-dessous.

Prenez la release qui correspond à la version de CTLD embarquée dans votre VEAF MCT : l'outil et le moteur évoluent ensemble. Cette version est écrite en clair dans l'entête du script installé chez vous, published/src/scripts/community/CTLD.lua :

    CTLD.lua - Combined Transport and Logistics Dispatcher for DCS World
    Version : 2.0.0-rc7

(La vôtre peut être plus récente — c'est cette ligne qui fait foi, pas cet exemple.)

Après chaque mise à jour de VEAF MCT, relisez cette ligne : si la version a changé, retéléchargez ctld-tools.exe depuis la release correspondante. Un décalage n'est pas silencieux — l'outil vous liste les écarts en ouvrant votre fichier (voir plus bas).

Sécurité Windows : comme pour veaf-tools-updater.exe, Windows peut bloquer un .exe téléchargé depuis Internet. Clic droit → Propriétés → cochez Débloquer → OK.

Le fichier de configuration

veaf-tools mission prepare crée ce fichier pour vous quand le modèle choisi active CTLD, pré-rempli avec les valeurs par défaut du moteur. Il n'est jamais écrasé ensuite : c'est votre configuration.

Au build, VEAF l'injecte dans la mission sous forme d'un CTLD_userConfig.lua chargé juste avant CTLD.lua.

N'utilisez pas le bouton « Injecter dans la mission » de ctld-tools

Il écrit directement dans un .miz. Sur une mission VEAF, le .miz est reconstruit à chaque build depuis le dossier mission : votre injection serait effacée au build suivant. Enregistrez le fichier ctld-config.yaml, et laissez le build faire le reste.

Les FARP et porte-avions posés dans l'éditeur

Pour qu'une FARP ou un porte-avions serve de point de chargement, CTLD 2 doit connaître son type d'unité — par les réglages logisticUnitTypes et troopZoneShipTypes. CTLD les livre vides, ce qui est le bon choix pour le reste du monde et le mauvais pour une mission VEAF, qui a toujours reconnu les porte-avions et les dépôts de munitions FARP automatiquement.

VEAF s'en charge, via un interrupteur dans mission.yaml :

modules:
  CTLD:
    enabled: true
    manage_logistics: true   # défaut

Au build, les types VEAF (LHA_Tarawa, Stennis, CVN_71, KUZNECOW, FARP Ammo Dump Coating) sont ajoutés à ce que votre fichier déclare. Ajoutés, pas substitués : un type que vous avez saisi vous-même dans ctld-tools — un porte-avions de mod, par exemple — est conservé. Votre ctld-config.yaml n'est pas modifié ; c'est la copie injectée dans la mission qui l'est, et le CTLD_userConfig.lua généré indique en commentaire ce qui a été ajouté.

Passez le réglage à false pour gouverner ces deux listes entièrement vous-même — c'est le seul moyen de retirer un type que VEAF ajoute. Dans ce cas, si les deux listes sont vides, le build vous avertit en clair : la mission démarrera sans aucun point de chargement issu de l'éditeur.

Une mission dont le ctld-config.yaml ne vient pas de mission prepare

Un fichier écrit à la main, repris d'une autre mission ou régénéré depuis les défauts de CTLD arrive avec ces deux listes vides. Le symptôme est déroutant parce qu'il est partiel : les FOB que vous créez en vol fonctionnent — elles passent par un autre chemin — et les FARP que vous avez posées dans l'éditeur, non. C'est exactement ce que ce réglage corrige.

Ce fichier est une configuration complète

CTLD 2 ne fusionne rien. Un réglage simple absent retombe sur la valeur par défaut du moteur (et il vous le dit au démarrage de la mission), mais une liste absente — une section de caisses, un groupe de troupes, une zone — est réellement supprimée. C'est ainsi qu'on retire un élément. Partez toujours du fichier existant plutôt que d'en écrire un de zéro.

Si vous montez CTLD de version et que votre fichier a été écrit pour la précédente, ctld-tools vous liste ce qui est apparu, ce qui a disparu et ce qui diffère du défaut avant que vous ne réenregistriez.

Les outils livrent leur propre CTLD : une nouvelle version des outils peut donc apporter un catalogue plus récent que celui de votre fichier, sans que vous ayez touché à CTLD. veaf-tools mission validate le signale (le message), et veaf-tools mission ctld-upgrade ajoute les réglages manquants à leur valeur par défaut, sans changer aucune des vôtres ni toucher à vos listes ; une liste que CTLD a ajoutée après la version de votre fichier, comme les caisses et chargements de la Fat Cow, est écrite aussi, puisque vous ne pouvez pas l'avoir retirée.

Les aérodromes deviennent des zones logistiques

Jusqu'ici, un avion de transport posé sur un aérodrome capturé lisait « Aucune logistique à portée » : CTLD 2 ne reconnaît comme points de chargement que les types d'unité déclarés dans logisticUnitTypes (les FARP et porte-avions de la section précédente) et les zones LGZ_ posées dans l'éditeur. Un aérodrome — un Airbase de la carte, pas une unité — n'est ni l'un ni l'autre. VEAF comble l'écart : au démarrage, il enregistre chaque aérodrome de la carte comme zone logistique CTLD, puis la tient à jour au fil de la partie.

La même zone est aussi une zone d'embarquement de troupes, au même endroit, du même rayon et pour le même camp : elle s'éteint et revient avec la zone logistique, et change de camp avec elle. Sans elle, sur Kolkhida, les troupes ne s'embarquaient que sur le porte-avions. Revers de la médaille, c'est le comportement de CTLD dans toute zone de troupes : débarquer des troupes dans ce cercle les renvoie à la base au lieu de les déployer. Pour les poser sur un aérodrome tenu, débarquez-les hors du cercle.

Une mission dont les coalitions ne comptent que CJTF Blue et CJTF Red

CTLD crée ses caisses sous le pays USA (bleu) ou Russie (rouge), quel que soit celui de l'hélicoptère. Quand ce pays n'appartient à aucune coalition de la mission — le cas des campagnes —, DCS refuse l'objet et la demande ne donne rien, sans message (mesuré en jeu le 2026-10-09). Le correctif est dans CTLD lui-même ; d'ici sa version, mettre USA dans la coalition bleue et la Russie dans la rouge de la mission devrait suffire (non vérifié en jeu).

C'est un réglage, pas une fatalité :

modules:
  CTLD:
    enabled: true
    manage_airbase_logistics: true   # défaut
    # airbase_logistics_radius: 250    # rayon de la zone, en mètres
    # airbase_occupation_radius: 2000  # rayon sondé pour l'occupation au sol, en mètres
    # airbase_logistics_tick: 30       # période de réévaluation, en secondes

Passez manage_airbase_logistics à false pour qu'aucun aérodrome ne soit enregistré : rien ne se déclare, aucun tick n'est planifié, aucun cercle n'est dessiné, et le journal dit que la fonctionnalité a été explicitement désactivée — pas qu'aucun aérodrome n'a été trouvé. Les trois nombres sont les vôtres, sans toucher au Lua ; leurs valeurs par défaut sont commentées ci-dessus.

Deux classes d'aérodrome. Un aérodrome détenu par une coalition dès la première évaluation (classe A) ouvre sa zone tout de suite et la garde tant que la coalition ne change pas. Un aérodrome neutre au départ, ou qui bascule d'une coalition à l'autre en cours de partie (classe B), n'ouvre sa logistique qu'après deux minutes d'occupation au sol continue et incontestée. La réévaluation court toutes les 30 secondes (le tick). Les deux minutes se mesurent à l'horloge de la mission, à partir du premier tick qui voit vos troupes sur place, quelle que soit la période choisie. Un tick qui ne trouve personne, ou trouve les deux camps, remet le chronomètre à zéro.

L'occupation se compte en unités au sol

La sonde d'occupation ne regarde que les unités terrestres dans un rayon de airbase_occupation_radius (2 000 m par défaut) autour de l'aérodrome. Un transport qui se pose sur un champ capturé ne l'ouvre pas : un avion au sol n'est pas une unité terrestre. Il faut des troupes ou des véhicules au sol, à vous, sans ennemi en face, pendant deux minutes.

Les transitions sont annoncées en jeu dans la langue de la mission (transport.airbase_logistics_gained / transport.airbase_logistics_lost), mais pas symétriquement. Quand un champ tenu est capturé, le camp qui le perd est prévenu sur-le-champ ; le preneur, lui, n'entend rien à cet instant — la zone reste éteinte pour lui jusqu'à ce que les deux minutes d'occupation au sol l'ouvrent réellement, et ce n'est qu'à ce moment qu'il reçoit le message « gagnée ». Annoncer « vous pouvez charger » à la capture serait un mensonge que l'activation suivante contredirait. Un cercle vert translucide est dessiné sur la carte F10 autour de chaque aérodrome dont la logistique est active, visible pour la coalition qui le tient.

L'écart accepté des 250 m

Il n'y a qu'une zone de airbase_logistics_radius (250 m par défaut) par aérodrome, centrée sur le parking le plus proche du centroïde du terrain. Sur un aérodrome très étalé, un avion garé à plus de 250 m de ce point lit « Aucune logistique à portée » alors même que le champ est actif. C'est un compromis assumé (2026-09-27) : le rayon est le réglage à monter si votre théâtre a de grands parkings dispersés.

Mesuré le 2026-10-03 à Ramstein : un C-130 garé par DCS lui-même s'est retrouvé à 997 m du centre de la zone, et un seul des 90 parkings gros porteurs du terrain est à moins de 250 m. Le rayon vaut pour tous les aérodromes de la mission, on ne peut pas le régler terrain par terrain : réglez-le sur le plus grand terrain d'où partent vos transports. Pour une grande base comme Ramstein, 1 100 m couvre la place du C-130 et les six parkings gros porteurs les plus proches. Un cercle plus grand ne coûte que sa taille sur la carte F10.

La langue de CTLD

CTLD parle la langue de votre mission : VEAF aligne sa langue sur mission.language au démarrage, donc une mission en français a un menu CTLD en français, sans rien avoir à régler.

Deux cas où ce n'est pas ce qui se passe :

  • vous avez mis un i18n_lang: dans votre ctld-config.yaml — votre réglage explicite gagne, c'est voulu ;
  • CTLD ne parle pas cette langue. Il fournit en, fr, es et ko ; pour toute autre, il reste dans sa langue par défaut et l'écrit une fois dans le journal, plutôt que d'afficher la clé de traduction à la place de chaque texte.

Ce qui a changé par rapport à CTLD v1

Avant Maintenant
modules: CTLD: { settings: … } ctld-config.yaml (le bloc settings: est refusé par validate)
unités nommées logistic #001 … #020 une zone de l'éditeur nommée LGZ_… (nombre illimité)
zones nommées pickzone #001 … #020 une zone de l'éditeur nommée TRZ_…
ctld.initialize(configurationCallback) dans mission-script.lua rien à écrire : le build génère le démarrage de CTLD

Missions construites avec veaf-tools 6.14.0 ou antérieur : reconstruisez-les

Ces versions n'écrivaient pas la ligne qui démarre CTLD. Dans le jeu, cela se voit ainsi : pas de menu CTLD dans le menu radio, et le premier -fob provoque une erreur de script (CTLD.lua: attempt to perform arithmetic on local 'interval') dans le journal DCS. Reconstruisez la mission avec une version à jour, ou, si vous ne pouvez pas reconstruire tout de suite, ajoutez cette ligne dans votre src/scripts/mission-script.lua :

if ctld then veaf.ctld_initialize() end

Pour attacher une zone logistique à un objet mobile (un porte-avions, par exemple), liez la zone à l'unité dans l'éditeur de mission (Moving Zone) : la zone suit son unité.

Couper l'élingage CTLD en cours de mission

Un game master peut activer ou désactiver l'élingage de CTLD sans éditer de fichier ni reconstruire la mission :

F10 → CTLD → Désactiver l'élingage CTLD (ou Activer, selon l'état courant)

L'entrée est protégée par mot de passe : elle change la façon de jouer de tous les équipages d'hélicoptère, pas seulement celle de qui appuie. Le menu n'affiche que la commande qui change quelque chose — inutile de proposer « activer » quand c'est déjà actif.

Le changement prend effet immédiatement et dans les deux sens : couper arrête les prises en vol stationnaire, réactiver les reprend. Rien à recharger.

Ce que ce réglage ne coupe pas : le treuil de DCS

Il ne gouverne que l'élingage géré par CTLD — la prise en vol stationnaire, le compte à rebours, la caisse perdue en survitesse. Le treuil du jeu lui-même continue de fonctionner : une caisse CTLD reste physiquement accrochable avec l'élingue de DCS, quel que soit ce réglage.

Le message affiché le dit, parce que c'est la première chose qu'un équipage constate après une coupure — et sans cette phrase, la commande passe pour cassée.

Le réglage sous-jacent est enableHoverSlingload, qui vit dans votre ctld-config.yaml comme tous les autres : le menu ne fait que le basculer à chaud. Pour démarrer la mission avec l'élingage déjà coupé, posez-le à false dans ce fichier.

Configurer CSAR via mission.yaml (YAML-first)

CSAR se configure de la même façon :

modules:
  CSAR:
    enabled: true
    settings:                # paires csar.xxx = valeur
      enableAllslots: true
      useprefix: true
      csarPrefix: ["helicargo", "MEDEVAC"]

VEAF génère les assignations csar.xxx = value et l'appel csar.initialize() dans veaf-config.lua.

Une valeur peut être un booléen, un nombre, du texte, ou une liste — une liste YAML devient une table Lua. Une valeur à clés (UH-1H: 8) n'a pas sa place ici : le build la refuse en nommant le réglage, et vous renvoie au callback Lua.

Les réglages disponibles

Les valeurs par défaut ci-dessous sont celles de CSAR.lua. Vous ne reprenez que celles que vous voulez changer.

Qui est secouru

Réglage Défaut Effet
csarOncrash true crée aussi un CSAR au crash, pas seulement à l'éjection
enableForAI true les équipages IA abattus sont secourables
enableForRED true CSAR actif côté rouge
enableForBLUE true CSAR actif côté bleu
countCSARCrash false le crash d'un appareil CSAR consomme aussi une vie
allowDownedPilotCAcontrol true le pilote au sol est pilotable en Combined Arms

Qui peut faire le sauvetage

Réglage Défaut Effet
enableAllslots false tous les hélicoptères peuvent secourir, sans condition de nom
useprefix true seuls les appareils dont le nom contient un préfixe de csarPrefix peuvent secourir
csarPrefix ["helicargo", "MEDEVAC"] la liste de ces préfixes
csarFixedUnits ["helicargo1", …] noms d'unités autorisées, en plus des préfixes
enableSlotBlocking true exige csarSlotBlockGameGUI.lua côté serveur
max_units 6 nombre de pilotes transportables à la fois

Vies et sanctions

Réglage Défaut Effet
csarMode 0 sanction d'une éjection — voir csarMode
maxLives 8 vies par pilote en mode 3
disableTimeoutTime 20 durée de l'indisponibilité, en minutes, pour les modes 1 et 2
disableAircraftTimeout true l'appareil redevient utilisable une fois ce délai passé
reenableIfCSARCrashes true un CSAR qui se crashe compte quand même comme réussi
destructionHeight 150 hauteur, en mètres, à laquelle un appareil interdit est détruit

Retrouver le survivant

Réglage Défaut Effet
coordtype 3 format des coordonnées annoncées : 0 DDM, 1 DMS, 2 MGRS, 3 bullseye impérial, 4 bullseye métrique
coordaccuracy 1 précision de ces coordonnées
autosmoke false fumigène automatique quand l'hélicoptère est à 5 km
bluesmokecolor 4 couleur du fumigène bleu : 0 vert, 1 rouge, 2 blanc, 3 orange, 4 bleu
redsmokecolor 1 idem côté rouge
radioSound "beacon.ogg" fichier son de la balise du pilote — il doit être présent dans la mission
requestdelay 2 délai, en secondes, avant que le survivant demande l'évacuation
messageTime 30 durée d'affichage du message initial, en secondes

La récupération

Réglage Défaut Effet
loadDistance 60 distance, en mètres, à laquelle le pilote peut embarquer
extractDistance 500 distance, en mètres, que le pilote parcourt à pied vers l'hélicoptère
pilotRuntoExtractPoint true le pilote court vers l'hélicoptère au lieu d'attendre
loadtimemax 135 durée maximale de l'embarquement, en secondes
weight 100 poids ajouté par pilote embarqué
allowFARPRescue true déposer le pilote sur une FARP ou un aérodrome compte comme un sauvetage
bluemash ["BlueMASH #1", …] unités servant d'hôpital côté bleu
redmash ["RedMASH #1", …] idem côté rouge

L'état du survivant

Réglage Défaut Effet
immortalcrew true le survivant ne peut pas être tué
invisiblecrew true le survivant est invisible pour l'IA
downedPilotCounterRed 0 compteur de départ des pilotes abattus, côté rouge
downedPilotCounterBlue 0 idem côté bleu

Le seul réglage que mission.yaml ne peut pas atteindre

aircraftType associe un nombre de places à chaque type d'appareil (csar.aircraftType["UH-1H"] = 8). C'est une valeur à clés, la seule de CSAR, et elle passe par le callback Lua.

Les quatre autres tables — csarPrefix, csarFixedUnits, bluemash et redmash — sont de simples listes et s'écrivent directement en YAML.

Un pilote abattu au-dessus de l'eau

Quand un appareil est descendu, CSAR fait apparaître le pilote survivant à récupérer. Sa position venait d'un décalage fixe de 50 m par rapport à l'appareil, sans que rien ne regarde ce qu'il y avait là : une éjection près d'un rivage mettait donc le survivant dans l'eau, injoignable (#245).

Depuis la 6.15.28, deux issues et rien entre les deux :

Où l'éjection a eu lieu Ce que la mission obtient
au sec, ou dans l'eau avec du sec à moins de 500 m un CSAR au point sec le plus proche
en pleine eau, rien de sec à moins de 500 m aucun CSAR — le pilote est perdu, et un message le dit à sa coalition

Le second cas n'est pas « un CSAR inaccessible » : c'est l'absence de CSAR. Pas de MAYDAY, pas de balise ADF, pas de groupe de blessé posé au fond de l'eau jusqu'à la fin de la mission. Un flight n'attend donc pas un sauvetage qui n'existe pas.

L'eau peu profonde ne compte pas comme la pleine mer : un survivant qui a pied à quelques mètres d'une plage reste récupérable là où il est.

CSAR.lua n'est pas modifié

Le script CSAR est un composant tiers embarqué : le corriger sur place serait effacé à sa prochaine mise à jour. VEAF remplace csar.addCsar depuis son propre code, comme il remplace déjà les journaux de CSAR.

Sanctionner une éjection : csarMode

CSAR peut faire payer une éjection, pour que se crasher ne soit pas gratuit. C'est un réglage settings: comme un autre :

modules:
  CSAR:
    enabled: true
    settings:
      csarMode: 3
      disableTimeoutTime: 30   # en minutes, pour les modes 1 et 2
csarMode Ce que le pilote perd
0 (défaut) rien
1 son appareil est indisponible pour tout le monde pendant disableTimeoutTime minutes
2 le même appareil lui est interdit à lui seul, les autres peuvent le prendre
3 il perd une de ses vies

Un cas où les modes 1 et 2 ne s'appliquent pas

Les modes 1 et 2 verrouillent un appareil précis, désigné par son identifiant DCS. Quand le pilote s'est éjecté et que son appareil a déjà disparu du monde, cet identifiant n'existe plus : la sanction est alors passée, et le journal DCS le dit (csarMode … the sanction is skipped).

Ce n'est pas un choix par défaut mais un refus délibéré : verrouiller un appareil au hasard priverait de son avion un pilote qui n'a rien fait. Le mode 3 n'a pas ce problème — il ne dépend que du nom du joueur — et s'applique toujours.

Ordre de chargement dans la chaîne de triggers DCS

Le build produit cette chaîne pour vous ; elle est décrite ici pour que vous puissiez la relire dans l'éditeur de mission :

DO SCRIPT FILE → CTLD_userConfig.lua (généré depuis votre ctld-config.yaml)
DO SCRIPT FILE → CTLD.lua            (tiers)
DO SCRIPT FILE → csar.lua            (tiers)
DO SCRIPT FILE → veaf-scripts.lua    (modules VEAF)
DO SCRIPT FILE → veaf-config.lua     (généré depuis mission.yaml)
DO SCRIPT FILE → mission-script.lua  (votre code personnalisé)

L'ordre des deux premières lignes compte : CTLD lit sa configuration au chargement. Ce même fichier lui demande d'attendre le framework VEAF plutôt que de démarrer tout seul, ce qui permet à VEAF de router ses messages dans les logs VEAF — y compris son rapport de démarrage, qui signale une configuration incomplète ou périmée.

CSAR, lui, garde l'ancien mécanisme : veaf-scripts.lua détecte la table globale csar et enveloppe sa fonction initialize().

Fallback Lua — CSAR dans mission-script.lua

Pour les surcharges par type d'appareil ou d'autres paramètres complexes non supportés par YAML :

if csar then
    local initializeCSAR = true
    if initializeCSAR then
        veaf.loggers.get(veaf.Id):info("initialize CSAR")
        local function configurationCallback()
            -- Configurer les paramètres CSAR avant son initialisation
            csar.enableAllslots = true
            csar.aircraftType["UH-1H"]  = 8
            csar.aircraftType["Mi-8MT"] = 16
            csar.useprefix  = true
            csar.csarPrefix = { "MEDEVAC" }
        end
        csar.initialize(configurationCallback)
    else
        csar.alreadyInitialized = true
    end
end

Valeurs par défaut automatiques VEAF

Quand VEAF enveloppe les initialiseurs, il applique ses propres valeurs par défaut : journalisation et une entrée de menu radio standard. Vous n'avez pas besoin de configurer cela manuellement.


DCS Bridge

VEAF-dcs-bridge est un module Lua optionnel qui ouvre un socket TCP entre DCS World et un serveur externe, permettant de piloter la mission depuis l'extérieur (bots Discord, dashboards, outils d'automatisation).

Activer l'injection de dcs-bridge.lua

Ajoutez la section suivante dans votre mission.yaml :

dcs_bridge:
  enabled: true

Lors du build, veaf-tools télécharge automatiquement dcs-bridge.lua depuis GitHub et l'injecte comme premier trigger DO SCRIPT FILE de la mission (avant les scripts VEAF).

Utiliser un fichier local

Si vous avez un clone local de VEAF-dcs-bridge, pointez directement vers le fichier :

dcs_bridge:
  enabled: true
  lua_path: /chemin/vers/VEAF-dcs-bridge/src/lua/dcs-bridge.lua

Le chemin peut être absolu ou relatif au dossier de la mission.

Ordre de chargement

Lorsque dcs_bridge est activé, le trigger est inséré en position 1, avant tous les autres triggers VEAF. dcs-bridge est donc disponible dès le démarrage de la mission, avant le chargement de veaf-scripts.lua.


Journalisation de débogage

Tous les scripts VEAF écrivent dans le journal DCS (Saved Games\DCS\Logs\dcs.log). Le build produit désormais un unique chargeur veaf-scripts.lua ; la verbosité se contrôle via les niveaux de log dans mission.yaml, et non en chargeant un script différent.

Changer le niveau de log

Définissez un défaut global avec global_log_level, ou surchargez-le par module avec logLevel, puis reconstruisez :

global_log_level: info   # trace | debug | info | warning | error

modules:
  SPAWN:
    logLevel: debug   # surcharge le défaut global pour ce module uniquement

.\veaf-tools.exe mission build régénère veaf-config.lua depuis mission.yaml. N'éditez pas veaf-config.lua directement : il est généré, donc toute modification disparaît au prochain build. Pour essayer un réglage sans reconstruire, éditez-le en sachant que le changement est jetable — puis reportez-le dans mission.yaml pour qu'il survive.

Lire le journal

Nous recommandons Klogg — un visualiseur de logs rapide avec surligneur regex. Chargez dcs.log et filtrez sur VEAF pour ne voir que les messages VEAF.

Un profil de surligneur Klogg prêt à l'emploi est inclus dans le dépôt : tools/klogg/veaf.conf. Il code les niveaux de log par couleur (erreurs en rouge, avertissements en orange, info VEAF en vert, debug en bleu-vert, trace en gris) et met en évidence les entrées MIST et CTLD. Pour l'installer : Klogg → Fichier > Importer les surligneurs… et sélectionnez le fichier.

Signaler ce que vous y trouvez

Si le journal montre une erreur que vous ne vous expliquez pas, Obtenir de l'aide dit où la signaler et quoi joindre — extrait du dcs.log, et le bloc de .\veaf-tools.exe doctor qui porte les versions.


Ressources