--- addons/core/Scripts/Game/ERR/00_Core/ERR_NativeEnemyLoadoutProbe.c
+++ addons/core/Scripts/Game/ERR/00_Core/ERR_NativeEnemyLoadoutProbe.c
@@ -1,4 +1,21 @@
 #ifdef WORKBENCH
+class ERR_ProbeAutomaticGrant : ERR_AutomaticEquipmentGrant
+{
+ ResourceName Prefab;
+ bool Weapon;
+ override protected ERR_AutomaticEquipmentItem Choose(ERR_GameMode mode)
+ {
+  ERR_AutomaticEquipmentItem choice = new ERR_AutomaticEquipmentItem(); choice.Prefab = Prefab; choice.Weapon = Weapon; return choice;
+ }
+ int MagazinesRequested() { return m_Magazines; }
+ bool Carried(IEntity actor)
+ {
+  InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(actor.FindComponent(InventoryStorageManagerComponent));
+  return m_Issued && inventory && inventory.Contains(m_Issued);
+ }
+ bool AmmunitionComplete() { return m_Magazines == 2 && m_Operation && m_Operation.Finished && m_Operation.Succeeded; }
+}
+
 // Real native inventory fixture; deliberately not registered with the ordinary equipment service.
 class ERR_ProbeBrokenLauncherGrant : ERR_EnemyLauncherGrant
 {
@@ -9,6 +26,8 @@
 }
 modded class ERR_GameMode
 {
+ protected ref ERR_ProbeAutomaticGrant m_ERRAutoGun = new ERR_ProbeAutomaticGrant();
+ protected ref ERR_ProbeAutomaticGrant m_ERRAutoItem = new ERR_ProbeAutomaticGrant();
  protected int m_ERRLoadoutDeadline;
  protected int m_ERRLoadoutStage;
  protected SCR_AIGroup m_ERRLoadoutGroup;
@@ -49,12 +68,28 @@
    m_ERRLoadoutGroup.m_aUnitPrefabSlots = {
     "{5436629450D8387A}Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_SL.et",
     "{5436629450D8387A}Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_SL.et"};
-   m_ERRLoadoutGroup.RequestSpawn(2); m_ERRLoadoutStage = 1; return;
+   m_ERRLoadoutGroup.m_aUnitPrefabSlots.Insert("{5436629450D8387A}Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_SL.et");
+   m_ERRLoadoutGroup.m_aUnitPrefabSlots.Insert("{5436629450D8387A}Prefabs/Characters/Factions/OPFOR/USSR_Army/Character_USSR_SL.et");
+   if (!ERR_LoadoutCheck(Settings().Set("automaticEquipmentChancePercent", 100) && ERR_AutomaticEquipmentCatalog.Count(this) > 0, "automatic equipment catalog and setting")) return;
+   // Choose a real discovered mod rifle, not a hardcoded Escape integration entry.
+   for (int candidate = 0; candidate < 512; candidate++)
+   {
+    ERR_AutomaticEquipmentItem discovered = ERR_AutomaticEquipmentCatalog.Pick(this);
+    if (!discovered || !discovered.Weapon || (!discovered.Prefab.Contains("/AK74M/") && !discovered.Prefab.Contains("/M4A1/"))) continue;
+    m_ERRAutoGun.Prefab = discovered.Prefab; m_ERRAutoGun.Weapon = true; break;
+   }
+   if (!ERR_LoadoutCheck(!m_ERRAutoGun.Prefab.IsEmpty(), "discovered mod rifle=" + m_ERRAutoGun.Prefab)) return;
+   m_ERRAutoItem.Prefab = ERR_EnemyMedicalCatalog.MORPHINE;
+   for (int sample = 0; sample < 12; sample++) Print("ERR AUTO CATALOG SAMPLE: " + ERR_AutomaticEquipmentCatalog.Pick(this).Prefab);
+   m_ERRLoadoutGroup.RequestSpawn(4); m_ERRLoadoutStage = 1; return;
   }
   array<AIAgent> agents = {}; m_ERRLoadoutGroup.GetAgents(agents);
