Skip to content

How It Works

Activation Range vs Engagement Zone

Every SAM has two range values:

  • Activation Range (actRange): When the EW feeds contact data in integrated mode, the SAM goes ALERT and starts tracking at this range. This gives the DCS AI time to build a fire solution before the target reaches missile range.
  • Engagement Zone (WEZ/NEZ): The actual missile engagement envelope. In EMCON mode, the SAM only breaks cover when a target is inside this range.

For example, the SA-2 has actRange=30 NM and WEZ=24 NM. In integrated mode it starts tracking at 30 NM, giving the AI 6 NM of lead time (~45s at 480 kts). In EMCON mode it stays hidden until 24 NM.

The activation range automatically tracks zone overrides. Each system has a built-in margin (actRange minus WEZ) representing the DCS AI lead time. When a NEZ or WEZ override changes the engagement zone, the activation range adjusts to preserve that margin. For example, an SA-6 (wez=18, actRange=22, margin=4) with a NEZ override (nez=6) activates at 10 NM (6+4), not the default 22 NM. The ACT suffix always overrides this calculation.

State Machine

Every SAM site is in one of seven states:

State Emissions ROE Description
DARK OFF HOLD No threat. Invisible to RWR.
AWARE OFF HOLD EW has contacts but none in this SAM's activation range.
ALERT ON WEAPONS FREE Contact in activation range. Fully hot, engaging.
EMCON_ON OFF HOLD EMCON active. Emissions silent. Cycling.
EMCON_OFF ON HOLD EMCON lifted. Radar sweeping, not yet engaging.
EMCON_ENGAGED ON WEAPONS FREE Was EMCON, found target in WEZ, weapons free.
DESTROYED -- -- Dead. Terminal state.

Integrated Operations (EW Alive)

Contact enters theater
  -> EW detects contact
  -> SAMs in sector go AWARE (still dark, no emissions)
  -> Contact enters a SAM's activation range
  -> That SAM goes ALERT (emissions on, weapons free)
  -> Contact leaves activation range
  -> SAM returns to AWARE (next poll cycle)
  -> Contact leaves theater
  -> SAM returns to DARK (after alertTimeout)

From the cockpit: RWR is clean until you push into the activation range.

Alert Frustration

A SAM in ALERT checks whether any EW-fed contact is actually inside its WEZ (not just the activation range). If the target loiters in the activation zone without ever entering the WEZ:

  • After 30-60s (randomized) of ALERT with no WEZ contacts, the crew gets antsy
  • 10% chance they stay hot (re-rolls the timeout), 90% chance they power down to AWARE
  • After powering down, the crew enters a frustration cooldown (another 30-60s randomized). During cooldown, the same contact in actRange won't re-alert the SAM — the crew is ignoring it
  • A WEZ contact breaks cooldown immediately — that's a real threat and the crew snaps back to ALERT
  • Once cooldown expires, the next poll cycle can re-alert the SAM if contacts are still in actRange (with a fresh frustration timeout)

This uses the same contacts the EW poll already gathered — zero additional API calls.

Degraded Operations (EW Dead)

When a SAM loses EW coverage (or was never networked), it enters EMCON cycling:

EMCON_ON (silent, 30-120s)
  -> EMCON_OFF (sweep, 15-45s)
    -> Target in WEZ? EMCON_ENGAGED (weapons free)
    -> No target? Back to EMCON_ON

HARM Reaction

AEGIS hooks S_EVENT_SHOT and identifies anti-radiation missiles by weapon descriptor (missileCategory=6, guidance=5).

TOO/SP Mode (HARM locked on a SAM)

getTarget() returns the targeted unit. AEGIS maps it to a tracked SAM, then the crew processes the warning (8-12s randomized delay — detection + classification + crew action) before reacting:

Condition Reaction Behavior
Multi-HARM saturation (2+ in 15s) GO_DARK Even capable crews bail under saturation
Nat 20 bravery roll (5% chance) DEFIANT Any crew might decide to fight back
selfProtect=true (SA-10, SA-11, PATRIOT, SA-15, TOR) STAY_HOT Engages ARM with own missiles (30s window)
selfProtect=true but crew panics (15% chance) GO_DARK Not every crew is brave
Has live PD child LAST_DITCH PD defends 8-12s, then parent goes dark
Neither GO_DARK Classic HARM dodge with jittered cooldown (45-90s)

