Using the “modify”-Preset
MizEdit’s modify DSL (Domain Specific Language) lets you search and modify Lua tables inside DCS .miz files.
A .miz file is a ZIP archive containing three Lua table files:
| File | Contents |
|---|---|
mission | Units, routes, weather, triggers, coalition data — the main mission |
options | Mission options (overrides the player’s options.lua) |
warehouses | Airport warehouse data and dynamic spawn configuration |
MizEdit unpacks the .miz, amends these Lua tables, and repacks into a new .miz file.
DSL Overview
Every modify block follows this structure:
# config/presets.yaml
PresetName:
modify:
file: mission # which Lua file to modify: mission | options | warehouses
variables: ... # optional: extract or define variables
if: ... # optional: condition that must be true
for-each: <path> # required: path to elements to iterate
where: ... # optional: filter on the reference element
select: <path> # optional: navigate deeper to the element to change
replace: ... # modify existing values
delete: ... # remove elements
insert: ... # add new keys/values
merge: ... # merge two Lua tables
run: <python.func> # call a Python function for complex logic
debug: true # optional: verbose logging
Path Navigation
Paths navigate the Lua table tree from root to leaf:
| Syntax | Meaning |
|---|---|
/node | Descend into a named key |
* | Iterate all elements in a list or table |
[x] | Select the n-th element from a Lua list (1-based) or a specific key from a table |
[x,y] | Select multiple elements |
$'...' | Evaluate the content as a Python expression (returns a boolean for filtering, or a value for replacement) |
'{var}' | Substitute a previously defined variable’s value |
Important on indexing: Lua lists are 1-based, so [1] is the first element. However, when accessing data via Python expressions (inside $'...' or reference), use Python 0-based indexing: reference[units][0].
Finding Elements
for-each — sets the iteration and the reference element
for-each defines which elements to iterate over. The matched element becomes the reference element — the context you work with.
for-each: coalition/blue/country/*/ship/group/*/units/$'{type}' in ['CVN_71','CVN_72','CVN_73','CVN_74','CVN_75']
This walks the mission tree and selects every individual carrier unit matching the type list. The reference element is each unit.
where — filters without changing the reference
where filters which reference elements to process, but does NOT change what the reference points to.
for-each: coalition/blue/country/*/ship/group/*
where: units/$'{type}' in ['CVN_71','CVN_72','CVN_73','CVN_74','CVN_75']
This iterates all groups, but only processes groups containing a matching carrier. The reference element is each group (not the unit). This matters when you need to modify group-level data like routes.
Rule: Use for-each alone when you want to modify the iterated elements directly. Add where when you need to filter by a child property but work on the parent.
select — navigates deeper to the target
select navigates from the reference element to the specific sub-element to modify. The reference stays the same.
for-each: coalition/blue/country/*/ship/group/*
where: units/$'{type}' in ['CVN_71','CVN_72','CVN_73','CN_74','CVN_75']
select: route/points/*/task/params/tasks/$'{id}' == 'WrappedAction'/params/action/$'{id}' == 'ActivateBeacon'/params
This finds blue carrier groups, then drills into their route tasks to find TACAN beacon parameters.
Modification Operations
replace — overwrite values
Simple replacement:
replace:
frequency: 371000000
modeChannel: X
Conditional replacement (switch/case): When a replace value is a mapping, each key is a Python expression. The first expression that evaluates to True determines the value:
replace:
frequency:
$'{reference[units][0][type]}'[-2:] == '72': 1158000000
$'{reference[units][0][type]}'[-2:] == '73': 1160000000
delete — remove elements
delete: $'{type}' == 'FA-18C_hornet'
insert — add new keys/values
Use insert when the target key doesn’t exist yet:
insert:
Radio:
- channels:
- 243
merge — combine Lua tables
Merges two parts of a mission file together, e.g., merging neutral country data into blue:
merge:
source: coalition/neutral
target: coalition/blue
Built-in Variables
The following variables are available in all modify blocks:
| Variable | Description |
|---|---|
{reference} | The current reference element (set by for-each). Access properties like {reference[units][0][type]}. Uses Python 0-based indexing. |
{type} | The type name of the current element (when iterating units) |
Custom Variables
Extract values from the mission or define your own:
variables:
theatre: theatre # extract from mission
temperature: weather/season/temperature # extract nested value
speed: 40 # fixed value
rand: '$random.randint(1, 10)' # Python random
mylist: '$list(range(1, {rand}))' # use other variables
Reference variables with {variablename} in paths and expressions.
Conditions
Run the modification only when a condition is met:
variables:
start_time: start_time
theatre: theatre
if: ${start_time} > 20000 and '{theatre}' == 'Caucasus'
Python Functions
For complex logic, call a Python function:
variables:
wind: weather/wind/atGround
for-each: coalition/*/country/*/ship/group/*
where: units/$'{type}' in ['CVN_71','CVN_72','CVN_73','CVN_74','CVN_75', "Stennis", "LHA_Tarawa"]
run: core.utils.mizedit.relocate_carrier
The function receives three arguments:
| Parameter | Description |
|---|---|
data | The selected element |
reference | The reference element |
kwargs | All defined variables |
def my_function(data: dict, reference: dict, **kwargs) -> dict:
# modify data in place or return a replacement dict
return data
See the DCSServerBot source for available built-in functions.
Debugging
Set debug: true to enable verbose logging. The log shows which elements were matched and what changes were made. Check the DCSServerBot log file for output.
Examples
Example 1: Change carrier frequencies (simple replacement)
Select every blue carrier unit and set its frequency based on type:
# config/presets.yaml
SetCarrierFreqs:
modify:
file: mission
for-each: coalition/blue/country/*/ship/group/*/units/$'{type}' in ['CVN_71','CVN_72','CVN_73','CVN_74','CVN_75']
replace:
frequency:
"$'{type}' == 'CVN_71'": 371000000
"$'{type}' == 'CVN_72'": 372000000
"$'{type}' == 'CVN_73'": 373000000
"$'{type}' == 'CVN_74'": 374000000
"$'{type}' == 'CVN_75'": 375000000
Shorter version using a Python calculation:
# config/presets.yaml
SetCarrierFreqs:
modify:
file: mission
for-each: coalition/blue/country/*/ship/group/*/units/$'{type}' in ['CVN_71','CVN_72','CVN_73','CVN_74','CVN_75']
replace:
frequency: $int('3' + '{type}'[-2:] + '000000')
Example 2: Change TACAN frequencies (deep navigation with where + select)
TACAN data is nested inside the group’s route, not on the unit itself. We use for-each to iterate groups, where to filter for carrier groups, and select to reach the beacon parameters:
# config/presets.yaml
SetTACAN:
modify:
file: mission
for-each: coalition/blue/country/*/ship/group/*
where: units/$'{type}' in ['CVN_71','CVN_72','CVN_73','CVN_74','CVN_75']
select: route/points/*/task/params/tasks/$'{id}' == 'WrappedAction'/params/action/$'{id}' == 'ActivateBeacon'/params
replace:
modeChannel: X
channel: $'{reference[units][0][type]}'[-2:]
frequency:
$'{reference[units][0][type]}'[-2:] == '72': 1158000000
$'{reference[units][0][type]}'[-2:] == '73': 1160000000
Here {reference} points to the group (from for-each), so {reference[units][0][type]} gets the first unit’s type name. The [-2:] slice extracts the carrier number (e.g. “72” from “CVN_72”).
Example 3: Set radio presets (with insert)
Set the first radio channel of all blue F-14Bs. Uses insert to add the Radio key if it doesn’t exist:
# config/presets.yaml
ChangeRadios:
modify:
file: mission
for-each: coalition/blue/country/*/plane/group/*/units/$'{type}' in ['F-14B']
select: Radio/[1]/channels
replace:
1: 243
insert:
Radio:
- channels:
- 243
Example 4: Delete all Hornets (with delete)
# config/presets.yaml
DeleteAllHornets:
modify:
file: mission
for-each: coalition/[blue,red]/country/*/plane/group/*/units
delete: $'{type}' == 'FA-18C_hornet'
Example 5: Enable dynamic cargo on blue warehouses (different target file)
# config/presets.yaml
EnableDynamicCargo:
modify:
file: warehouses
debug: true
for-each: airports/*/$'{coalition}' == 'BLUE'
replace:
dynamicCargo: true
Example 6: Search path walkthrough
The path coalition/[blue,red]/country/*/ship/group/*/units/$'{type}' in ['CVN_71'..'CVN_75'] walks the tree:
|_ coalition
|_ blue
|_ country
|_ ... all countries ...
|_ ship
|_ group
|_ ... all groups ...
|_ units
|_ elements where ["type"] is one of ['CVN_71'..'CVN_75']
|_ red
|_ ... same structure ...