-  if (agents.Count() != 2 || !agents[0].GetControlledEntity() || !agents[1].GetControlledEntity()) return;
+  if (agents.Count() != 4) return;
+  foreach (AIAgent ready : agents) if (!ready.GetControlledEntity()) return;
   IEntity first = agents[0].GetControlledEntity(); IEntity second = agents[1].GetControlledEntity();
   foreach (AIAgent agent : agents) agent.DeactivateAI();
+  m_ERRAutoGun.Check(this, m_ERRLoadoutGroup, agents[2].GetControlledEntity());
+  m_ERRAutoItem.Check(this, m_ERRLoadoutGroup, agents[3].GetControlledEntity());
   if (m_ERRLoadoutStage == 1)
   {
    m_ERRNativeAA.Check(this, m_ERRLoadoutGroup, first);
@@ -77,6 +112,8 @@
    Print("ERR ADMIN CAPTURE PAGE: 1"); m_ERRLoadoutStage = 3; return;
   }
   if (m_ERRLoadoutStage++ < 8) return;
+  if (!m_ERRAutoGun.Done() || !m_ERRAutoItem.Done()) return;
+  if (!ERR_LoadoutCheck(m_ERRAutoGun.Carried(agents[2].GetControlledEntity()) && m_ERRAutoGun.AmmunitionComplete() && m_ERRAutoItem.Carried(agents[3].GetControlledEntity()), "automatic catalog item and spare-slot rifle still carried; both matching magazine insertions completed")) return;
   System.MakeScreenshot("$logs:err-enemy-loadout-menu");
   GetGame().GetCallqueue().Remove(ERR_LoadoutTick);
   Print("ERR SMOKE COMPLETE: enemy-loadout physical preferred/fallback launchers, AP mines and HQ menu");
--- addons/core/Scripts/Game/ERR/00_Core/ERR_Settings.c
+++ addons/core/Scripts/Game/ERR/00_Core/ERR_Settings.c
@@ -9,7 +9,7 @@
 
 	static array<string> Keys()
 	{
-		return {"keepWeaponOnUnconscious", "reportIntervalSeconds", "supportSquadLimit", "responseRadiusMetres", "aiIntelChancePercent", "intelRevealChancePercent", "radioDefenceSeconds", "startTimeMinutes", "timeMultiplier", "startDateCode", "weatherProfile", "viewDistanceMetres", "antiAirChancePercent", "antiPersonnelMineChancePercent", "automaticConvoyEnabled", "convoyCount", "heliTimerMinutes"};
+		return {"keepWeaponOnUnconscious", "reportIntervalSeconds", "supportSquadLimit", "responseRadiusMetres", "aiIntelChancePercent", "intelRevealChancePercent", "radioDefenceSeconds", "startTimeMinutes", "timeMultiplier", "startDateCode", "weatherProfile", "viewDistanceMetres", "antiAirChancePercent", "antiPersonnelMineChancePercent", "automaticEquipmentChancePercent", "automaticConvoyEnabled", "convoyCount", "heliTimerMinutes"};
 	}
 
 	static bool Valid(string key, int value)
@@ -18,7 +18,7 @@
 		if (key == "heliTimerMinutes") return value >= 1 && value <= 1440;
 		if (key == "convoyCount") return value >= 0 && value <= 20;
 		if (key == "automaticConvoyEnabled") return value == 0 || value == 1;
-		if (key == "antiAirChancePercent" || key == "antiPersonnelMineChancePercent") return value >= 0 && value <= 100;
+		if (key == "automaticEquipmentChancePercent" || key == "antiAirChancePercent" || key == "antiPersonnelMineChancePercent") return value >= 0 && value <= 100;
 		if (key == "reportIntervalSeconds") return value >= 5 && value <= 60;
 		if (key == "supportSquadLimit") return value >= 0 && value <= 8;
 		if (key == "responseRadiusMetres") return value >= 500 && value <= 5000;
