Optional, pluggable scenes for CTLD (Combined Transport and Logistics Dispatcher for DCS World).
A scene is a pre-defined multi-step build (a FARP, a minefield…). Most scenes ship built into
CTLD.lua. This repository hosts scenes that are kept out of the core deliverable — typically
because they depend on a DCS mod — so a mission only pays for them if it opts in.
A plugin scene is a single loadable .lua file. Load it from a mission-start trigger, after
CTLD, and it self-registers. One plugin = one scene.
- Download the plugin's
.luafrom the catalogue (or a release). - In the DCS Mission Editor, add a
DO SCRIPT FILE(orDO SCRIPT) trigger at MISSION START, after the trigger that loadsCTLD.lua. - If the plugin requires a DCS mod, ensure every client has that mod installed (the plugin's page lists it). The plugin warns in-game if your CTLD is older than it requires.
plugins/<plugin>/
src/ the scene source (+ optional Lua deps; built into dist/<plugin>.lua)
tests/ plugin-specific tests (optional)
docs/ authored notes (optional)
tests/
helpers/init.lua DCS stubs + vendored CTLD runtime (busted helper)
helpers/dcs_stubs.lua copied from CTLD
data/dcs_types.lua vendored datamine stock-type set (design-time asset gate)
scene_asset_gate_spec.lua strict gate: every spawned type is stock or declared modTypes
vendor/CTLD.lua pinned CTLD build used as the test runtime (= requiresCtld baseline)
tools/build/merge_plugin.ps1 builds plugins/<plugin>/src → dist/<plugin>.lua (UTF-8, no BOM)
docs/ mkdocs bilingual (EN + FR) catalogue
- Build:
powershell -ExecutionPolicy Bypass -File tools/build/merge_plugin.ps1 -All(or-Plugin <name>) →dist/<name>.lua. - Test:
busted tests/— the design-time asset hard-gate loads the vendored CTLD runtime, loads each plugin scene, and fails if it spawns a DCS type that is neither a known stock type (tests/data/dcs_types.lua) nor declared in the scene'smodTypes. - Declare a mod: set
model.modTypes = { "Your_Mod_Type" }(machine-readable, keeps the gate strict on every other type) andmodel.requiresMod = "<human label>"(docs). - Declare compatibility: set
model.requiresCtld = "X.Y.Z"; CTLD warns at load if older.
The vendored vendor/CTLD.lua and tests/data/dcs_types.lua are pinned to a CTLD baseline; refresh
them together when bumping the supported CTLD version.
- Document a plugin: create
plugins/<name>/README.md(useplugins/_template/README.mdas model), then run thegenerate-plugin-docskill in Claude to producedocs/plugins/<name>.mdanddocs/plugins/<name>.fr.md. Finally add the plugin row todocs/index.mdanddocs/index.fr.md.
The validate-docs job runs tools/ci/validate_docs.py on every push and PR. It:
- Warns (exit 0) when a plugin has no
README.md(docs will have no prose, but the build is not blocked). - Errors (exit 1) when:
README.mdis present but its YAML front-matter is absent or malformed.modUrlsexists but is not a list of{mod, url}pairs.docs/plugins/<name>.mdordocs/plugins/<name>.fr.mdis absent.
Run it locally before pushing: python tools/ci/validate_docs.py (requires pyyaml).
| Version | URL |
|---|---|
Production (latest, from master) |
https://veaf.github.io/CTLD_plugins/latest/ |
Recette (dev, from develop) |
https://veaf.github.io/CTLD_plugins/dev/ |
Racine (redirects to latest) |
https://veaf.github.io/CTLD_plugins/ |