convert-other — adopt a third-party mission onto v6¶
convert-other adopts a third-party .miz mission (non-VEAF, e.g. Foothold
by Lekaa) onto the v6 toolchain. It is the counterpart of
convert-v5, which migrates a VEAF v5 mission: here
the mission was never built with the VEAF tools, so we adopt it.
This command holds no knowledge specific to any given mission. The author-specific knowledge for a mission family (script order, triggers to strip, settings to override…) is carried by a conversion profile. Two ship with the tool:
footholdandfoothold-ww2. See ADR 0007.
Usage¶
veaf-tools convert other <mission.miz> <output-folder>
With no argument (in an interactive terminal) the command opens the TUI wizard
and asks for the source .miz then the output folder.
The input can be a release archive¶
Third-party missions are often distributed as a release .zip rather than a bare
.miz — Lekaa's Foothold assets bundle the mission with a config-manager executable, the
manual and a shortcut. Pass the archive you downloaded and convert-other adopts the .miz
inside it:
veaf-tools convert other Foothold_CA_4.4.1_Multi_Language_Coldwar-Modern-Vietnam.zip <output-folder> --profile foothold
Only the .miz member is read; nothing else in the archive is written anywhere (the bundled
executable is never extracted, and never run). The archive must contain exactly one
.miz: with none, or with several, the command stops and names what it found rather than
guessing which mission you meant.
| Argument / option | Purpose |
|---|---|
INPUT_MIZ |
Path to the third-party mission to adopt: a .miz, or a release .zip containing exactly one |
OUTPUT_FOLDER |
v6 mission folder to create / populate |
--force |
Overwrite an existing mission.yaml (otherwise left untouched) |
--report-file |
Markdown report path (default <output>/convert-other-report.md) |
--profile |
Conversion profile (bundled name, e.g. foothold, or a path to a .yaml) |
Conversion profiles¶
Without --profile the scaffold is generic (the minimal tier). With a profile,
mission-family-specific knowledge is applied — data, not code (see
ADR 0007). The bundled
foothold profile:
- enables the VEAF modules Foothold uses (RADIO, SPAWN, WEATHER, SHORTCUTS,
SECURITY, REMOTE) instead of the
minimaltier; - normalises versioned names (
Moose_2026-06-14.lua→Moose.lua,Splash_Damage_3.4.1_leka.lua→Splash_Damage.lua) socustom_scripts:paths stay stable across Lekaa versions. The per-map setup script (MA_Setup_CA.lua,footholdSyriaSetup.lua,kola_setup.lua…) is not normalised: those names vary per map, not per version; - writes a marker
conversion_profile: footholdintomission.yaml; - scaffolds a commented
config_overridetargetingFoothold Config.lua; - declares incompatible modules (
CTLD: Foothold ships its own). Enabling an incompatible module makesveaf-tools mission validateand the build fail — including if you enable it by hand later.
veaf-tools convert other <mission.miz> <output-folder> --profile foothold
Bundled profiles¶
| Profile | For |
|---|---|
foothold |
Lekaa's Foothold on Caucasus, Persian Gulf, Sinai, Syria, Cold War Germany, Kola, Iraq, Afghanistan |
foothold-ww2 |
WWII Normandy Foothold — a different config file (Foothold Config WW2.lua), no Era, and no Foothold CTLD, so the VEAF CTLD is not incompatible there |
See FOOTHOLD for the full per-version procedure.
What it does¶
- Extracts the
.mizinto the mission folder (scripts land insrc/scripts/). The third-party copies of known community scripts (CTLD, CSAR, AIEN…) are kept as-is (iso-functional) rather than replaced by the VEAF versions. - Detects the scripts loaded by the mission's native triggers, in their load order (trigger order × action order).
- Generates a scaffold
mission.yaml: - an ordered
custom_scripts:block (the original load order); - a
strip_native_triggers:list of the detected native loader triggers (by comment or glob pattern) — the build strips them (trigrule +trigentries +mapResourceresources) so they do not double-load alongside the re-injectedcustom_scripts; - a
modules:block seeded with theminimaltier (infra + RADIO/SPAWN/SHORTCUTS/INTERPRETER/SECURITY): a working VEAF baseline out of the box; enable more as needed. - Emits a Markdown report summarising the actions and review items.
Partial config override¶
A third-party mission like Foothold ships a large, author-controlled config file
that VEAF leaves untouched. To change a handful of settings at deploy time
(difficulty, start side, auto-restart…) without rewriting that file, fill the
config_override: block the scaffold leaves commented:
config_override:
target: "Foothold Config.lua" # the upstream config script you layer on top of
values:
CapDifficulty: medium # global = value
StartNormal: true
AutoRestart: false
Some.Nested.Global: 42 # dotted path → Some.Nested.Global = 42
At build, this renders a small veaf-config-override.lua that restates only the
globals you changed, loaded between the untouched upstream config and the
setup script (so the upstream config drops in unchanged on a new Lekaa version,
and your overrides win). Values are passed through as-is — VEAF never interprets
them; the mission validates its own values at runtime.
Each override key is validated lexically: every dotted segment must appear as
an identifier somewhere in the injected scripts (src/scripts/*.lua). A segment
found nowhere — a typo or a global the upstream renamed/removed — fails
veaf-tools mission validate and the build, so silent upstream drift becomes a
build-time alert. (No Lua is executed: the check is a pure-Python whole-word
search.)
After conversion¶
- Review
mission.yaml: enable the VEAF modules you want, check thecustom_scriptsorder and dependencies. - Build and test the mission in DCS to confirm iso-functional behaviour.
Updating to a newer upstream .miz (--update)¶
When the third-party author ships a new version (e.g. a Lekaa Foothold bump),
re-import it into your already-adopted folder with --update:
veaf-tools convert other <new-upstream.miz> <output-folder> --profile foothold --update
The new upstream can be the release .zip here too — same rule, exactly one .miz inside.
In update mode convert-other:
- refreshes the third-party scripts (
src/scripts/*.lua) and the mission base (src/mission/**) from the fresh.miz— overwriting the previous copies instead of keeping the old ones (a first-time adoption keeps existing files;--updateis the explicit "take the new version" switch); - re-applies versioned-name normalisation so
custom_scripts:paths stay stable across versions (e.g.Moose_<new-date>.lua→Moose.lua); - preserves your tuned
mission.yaml— it is never regenerated, so your modules,config_override, and your owncustom_scriptssurvive; - deletes the scripts the new release no longer ships, provided they came from upstream in the first place (see below);
- rewrites the
custom_scripts:list to what the upstream release loads, in its load order: a script it no longer loads leaves, a script it loads for the first time enters with its delay. Your own scripts stay, after the upstream ones and in their order. That is what covers an upstream rename (zoneCommander.lua→zoneCommanderv2.luain 5.3.0): without it, the build loaded the previous engine against the new config; - reconciles
delay_seconds:with the upstream staging — see Load staging; - reports everything it did: scripts added, updated, deleted, and every delay written.
Review the report, check where your own scripts sit in custom_scripts:, then rebuild and test in DCS.
What is yours and what is upstream's¶
A script the new release no longer ships is not necessarily stale: it may be one you
wrote and declared in custom_scripts:. From the folder, the two look identical.
So the conversion writes convert-other-state.yaml in the mission folder: the list of
scripts the upstream release loads. Commit it with the mission. On the next update, a
script missing from the new release and present in that list is an upstream script that
was dropped (deleted); anything else is yours (left strictly alone).
A folder converted before that file existed has no such list.
There, the previous release's scripts are read from the mission base it left: the mapResource of src/mission/ names every script that release embedded.
Load staging¶
Third-party missions often stagger their script loading (Foothold loads AIEN 12 s after
the others). That staging is upstream's decision rather than yours, so --update writes
the upstream delay_seconds: into your mission.yaml, and the report names every line it
wrote.
Only those lines change — comments, ordering, quoting and line endings elsewhere in the file are left exactly as they were. A script upstream knows nothing about keeps whatever delay you gave it.
If you deliberately wanted a delay other than upstream's, it will be rewritten on the next update. The report will tell you.