--- /tmp/erri-hunt-before/ERR_HunterService.c 2026-10-04 12:52:07.062255262 +0200 +++ addons/core/Scripts/Game/ERR/10_AI/ERR_HunterService.c 2026-10-04 12:52:07.173449725 +0200 @@ -131,13 +131,17 @@ ERR_ConvoyPlacement placement = new ERR_ConvoyPlacement(); if (m_Hunters.Count() < 3) { - if (!m_Opening || !m_Opening.Ready()) return false; - int slot = m_Hunters.Count(); - vector openingPosition = m_Opening.Positions[slot]; - vector openingAngles = m_Opening.Angles[slot]; - if (!ERR_HunterOpeningPlan.AwayFromPlayers(openingPosition, players) || !placement.Clear(openingPosition, openingAngles[0])) - { ERR_HQ.Event("HUNTER WAIT", "reserved opening road occupied; no unsafe spawn"); return false; } - return SpawnHunter(hq, now, openingPosition, openingAngles, "prison-opening"); + if (!m_Opening || !m_Opening.Done()) return false; + if (m_Opening.Ready()) + { + int slot = m_Hunters.Count(); + vector openingPosition = m_Opening.Positions[slot]; + vector openingAngles = m_Opening.Angles[slot]; + if (ERR_HunterOpeningPlan.AwayFromPlayers(openingPosition, players) && placement.Clear(openingPosition, openingAngles[0])) + return SpawnHunter(hq, now, openingPosition, openingAngles, "prison-opening"); + } + // Coastlines and sparse road networks may never admit three opposing + // bearings. A completed/occupied opening plan must not lock out all patrols. } for (int i = 0; i < m_Mode.Sites().Count(); i++) { @@ -147,11 +151,15 @@ vector position, angles; vector seed = site.Definition.Position + Vector(Math.RandomFloat(-200, 200), 0, Math.RandomFloat(-200, 200)); if (!ERR_SupplyConvoySystem.ApproachDirected(seed, position, angles) || !placement.Clear(position, angles[0])) continue; - bool nearPlayer; - foreach (IEntity player : players) if (player && vector.DistanceXZ(player.GetOrigin(), position) < 400) nearPlayer = true; - if (nearPlayer) continue; + if (!ERR_HunterOpeningPlan.AwayFromPlayers(position, players)) continue; + if (m_Hunters.Count() < 3 && vector.DistanceXZ(position, m_Opening.Center) < 600) continue; + bool occupied; + foreach (ERR_HunterVehicle deployed : m_Hunters) + if (!deployed.Released && deployed.Entity && vector.DistanceXZ(position, deployed.Entity.GetOrigin()) < 100) occupied = true; + if (occupied) continue; return SpawnHunter(hq, now, position, angles, site.Definition.Id); } + m_NextSpawn = now + 10000; ERR_HQ.Event("HUNTER WAIT", "deployment deferred: friendly road obstructed, occupied, budget full or players within 400m"); return false; }