@@ -52,7 +52,7 @@
 	// Saved modes are distinct from validated concrete gameplay values.
 	static bool Randomizable(string key)
 	{
-		return key == "antiAirChancePercent" || key == "antiPersonnelMineChancePercent" || key == "heliTimerMinutes" || key == "convoyCount" || key == "reportIntervalSeconds" || key == "supportSquadLimit" || key == "responseRadiusMetres" || key == "aiIntelChancePercent" || key == "intelRevealChancePercent" || key == "radioDefenceSeconds" || key == "startTimeMinutes" || key == "timeMultiplier" || key == "startDateCode" || key == "weatherProfile";
+		return key == "automaticEquipmentChancePercent" || key == "antiAirChancePercent" || key == "antiPersonnelMineChancePercent" || key == "heliTimerMinutes" || key == "convoyCount" || key == "reportIntervalSeconds" || key == "supportSquadLimit" || key == "responseRadiusMetres" || key == "aiIntelChancePercent" || key == "intelRevealChancePercent" || key == "radioDefenceSeconds" || key == "startTimeMinutes" || key == "timeMultiplier" || key == "startDateCode" || key == "weatherProfile";
 	}
 	static bool ValidSelection(string key, int value)
 	{
@@ -74,7 +74,7 @@
 		else if (key == "reportIntervalSeconds") { minimum = 5; maximum = 60; }
 		else if (key == "supportSquadLimit") maximum = 8;
 		else if (key == "responseRadiusMetres") { minimum = 500; maximum = 5000; }
-		else if (key == "antiAirChancePercent" || key == "antiPersonnelMineChancePercent" || key == "aiIntelChancePercent" || key == "intelRevealChancePercent") maximum = 100;
+		else if (key == "automaticEquipmentChancePercent" || key == "antiAirChancePercent" || key == "antiPersonnelMineChancePercent" || key == "aiIntelChancePercent" || key == "intelRevealChancePercent") maximum = 100;
 		else if (key == "radioDefenceSeconds") { minimum = 30; maximum = 1800; }
 		else if (key == "startTimeMinutes") maximum = 1439;
 		else if (key == "timeMultiplier") { minimum = 1; maximum = 24; }
@@ -102,6 +102,7 @@
 		if (key == "heliTimerMinutes") return 15;
 		if (key == "convoyCount") return 3;
 		if (key == "automaticConvoyEnabled") return 1;
+		if (key == "automaticEquipmentChancePercent") return 25;
 		if (key == "antiAirChancePercent") return 7;
 		if (key == "antiPersonnelMineChancePercent") return 60;
 		if (key == "startTimeMinutes") return 840;
@@ -125,6 +126,7 @@
 		m_Values.Set("startDateCode", AddedDefault("startDateCode"));
 		m_Values.Set("weatherProfile", AddedDefault("weatherProfile"));
 		m_Values.Set("viewDistanceMetres", AddedDefault("viewDistanceMetres"));
+		m_Values.Set("automaticEquipmentChancePercent", AddedDefault("automaticEquipmentChancePercent"));
 		m_Values.Set("antiAirChancePercent", AddedDefault("antiAirChancePercent"));
 		m_Values.Set("antiPersonnelMineChancePercent", AddedDefault("antiPersonnelMineChancePercent"));
 		m_Values.Set("automaticConvoyEnabled", AddedDefault("automaticConvoyEnabled"));
--- addons/core/Scripts/Game/ERR/10_AI/ERR_EnemyEquipment.c
+++ addons/core/Scripts/Game/ERR/10_AI/ERR_EnemyEquipment.c
@@ -80,6 +80,7 @@
  ref ERR_EnemyOptics Optics;
  ref ERR_EnemyLauncherGrant Launcher = new ERR_EnemyLauncherGrant();
  ref ERR_EnemyMineGrant Mines = new ERR_EnemyMineGrant();
+ ref ERR_AutomaticEquipmentGrant Automatic = new ERR_AutomaticEquipmentGrant();
  ref ERR_EnemyMedicine Medicine = new ERR_EnemyMedicine();
  int SkillChecks;
  bool Released;
@@ -90,11 +91,12 @@
   if (Actor && Actor.GetPrefabData() && ERR_EnemyMedicalCatalog.Medic(Actor.GetPrefabData().GetPrefabName())) return;
   Launcher.Check(mode, Group, Actor);
   Mines.Check(mode, Group, Actor);
+  if (Medicine.ReadyForExtras() && Launcher.ReadyForExtras() && Mines.ReadyForResupply()) Automatic.Check(mode, Group, Actor);
  }
 
  void Stop(ERR_GameMode mode)
  {
-  Launcher.Stop(); Mines.Stop(); Medicine.Stop();
+  Launcher.Stop(); Mines.Stop(); Medicine.Stop(); Automatic.Stop();
   Released = true;
   if (Optics) Optics.Stop();
   if (Combat) Combat.ERR_ReleaseEnemySkill(mode);
--- addons/core/Scripts/Game/ERR/10_AI/ERR_EnemyLoadout.c
+++ addons/core/Scripts/Game/ERR/10_AI/ERR_EnemyLoadout.c
@@ -89,6 +89,7 @@
  protected IEntity m_Issued;
  protected ref array<IEntity> m_Before = {};
  protected ref ERR_EnemyEquipmentCallback m_Operation;
+ bool ReadyForExtras() { return m_Finished && (!m_Operation || m_Operation.Finished); }
  protected ResourceName Preferred(ERR_GameMode mode, SCR_AIGroup group) { return ERR_EnemyLoadoutCatalog.Launcher(mode, group.GetFaction()); }
  protected void Finish(IEntity actor, string reason)
  {
--- addons/core/Scripts/Game/ERR/10_AI/ERR_EnemyMedicine.c
+++ addons/core/Scripts/Game/ERR/10_AI/ERR_EnemyMedicine.c
@@ -64,6 +64,7 @@
  protected bool m_Medic;
  protected ref ERR_EnemyEquipmentCallback m_Operation;
  void Stop() { m_Done = true; }
+ bool ReadyForExtras() { return m_Done && (!m_Operation || m_Operation.Finished); }
  protected void Finish(IEntity actor, string reason)
  {
   m_Done = true;
--- addons/core/Scripts/Game/ERR/10_AI/ERR_HQAdminProvider.c
+++ addons/core/Scripts/Game/ERR/10_AI/ERR_HQAdminProvider.c
@@ -10,6 +10,7 @@
   if (section != "hq") return "";
   if (option == "interval") return "reportIntervalSeconds";
   if (option == "squads") return "supportSquadLimit";
+  if (option == "equipment") return "automaticEquipmentChancePercent";
   if (option == "mines") return "antiPersonnelMineChancePercent";
   if (option == "radius") return "responseRadiusMetres";
   if (option == "aa" || option == "stinger") return "antiAirChancePercent";
--- docs/enemy-loadouts.md
+++ docs/enemy-loadouts.md
@@ -67,3 +67,17 @@
 Multiplayer replication and actual missile targeting/firing were not tested.
 
 Final local fixture logs: `/tmp/erri-loadouts-native2/logs/logs_2026-09-23_15-29-59`. Source and external-addon fingerprints remained unchanged; runner cleanup was confirmed. Native menu navigation passed, but the engine screenshot omitted the overlay and the separate display capture failed, so visual layout acceptance remains unverified.
+
+## Automatic equipment from installed mods
+
+Every eligible non-medic enemy has a **25%** default chance to receive one extra inventory item. The pool is built once per round from enabled standard arsenal entries in the active scenario's general and faction ITEM catalogs. Vanilla and mod items share the pool, regardless of faction. Each distinct resource GUID has equal selection probability; entries repeated across factions do not get extra weight. A mod with many distinct variants consequently has a larger total share.
+
+No Escape connector, extra dependency or soldier prefab edit is needed for equipment that a loaded mod registers in those catalogs. Merely installing a mod is insufficient if its equipment is absent from the active catalogs. This does not enumerate every prefab in Workshop archives or automatically register new factions.
+
+The pool supports rifles, pistols, machine guns, sniper rifles, grenades, medical items and general equipment. Clothing, backpacks, attachments, loose ammunition, mines, launchers, vehicles and mortars are excluded. Existing AA/mine probabilities and authored uniforms, weapons and medical loadouts remain unchanged. Known disabled Escape content entries are excluded; unregistered mods follow the native catalog's enabled state.
+
+Use `/esc hq equipment show` or `/esc hq equipment set 0..100` (`random` is also supported). The saved key is `automaticEquipmentChancePercent` in `$profile:rereintroduced.json`; zero disables future rolls. Changing it does not reroll existing soldiers.
+
+Each selected item is attempted once after existing startup supplies settle. Guns use a free weapon slot and request at most two magazines of their main muzzle's default ammunition. The AI may use the additional gun through its normal weapon selection; this does not force a main-weapon replacement. Full or incompatible storage can refuse an item or ammunition, so the configured percentage is an **attempt probability**, not a guaranteed count of equipped soldiers. There are no loose fallback drops, retries with different items, or replacements after looting. Medics retain their storage for treatment.
+
+The HQ journal records `AUTO EQUIPMENT CATALOG` (pool size) and `AUTO EQUIPMENT` (issued/refused items and ammunition requests). Catalog limits disable the pool with a diagnostic instead of favoring a truncated subset.
--- tests/test_settings_migration.py
+++ tests/test_settings_migration.py
@@ -5,7 +5,7 @@
 spec=importlib.util.spec_from_file_location('import_settings',BASE/'tools/import_settings.py')
 m=importlib.util.module_from_spec(spec);spec.loader.exec_module(m)
 result,deferred=m.merge({'configVersion':1,'reportIntervalSeconds':20.0,'supportSquadLimit':2,'responseRadiusMetres':1500,'convoyCount':3},{'aiIntelChancePercent':0,'intelRevealChancePercent':100})
-assert result==dict(keepWeaponOnUnconscious=1,reportIntervalSeconds=20,supportSquadLimit=2,responseRadiusMetres=1500,aiIntelChancePercent=0,intelRevealChancePercent=100,radioDefenceSeconds=180,startTimeMinutes=840,timeMultiplier=1,startDateCode=0,weatherProfile=0,viewDistanceMetres=0,antiAirChancePercent=7,antiPersonnelMineChancePercent=60,automaticConvoyEnabled=1,convoyCount=3,heliTimerMinutes=15)
+assert result==dict(keepWeaponOnUnconscious=1,reportIntervalSeconds=20,supportSquadLimit=2,responseRadiusMetres=1500,aiIntelChancePercent=0,intelRevealChancePercent=100,radioDefenceSeconds=180,startTimeMinutes=840,timeMultiplier=1,startDateCode=0,weatherProfile=0,viewDistanceMetres=0,automaticEquipmentChancePercent=25,antiAirChancePercent=7,antiPersonnelMineChancePercent=60,automaticConvoyEnabled=1,convoyCount=3,heliTimerMinutes=15)
 assert deferred==[]
 for count in (0,1,3,20):
  values,notes=m.merge(ai={'convoyCount':count})
--- tools/import_settings.py
+++ tools/import_settings.py
@@ -15,13 +15,14 @@
  'startDateCode':(0,0,1501231),
  'weatherProfile':(0,0,3),
  'viewDistanceMetres':(0,0,10000),
+ 'automaticEquipmentChancePercent':(25,0,100),
  'antiAirChancePercent':(7,0,100),
  'antiPersonnelMineChancePercent':(60,0,100),
  'automaticConvoyEnabled':(1,0,1),
  'convoyCount':(3,0,20),
  'heliTimerMinutes':(15,1,1440),
 }
-AI_KEYS=('reportIntervalSeconds','supportSquadLimit','responseRadiusMetres','antiAirChancePercent','antiPersonnelMineChancePercent','automaticConvoyEnabled','heliTimerMinutes')
+AI_KEYS=('reportIntervalSeconds','supportSquadLimit','responseRadiusMetres','automaticEquipmentChancePercent','antiAirChancePercent','antiPersonnelMineChancePercent','automaticConvoyEnabled','heliTimerMinutes')
 INTEL_KEYS=('aiIntelChancePercent','intelRevealChancePercent')
 def merge(ai=None,intel=None):
  result={key:spec[0] for key,spec in SCHEMA.items()};deferred=[]
