class ERR_ObjectProbeScanner { protected int m_ObjectProbeCount; protected int m_ObjectProbeElevated; ref array m_ObjectProbeCandidates = {}; protected bool ObjectProbeFilter(IEntity entity) { if (!entity || Vehicle.Cast(entity) || ChimeraCharacter.Cast(entity)) return false; string prefab; if (entity.GetPrefabData()) prefab = entity.GetPrefabData().GetPrefabName(); MapDescriptorComponent descriptor = MapDescriptorComponent.Cast(entity.FindComponent(MapDescriptorComponent)); int type = -1; if (descriptor) type = descriptor.GetBaseType(); return ERR_ObjectGuardRules.Structure(prefab, type); } protected bool ObjectProbeRemember(IEntity entity) { m_ObjectProbeCandidates.Insert(entity); return m_ObjectProbeCandidates.Count() < 80; } void Run(BaseWorld world) { world.QueryEntitiesByAABB("0 -1000 0", "14000 1000 14000", ObjectProbeRemember, ObjectProbeFilter, EQueryEntitiesFlags.ALL); PrintFormat("ERR OBJECT PROBE candidates=%1", m_ObjectProbeCandidates.Count()); foreach (IEntity entity : m_ObjectProbeCandidates) { ERR_ObjectGuardPlacement posts = new ERR_ObjectGuardPlacement(); posts.Reset(); array players = {entity.GetOrigin() + "1200 0 0"}; vector point; bool found = posts.Find(entity, players, 0, point); float height; if (found) height = point[1] - world.GetSurfaceY(point[0], point[2]); string prefab; if (entity.GetPrefabData()) prefab = entity.GetPrefabData().GetPrefabName(); PrintFormat("ERR OBJECT PROBE structure=%1 origin=%2 found=%3 point=%4 aboveGround=%5", prefab, entity.GetOrigin(), found, point, height); if (found && height > 2) m_ObjectProbeElevated++; m_ObjectProbeCount++; } PrintFormat("ERR OBJECT GEOMETRY COMPLETE: tested=%1 elevated=%2", m_ObjectProbeCount, m_ObjectProbeElevated); ERR_HQ hq = ERR_HQ.Cast(ERR_GameMode.Get().Command()); foreach (IEntity candidate : m_ObjectProbeCandidates) { string name; if (candidate.GetPrefabData()) name = candidate.GetPrefabData().GetPrefabName(); if (!name.Contains("LightTower_01")) continue; hq.ObjectProbeStart(candidate, m_ObjectProbeCandidates); break; } } } modded class SCR_ChimeraAIAgent { void ObjectProbeRelease() { ERR_PrisonPhaseChanged(ERR_Phase.PRISON, ERR_Phase.RADIO_SEARCH); SetPermanentLOD(0); ActivateAI(); } } modded class ERR_ObjectGarrisons { protected ref array m_ProbeObservers = {}; protected ref array m_ProbeStarts = {}; override protected void Players(out array positions) { if (m_ProbeObservers.IsEmpty()) { super.Players(positions); return; } positions.Copy(m_ProbeObservers); } void ObjectProbeSetup(IEntity first, array nearby) { ConfigureCount(8); Remember(first); foreach (IEntity other : nearby) if (vector.DistanceXZ(first.GetOrigin(), other.GetOrigin()) < 120) Remember(other); m_ProbeObservers.Insert(first.GetOrigin() + "1200 0 0"); PrintFormat("ERR OBJECT SETUP sites=%1 groups=%2 structures=%3", m_Sites.Count(), m_Towns.Count(), m_Sites[0].Structures.Count()); } override void ObjectProbeSpawn(float now) { foreach (ERR_TownGarrison entry : m_Towns) Attempt(entry, m_ProbeObservers, now); } override void ObjectProbeInspect(bool release) { int total, fixed, radios, elevated; foreach (ERR_TownGarrison entry : m_Towns) { if (!entry.Admitted) { PrintFormat("ERR OBJECT WAIT id=%1", entry.Id); continue; } array agents = {}; entry.Group.GetAgents(agents); foreach (AIAgent agent : agents) { IEntity actor = agent.GetControlledEntity(); if (!actor) continue; vector point = actor.GetOrigin(); float height = point[1] - GetGame().GetWorld().GetSurfaceY(point[0], point[2]); int radio = ERR_HQRadio.Capability(actor); bool alive = ERR_Actors.Alive(actor); PrintFormat("ERR OBJECT ACTOR id=%1 fixed=%2 alive=%3 radio=%4 height=%5 point=%6", entry.Id, entry.FixedGuard, alive, radio, height, point); total++; if (entry.FixedGuard) fixed++; if (radio > 0) radios++; if (height > 2) elevated++; SCR_ChimeraAIAgent soldier = SCR_ChimeraAIAgent.Cast(agent); if (release && soldier) soldier.ObjectProbeRelease(); } } PrintFormat("ERR OBJECT COUNTS total=%1 fixed=%2 radios=%3 elevated=%4 release=%5", total, fixed, radios, elevated, release); } } modded class ERR_TownGarrisons { void ObjectProbeStart(IEntity first, array nearby) { m_Objects = new ERR_ObjectGarrisons(m_Mode); m_Objects.ObjectProbeSetup(first, nearby); } void ObjectProbeSpawn(float now) { if (m_Objects) m_Objects.ObjectProbeSpawn(now); } void ObjectProbeInspect(bool release) { if (m_Objects) m_Objects.ObjectProbeInspect(release); } } modded class ERR_HQ { void ObjectProbeStart(IEntity first, array nearby) { m_Towns.ObjectProbeStart(first, nearby); } void ObjectProbeSpawn(float now) { m_Towns.ObjectProbeSpawn(now); m_Equipment.Tick(now); } void ObjectProbeInspect(bool release) { m_Towns.ObjectProbeInspect(release); foreach (ERR_HQUnit unit : m_Units) if (unit.ForceSourceId.StartsWith("object-")) PrintFormat("ERR OBJECT HQ id=%1 fixed=%2 reserved=%3 eligible=%4", unit.ForceSourceId, unit.HomeGuard, unit.ReservedForSupport, unit.Eligible(m_Mode)); } } modded class ArmaReforgerScripted { protected int m_ObjectProbePhase; protected float m_ObjectProbeStarted; protected float m_ObjectProbeNext; override void OnUpdate(BaseWorld world, float timeslice) { super.OnUpdate(world, timeslice); ERR_GameMode mode = ERR_GameMode.Get(); if (!mode || mode.Phase() < ERR_Phase.PRISON || m_ObjectProbePhase == 3) return; float now = world.GetWorldTime(); if (now < m_ObjectProbeNext) return; m_ObjectProbeNext = now + 1000; ERR_HQ hq = ERR_HQ.Cast(mode.Command()); if (m_ObjectProbePhase == 0) { ERR_ObjectProbeScanner scanner = new ERR_ObjectProbeScanner(); scanner.Run(world); m_ObjectProbePhase = 1; m_ObjectProbeStarted = now; return; } if (m_ObjectProbePhase == 1) { hq.ObjectProbeSpawn(now); if (now - m_ObjectProbeStarted < 12000) return; hq.ObjectProbeInspect(true); m_ObjectProbePhase = 2; return; } hq.ObjectProbeSpawn(now); if (now - m_ObjectProbeStarted < 45000) return; hq.ObjectProbeInspect(false); m_ObjectProbePhase = 3; Print("ERR OBJECT PROBE COMPLETE: native spawn / HQ role / 30-second post observation"); } }