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¶
- Ce que vous obtenez
- Prérequis
- Installation et mises à jour
- Configuration globale utilisateur
- Créer une nouvelle mission
- Comment les scripts sont chargés
- Configurer les modules
- Configurer le pipeline de build
- Outils de conception
- Workflow de build typique
- Profils de build
- Référence des scripts
- Exemples de configuration
- Intégration CTLD et CSAR
- DCS Bridge
- Journalisation de débogage
- 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
.exeté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¶
- Créez un dossier pour votre projet de mission (c'est votre dépôt Git)
- Copiez votre fichier
.mizexistant dedans - Exécutez
.\veaf-tools-updater.exepour récupérer tous les scripts VEAF - Extrayez votre mission :
.\veaf-tools.exe mission extract ma-mission.miz - Configurez les modules dans
mission.yamlet éventuellementsrc/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'extractionmission/) provient du gabaritdefaults/mission-folder/de l'outil et est consommé dès le premier build — les*.yamlpar leur étape de pipeline/module,optionspar injection dans le.miz, et lesscripts/*.luapar 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¶
- Lit
src/mission/(les données DCS extraites) - Supprime tous les triggers VEAF existants
- Injecte de nouveaux triggers
DO SCRIPT FILEpour tous les scripts VEAF + vos scripts personnalisés - Écrit le
.mizfinal
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.yamletdynamic-slot-templates.yamlsont 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-templateCela réécrit
src/dynamic-slot-templates.yamlavec vos modèles. Le prochain build les injecte, et les slots dynamiques proposent des appareils prêts à décoller.Ajoutez
--mergepour 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'assetssrc/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 depuismission.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éslua_modules:+community_scripts:, etenabled:remplaceenable:. 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.yamlcontient déjà une ligneMIST: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 --helpliste les groupes, etveaf-tools <groupe> --helpleur contenu. Le groupedcsregroupe ce qui exige DCS lancé. Les groupes sont :mission,convert,content,campaign,cockpitetdcs. Une commande dont le nom commence par celui de son groupe le perd à l'intérieur : on écritveaf-tools convert v5etveaf-tools convert other, pasconvert convert-v5.Les anciens noms courts fonctionnent toujours :
veaf-tools buildfait exactement la même chose queveaf-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.--tuiajouté à 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.exeté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 votrectld-config.yaml— votre réglage explicite gagne, c'est voulu ; - CTLD ne parle pas cette langue. Il fournit
en,fr,esetko; 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¶
- Référence des scripts — tous les scripts avec les détails de configuration
- Référence CLI — les 37 commandes de
veaf-tools, arguments et options - Référence API Lua — documentation complète de l'API Lua
- Mission de démo v6 — chaque fonctionnalité en jeu, avec une visite guidée (voir plus haut)
- Discord VEAF — aide communautaire