The bravery roll is checked after multi-HARM saturation (which always forces GO_DARK) but before the normal selfProtect/PD/GO_DARK tree. When it hits, the SAM executes as STAY_HOT — 30s engagement window, same as selfProtect. Even a non-selfProtect SA-2 crew might decide today's the day they earn a medal. F10 marker shows DEFIANT (crew fighting back!).

selfProtect values are in SYSTEM_DB and can be hand-edited by mission makers.

During any HARM reaction, a cooldown prevents the EW poll from overriding the SAM's state. The cooldown starts at detection time (not after the crew delay) — the SAM's state is frozen the moment the crew begins processing the threat. This prevents alert frustration or other poll-driven transitions from overriding a pending HARM reaction. The actual reaction (STAY_HOT, LAST_DITCH, GO_DARK) overwrites the cooldown with its own duration. If the HARM is still in flight when cooldown expires, it auto-extends (checked via weapon:isExist()). Hard cap of 180s prevents infinite extension.

HARM Targeting a PD

When a HARM targets a point defense unit, AEGIS redirects the reaction to the parent SAM. A HARM aimed at a co-located PD is functionally a HARM aimed at the entire site. The PD stays hot -- engaging HARMs is its job.

PB Mode (HARM aimed at coordinates, no lock)

getTarget() returns nil. AEGIS stores the weapon reference and checks trajectory 2 seconds later (velocity is {0,0,0} at launch but populates within ~0.5s). A single position + velocity sample projects a ray forward. SAMs within 5 NM (configurable) of the projected path are affected.

Two independent detection paths:

  1. harmInbound flag — Set on ALL SAMs in trajectory, regardless of EW coverage. If the SAM emits while the flag is active (from any cause — EW activation, EMCON sweep, weasel bait), the SAM detects the HARM on its own tracking radar and enters the HARM reaction tree (8-12s crew delay). Flag expires at ETA + 30s margin. If the SAM never emits, the flag expires silently.

  2. EW network warning — If the SAM has a live EW in its sector, the EW detects the HARM via radar sweeps using a score-per-sweep model. Detection delay is based on range from the HARM to the EW — 12s at close range, 60s+ at 40 NM, effectively never at 70+ NM. Multiple EWs sum scores each sweep. After detection, a 3-5s unit reaction delay, then the SAM gets warned. Warning only sent if total delay < HARM ETA.

EW Network Gate

EW warnings require a live EW close enough to detect a small RCS target. An autonomous SAM (EW dead) only has the harmInbound path — it must emit to detect the HARM.

Situation Detection Path Action
SAM emitting, harmInbound active Own-radar detection HARM reaction tree (8-12s delay)
SAM dark, close EW (< 30 NM) EW network warning (12-30s) Emitting: HARM reaction. Dark: EMCON suppressed + PD activation
SAM dark, distant EW (> 40 NM) EW too slow, harmInbound only Flag waits. SAM baited up → own-radar detection
SAM dark, no EW harmInbound only Flag waits. SAM stays dark → flag expires, SAM survives
PB HARM + weasel baits SAM harmInbound triggers SAM detects HARM on own radar, reacts

Point Defense

Point defense SAMs (SA-15, Tor, etc.) slave to their nearest parent SAM or EW:

  • Parent goes ALERT -> PD goes ALERT
  • Parent goes DARK -> PD goes DARK
  • PD units don't use their own WEZ for activation
  • During HARM events: PD activates immediately to defend parent (bypasses poll cycle)
  • PD stays ALERT through full HARM cooldown -- even after parent goes dark, PD remains hot to engage inbound HARMs
  • PB HARM warning: PD goes ALERT to defend a dark parent when network detects inbound HARM

Place PD groups within 5 NM of their parent and name them PD-TYPE-SECTOR-ID.

Orphan Promotion

When a parent SAM is destroyed, its PD children don't just go dark forever — they promote to autonomous SAMs:

  • The PD creates a full SAM entry using its own system data (SA-15 with wez=8, actRange=10, selfProtect=true)
  • Starts EMCON cycling independently in the parent's sector
  • Responds to HARMs through the normal reaction tree (SA-15 has selfProtect)
  • Shows up in status reports and F10 markers as a SAM, not a PD

An orphaned SA-15 is still a capable short-range SAM. Kill a parent SA-10 and the defending SA-15 doesn't give up — it starts hunting on its own.

Decoy Effectiveness

Decoys (TALDs, ADM-141A) appear as real radar contacts to the IADS. This means:

  • EWRs detect them and feed them to the contact list
  • SAMs check activation range and go ALERT
  • DCS AI locks and engages the decoy with missiles

