Doctrine
Doctrine controls how your IADS behaves tactically: engagement rules, EMCON policies, HARM response, and more.
All fields are optional. Omit any field to use its default.
How doctrine resolves
Section titled “How doctrine resolves”Doctrine resolves in three layers:
- Code defaults. Every doctrine field has a built-in default (e.g.
ROE = "TIGHT",HoldDownSec = 15). Medusa_MM_Doctrine. If this global table exists, its fields override the code defaults. This is your base doctrine for all networks.- Per-network doctrine. If a network specifies its own doctrine table (via
MEDUSA_CONFIG), those fields merge on top ofMedusa_MM_Doctrine. Fields you set in the per-network table override. Fields you don’t set inherit fromMedusa_MM_Doctrine. Nested tables likeEMCONandMaxEngageRangePctalso merge per-key, so you only need to specify the roles you want to change.
Single network. Set Medusa_MM_Doctrine before loading Medusa. Any field you omit uses the code default:
Medusa_MM_Doctrine = { ROE = "TIGHT", HARMResponse = "AUTO_DEFENSE", -- everything else uses code defaults}Multi-network. Each network can have its own doctrine. The doctrine field accepts either an inline table or a string naming a global variable. Networks without a doctrine key fall back to Medusa_MM_Doctrine. See Multi-Network Setup for the full pattern:
-- Base doctrine for all networks.-- Any field set here overrides code defaults.Medusa_MM_Doctrine = { ROE = "TIGHT", HARMResponse = "AUTO_DEFENSE", EMCON = { EWR = "ALWAYS_ON", LR_SAM = "MINIMIZE", MR_SAM = "PERIODIC_SCAN" }, PkFloor = 0.15,}
MEDUSA_CONFIG = { Networks = { { name = "PVO", coalition = "red", prefix = "pvo", doctrine = { ROE = "FREE", -- overrides MM_Doctrine's "TIGHT" EMCON = { LR_SAM = "PERIODIC_SCAN" }, -- overrides LR_SAM, keeps EWR and MR_SAM from MM_Doctrine }, -- Result: ROE="FREE", HARMResponse="AUTO_DEFENSE" (inherited), -- EMCON={EWR="ALWAYS_ON", LR_SAM="PERIODIC_SCAN", MR_SAM="PERIODIC_SCAN"}, -- PkFloor=0.15 (inherited) }, { name = "MILITIA", coalition = "red", prefix = "militia", -- No doctrine field. Uses MM_Doctrine as-is. -- Result: ROE="TIGHT", HARMResponse="AUTO_DEFENSE", -- EMCON={EWR="ALWAYS_ON", LR_SAM="MINIMIZE", MR_SAM="PERIODIC_SCAN"}, -- PkFloor=0.15 }, { name = "BLUE", coalition = "blue", prefix = "blue", doctrine = { ROE = "FREE", HARMResponse = "IGNORE", PkFloor = 0.05, }, -- Result: ROE="FREE", HARMResponse="IGNORE", PkFloor=0.05, -- EMCON={EWR="ALWAYS_ON", LR_SAM="MINIMIZE", MR_SAM="PERIODIC_SCAN"} (all inherited) }, },}Rules of Engagement
Section titled “Rules of Engagement”ROE = "TIGHT",| Value | Behavior |
|---|---|
"FREE" | Batteries engage any BANDIT/HOSTILE in range without restriction |
"TIGHT" | Batteries engage only HOSTILE tracks (requires dwell-time promotion) |
"HOLD" | No target assignments are made. Sensors still detect, tracks still update, EMCON and HARM response still run. Batteries just never get assigned a target to shoot at. This exists for future C2 and centralized firing authority features |
Target Assignment
Section titled “Target Assignment”For a detailed explanation of how target assignment works, see the Target Assignment guide.
HoldDownSec = 15, -- Seconds HOT after target goes stale (default: 15)EngageTimeoutSec = 45, -- Max seconds in ENGAGING before timeout (default: 45)MaxTargets = 1, -- Concurrent targets per battery (default: 1)StickyRangePct = 15, -- How far Pk must drop below PkFloor before releasing a target (default: 15)
MaxEngageRangePct = { -- Hard cap on engagement range as % of hardware max LR_SAM = 80, MR_SAM = 90, SR_SAM = 100,},Engagement Tactics
Section titled “Engagement Tactics”EngageTactics controls how many batteries can engage the same track at once. The default is SHOOT_IN_DEPTH.
EngageTactics = "SHOOT_SHOOT_FLOOD",SHOOT_LOOK_SHOOT
Section titled “SHOOT_LOOK_SHOOT”One battery per track. The battery fires, and Medusa waits to see the result before assigning another battery. This is the most conservative mode. You see one battery go HOT at a time per inbound aircraft. Good for preserving ammo when threats are sparse. VLR_SAMs follow this same pattern and do not add a second engagement.
Real-world parallel: standard NATO Hawk and Patriot fire doctrine. Fire one interceptor, assess via radar, fire again if the first misses.
SHOOT_IN_DEPTH
Section titled “SHOOT_IN_DEPTH”One battery per role tier per track. A track can have one VLR_SAM, one LR_SAM, one MR_SAM, and one SR_SAM or AAA assigned simultaneously. A second SA-2 will not engage if an SA-2 is already on the track, but an SA-3 can join because it fills a different role tier. This is the default. You see layered defenses activate as the target flies deeper into the IADS.
Real-world parallel: Soviet/Russian layered air defense. An S-300 brigade has long-range battalions engaging at distance while Tor and Pantsir batteries screen the close-in zone. Each layer operates independently against the same threat.
SHOOT_SHOOT
Section titled “SHOOT_SHOOT”Up to 2 batteries per track, regardless of role. The two highest-Pk batteries both activate. A track could get two SA-2s, an SA-2 and an SA-10, or any combination. VLR_SAMs still follow SHOOT_LOOK_SHOOT among themselves (only one VLR_SAM per track), but a VLR_SAM plus two other batteries can all be active on the same track. You see pairs of batteries light up together for each threat.
Real-world parallel: common doctrine for high-value targets or saturated threat axes. Two interceptors from different angles increase the probability of at least one hit.
SHOOT_SHOOT_FLOOD
Section titled “SHOOT_SHOOT_FLOOD”Up to 2 LR_SAM or MR_SAM batteries per track (counted separately from short-range systems). Every SR_SAM and AAA battery whose engagement zone touches the track activates without limit. VLR_SAMs occupy their own tier and follow SHOOT_LOOK_SHOOT (one VLR_SAM per track), independent of the LR/MR count. You see short-range systems flooding on across the track’s flight path while long-range systems provide layered coverage behind them. This is the most aggressive mode. Best suited for high-threat scenarios where volume of fire matters more than ammo conservation.
Real-world parallel: dense Syrian and Iraqi IADS deployments. Every system in range fires at anything that enters the engagement zone. Quantity of fire over ammunition conservation.
Emission Control (EMCON)
Section titled “Emission Control (EMCON)”Per-role EMCON policies control when radars emit:
EMCON = { EWR = "PERIODIC_SCAN", GCI = "PERIODIC_SCAN", VLR_SAM = "MINIMIZE", LR_SAM = "PERIODIC_SCAN", MR_SAM = "ALWAYS_ON", SR_SAM = "MINIMIZE", AAA = "MINIMIZE",},ScanSec = 20, -- Seconds radar is ON per cycle (used by both -- PERIODIC_SCAN and COORDINATED_ROTATION)QuietPeriodSec = 40, -- Seconds radar is OFF per cycle (used by both -- PERIODIC_SCAN and COORDINATED_ROTATION)EmconRotateGroups = 3, -- Number of sensor groups for COORDINATED_ROTATION| Policy | Behavior |
|---|---|
"MINIMIZE" | Units stay cold until cued |
"PERIODIC_SCAN" | Cycle between warm and cold on a timer |
"COORDINATED_ROTATION" | Like PERIODIC_SCAN, but sensors are divided into groups that take turns radiating (see below) |
"ALWAYS_ON" | All units stay warm (search radar on) |
How COORDINATED_ROTATION works
Section titled “How COORDINATED_ROTATION works”Instead of every sensor radiating all the time (which makes the IADS unnecessarily vulnerable to SIGINT and SEAD aircraft), coordinated rotation divides sensors into groups. Only one group radiates at a time. The others stay cold. After a set duration, the active group goes cold and the next group takes over.
At any given moment, only a fraction of your sensors are emitting. This makes the network harder to target while still maintaining coverage.
The cycle works like this with EmconRotateGroups = 2, ScanSec = 30, QuietPeriodSec = 0:
Time 0-30s: Group A radiating, Group B coldTime 30-60s: Group A cold, Group B radiatingTime 60-90s: Group A radiating, Group B cold...Sensors are assigned to groups by their internal index in Medusa, which is the order Medusa discovers them at mission start. This order is not guaranteed to be consistent between mission restarts. If you have 6 EWRs and 2 groups, they’ll be split evenly, but which specific EWR ends up in which group may vary.
With QuietPeriodSec > 0, there’s dead time between each group’s handoff where nobody is radiating:
EmconRotateGroups = 3, ScanSec = 20, QuietPeriodSec = 10
Time 0-20s: Group A radiatingTime 20-30s: Everyone cold (dead time)Time 30-50s: Group B radiatingTime 50-60s: Everyone cold (dead time)Time 60-80s: Group C radiatingTime 80-90s: Everyone cold (dead time)...SAMAsEWR
Section titled “SAMAsEWR”All HOT batteries already contribute track data to the network (via BatteryTargetDatalink, enabled by default). SAMAsEWR is different. It controls whether LR_SAM and MR_SAM batteries with search radars are kept warm specifically to act as sensors, even when EMCON policy would otherwise send them cold. Short-range systems (SR_SAM, AAA) are never eligible.
This matters when your dedicated EWR sites get destroyed. Without SAMAsEWR, your SAM batteries go cold per EMCON policy and the IADS goes blind. With it enabled, long and medium range SAMs with search radars stay warm to fill the sensor gap.
When the sensor pool changes (an EWR is destroyed, a SAM starts acting as EWR, or a new sensor is added), Medusa automatically rebuilds COORDINATED_ROTATION groups and logs the new schedule.
SAMAsEWR = "WHEN_NO_EWR",| Value | Behavior |
|---|---|
"DISABLED" | SAMs follow their normal EMCON policy, never kept warm as sensors |
"WHEN_NO_EWR" | SAMs with search radars stay warm as sensors only if all dedicated EWR/GCI sensors are destroyed (default) |
"ALWAYS" | Eligible SAMs always stay warm as sensors regardless of EWR status |
HARM Response
Section titled “HARM Response”Controls how batteries react to detected anti-radiation missiles:
HARMResponse = "AUTO_DEFENSE",HARMShutdownM = 15000, -- Search radius around HARM tracks (meters)| Value | Behavior |
|---|---|
"AUTO_DEFENSE" | Automatic decision per battery (default, see below) |
"SELF_DEFEND" | Stay hot if the battery’s own defense points exceed inbound HARM count (no PD pooling) |
"SHUTDOWN_UNLESS_PD" | Always shut down unless a point defense provider is assigned and alive. No math, just “do I have a PD buddy or not” |
"SHUTDOWN" | Always shut down the targeted battery |
"IGNORE" | Do not react to detected HARMs |
How AUTO_DEFENSE works
Section titled “How AUTO_DEFENSE works”DCS does not expose how capable any given battery is at engaging an inbound HARM. There is no API to ask “can this SA-10 shoot down that AGM-88?” and no way to query how many guidance channels a battery’s radar has. Medusa uses a scoring algorithm based on launcher count and type. A battery with more launchers can engage more HARMs before it’s saturated. An SA-10 with 1 launcher runs out of ammo fast. One with 8 launchers can handle a much larger ARM salvo.
Medusa computes defense points for each battery by weighting its launchers. TLARs count 4 points each. DCS doesn’t tell us what system a battery is (a separate search radar + tracker + launcher battery could be an SA-5 or an SA-20B), so Medusa uses TLAR presence as a proxy for capability, assuming TLAR-based systems are more capable against ARMs. Standalone launchers count 1.5 points each.
When a HARM is detected heading toward a battery, AUTO_DEFENSE checks the following in order:
- Point defense check. If the battery has an assigned PD provider (e.g., a Tor or Pantsir) that is alive and has ammo, the battery stays hot and lets PD intercept the HARM.
- Defense points vs HARM count. If no PD is available, Medusa totals the battery’s own defense points plus defense points from any nearby PD assets, and compares against the number of inbound HARMs within the search radius (
HARMShutdownM). If defense points exceed HARM count, the battery stays hot. - Shutdown. If the HARMs outnumber the defense points, Medusa shuts down the battery (radar off, weapons hold) to break the HARM’s guidance.
The difference from SELF_DEFEND is that AUTO_DEFENSE pools nearby point defense assets into the defense point total. SELF_DEFEND only counts the battery’s own launchers.