SEAD packages with TALDs ahead of strike aircraft will force SAM emissions and waste missiles -- exactly as designed in real life. A 10-TALD swarm is a perfectly valid tactic.

Contact Filtering

DCS radar detection returns everything in the air. AEGIS filters out weapons that shouldn't trigger SAM activation:

Object Triggers SAM? Why
Aircraft / helicopters Yes Real threats
TALDs (ADM-141A) Yes Decoys designed to fool radar
Mk-82 / dumb bombs No Ordnance, not a trackable threat
AGM-88 HARM No Would give away HARM presence to IADS
AIM-120 / AAMs No Air-to-air, not relevant
SAM missiles No Friendly fire prevention

EMCON Jitter

EMCON cycling is not a metronome. Each cycle varies based on:

  • Startup jitter: 0-60s random delay before first cycle. SAMs entering EMCON at the same time desynchronize immediately.
  • Threat memory: SAM detected something last sweep? Next silent phase is shorter (crew is anxious). Three empty sweeps in a row? Silent phase gets longer (crew relaxes).
  • Quick peek: 20% chance of a very short 3-6 second sweep instead of the full window. Brief flash on RWR then gone.
  • Double-sweep: 15% chance of a brief pause then sweeping again if a contact was seen outside the WEZ. Crew wants another look.
  • Neighbor spook (optional): A nearby SAM gets killed? Neighboring EMCON SAMs go extra silent for 2 minutes. They know SEAD is active.
  • Reengage jitter: After engaging, SAM goes dark after 10-30s (random) once target leaves the WEZ.

Zone and Activation Overrides

Override a SAM's engagement zone and activation range directly in its ME group name. Suffixes are order-independent:

SAM-SA10-NORTH-1                Default WEZ (39 NM), default ACT (50 NM)
SAM-SA10-NORTH-1-NEZ            NEZ with database default (20 NM), ACT auto-derives (24 NM)
SAM-SA10-NORTH-1-NEZ25          NEZ at 25 NM, ACT auto-derives (25 + 11 = 36 NM)
SAM-SA10-NORTH-1-WEZ30          WEZ override at 30 NM, ACT auto-derives (30 + 11 = 41 NM)
SAM-SA10-NORTH-1-ACT60          Default WEZ, activation forced to 60 NM
SAM-SA2-NORTH-1-NEZ-ACT30       NEZ + activation forced to 30 NM (ACT overrides auto-derive)
SAM-SA6-SOUTH-ACT25-NEZ         Same as NEZ-ACT25 (order doesn't matter)

When a NEZ or WEZ suffix changes the engagement zone, the activation range automatically adjusts to preserve the system's built-in margin (actRange - WEZ from the database). An explicit ACT suffix always takes priority over the auto-derived value.

Parsed once at mission load. Zero runtime cost.

EW Detection Range Override

Limit an EW's effective detection range directly in its ME group name with the DET{range} suffix:

EW-NORTH                        No limit (DCS radar model determines range)
EW-NORTH-DET120                 120 NM detection cap
EW-NORTH-2-DET80                EW #2 in NORTH, 80 NM cap

Contacts beyond the detection range are dropped before feeding to the sector. Models degraded radars, terrain masking, or doctrinal placement — a hilltop 1L13 and a mobile P-19 can have different effective ranges without touching DCS unit properties.

A global default can be set via ewDetectionRange in the config table (0 = no limit). The per-EW DET suffix always takes priority. Parsed once at init, zero runtime cost — the range check is a single squared-distance comparison per contact, short-circuited when no cap is set.

Mission Kill vs Full Kill

AEGIS distinguishes between two types of SAM death:

Mission Kill — The tracking radar is destroyed but support units survive. Applies to SAM types with a dedicated tracking radar (SA-2, SA-3, SA-5, SA-6, SA-10, HAWK, PATRIOT). The SAM is combat-ineffective — it can't track or engage — even though DCS considers the group alive. AEGIS marks it DESTROYED and silences all surviving units (emissions off, weapons hold). Orphan PD promotion fires normally.

Full Kill — The entire DCS group is destroyed (getSize() == 0). Applies to all SAM types, including self-contained systems (SA-8, SA-11, SA-15, TOR, etc.) that have no single critical unit.

At init, AEGIS scans each SAM group for the tracking radar unit by DCS type name (e.g., S-300PS 40B6M tr for SA-10). The init log shows (TR: unitname) @(x, z) for SAMs with critical unit tracking — the coordinates enable cross-mission position comparison by diffing topology logs. On each death event, AEGIS checks the tracking radar first (Tier 1), then falls back to the group check (Tier 2). Self-contained systems skip Tier 1 entirely — zero overhead.

Kill SA-10's Flap Lid radar (1 of 18 units)
  -> *** SAM MISSION KILL: SAM-SA10-SOUTH-1 (tracking radar destroyed)
  -> Surviving 17 units silenced (emissions off, weapons hold)
  -> Orphan PD-SA15 promotes to autonomous SAM
  -> F10 marker removed (same as full kill)

Power Sources

Power is per-node, not per-sector. Every SAM is self-powered by default. To add a power dependency:

PWR-SA5-SOUTH-1    -> auto-links to SAM-SA5-SOUTH-1
PWR-SA2-NORTH-1    -> auto-links to SAM-SA2-NORTH-1
PWR-EW-NORTH       -> auto-links to EW-NORTH

Kill the power group, that specific node goes permanently DARK. For EW radars, the power kill also silences the radar in DCS so it drops off RWR.

Autonomous SAMs

SAMs in a sector with no EW and no other infrastructure start EMCON cycling from mission start. No special configuration needed -- just name your SAM and it handles itself.

ECM Jamming

ECM aircraft (ECM- prefix on opposing coalition) trigger jammed EMCON cycling on emitting SAMs within their effect range. The jammer is reactive — it only affects nodes that are actively radiating.

Jammed EMCON Flow

SAM emitting (ALERT, EMCON_OFF, or EMCON_ENGAGED)
  -> Jammer in range detects emission (1-3s delay)
  -> Crew recognizes jamming -> shuts down (DARK)
  -> Enters jammed EMCON cycling:
     -> Off-phase (45-120s): hiding from jammer
     -> On-phase (8-15s): brief radar peek
       -> During jam detection window (1-3s): targets inside burn-through range engageable
         -> Burn-through contact found -> SAM stays ALERT (monitored every 5s)
         -> Contacts leave burn-through range -> back to off-phase
       -> No burn-through -> jammer catches emission -> crew goes dark again
  -> Jammer leaves/dies -> next on-cycle, no jam detected -> exit jammed EMCON
  -> Poll restores normal state (EW alive -> ALERT, EW dead -> normal EMCON)

Burn-Through

Jamming isn't absolute. During the 1-3s detection delay at the start of each on-cycle, the SAM's radar is briefly unjammed. Any target inside burn-through range during that window produces a strong enough return to track — not just the jammer, any contact.

Once a burn-through contact is detected, the SAM stays ALERT and continues engaging as long as targets remain inside burn-through range. A monitoring loop checks every 5 seconds. When all burn-through contacts leave (or the jammer dies), the SAM returns to the jammed EMCON off-phase.

Priority

1. HARM cooldown (harmCooldownUntil) — highest, never overridden
2. Jammed EMCON (jammedEmconActive) — jammer in range
3. Normal state machine — poll evaluation

Jammed EMCON uses its own generation counter (jammedEmconGen), independent of normal EMCON (emconGen). _StopEMCON() is called before starting jammed EMCON to prevent timer conflicts.

Performance

Scenario Computation
Idle (no contacts) O(EW_count) -- typically 4-6 radars
Active contacts O(EW_count) + O(contacts x SAMs_in_sector) for range checks
EMCON cycling 2 getDetectedTargets() calls per SAM per cycle (staggered)
HARM detection Event-driven only (S_EVENT_SHOT), zero polling cost
PB HARM trajectory One-shot: 1 weapon poll + 1 ray per SAM site, fires once per PB HARM
Quiet sectors Zero -- skipped entirely

Range checks use squared distance (no sqrt). All values precomputed. Nothing runs every frame.

Round-Robin Polling (v0.8.0+)

AEGIS spreads EW polling across time for high-density missions (70+ aircraft). Instead of processing all sectors in one burst every ewPollInterval, it processes one sector per sub-cycle:

Pre-0.8:  |--- all 7 sectors ---|                    |--- all 7 sectors ---|
          t=0                   t=10                                       t=20

v0.8.0+:  |N|  |S|  |E|  |W|  |C|  |NW| |SE| |N|  |S|  |E| ...
          t=0  1.4  2.8  4.3  5.7  7.1  8.6  10.0 11.4 12.8

Each sector is still polled once per ewPollInterval (same frequency), but the DCS API calls are spread evenly. With debug = true, per-sector timing appears in the log: PERF: NORTH poll 2.3ms (12 contacts).