modded class SCR_ChimeraAIAgent { void ProbeHuntRelease() { ERR_PrisonPhaseChanged(ERR_Phase.PRISON, ERR_Phase.RADIO_SEARCH); SetPermanentLOD(0); ActivateAI(); } } modded class ERR_HunterService { ERR_HunterVehicle ProbeHuntUnit(vector position, vector angles, int ordinal) { ERR_HunterVehicle unit = new ERR_HunterVehicle(); unit.Source = "hunt-probe-" + ordinal.ToString(); unit.TroopTransport = ordinal == 2; unit.Entity = Vehicle.Cast(ERR_Actors.Spawn(ERR_HunterFleetRules.VehiclePrefab(ordinal), position, angles)); unit.Group = SCR_AIGroup.Cast(ERR_Actors.Spawn(ERR_ConvoyResources.GroupPrefab(), position)); if (!unit.Entity || !unit.Group || !FillCrew(unit)) return null; unit.Group.SetPermanentLOD(0); unit.Group.ActivateAI(); return unit; } } modded class ERR_HunterTactics { bool ProbeHuntBegin(float now) { foreach (IEntity member : Unit.Members) { AIControlComponent control = AIControlComponent.Cast(member.FindComponent(AIControlComponent)); SCR_ChimeraAIAgent agent = SCR_ChimeraAIAgent.Cast(control.GetControlAIAgent()); if (agent) agent.ProbeHuntRelease(); } SCR_AIGroupUtilityComponent utility = Unit.Group.GetGroupUtilityComponent(); SCR_AIVehicleUsageComponent usage = SCR_AIVehicleUsageComponent.Cast(Unit.Entity.FindComponent(SCR_AIVehicleUsageComponent)); if (utility && usage) utility.AddUsableVehicle(usage); if (!Move(Stage, 35)) return false; Delivered = true; State = 1; Deadline = now + ERR_HunterAttackRules.ManeuverBudget(m_TravelDistance); m_ApproachStarted = now; m_ApproachProgress = now; m_ApproachPosition = Unit.Entity.GetOrigin(); if (Role == 0) foreach (IEntity crew : Unit.Members) ERR_ConvoyMountedCrew.Hold(crew, Unit.Entity); return true; } } modded class ArmaReforgerScripted { protected ref ERR_HunterOpeningPlan m_HuntPlan; protected ref ERR_HunterService m_HuntService; protected ref ERR_HunterAttack m_HuntAttack; protected ref array m_HuntUnits = {}; protected ref array m_HuntStarts = {}; protected int m_HuntPhase; protected float m_HuntNext; protected float m_HuntStarted; 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_HuntPhase == 3) return; float now = world.GetWorldTime(); if (now < m_HuntNext) return; m_HuntNext = now + 1000; if (m_HuntPhase == 0) { if (!m_HuntPlan) { vector center, angles; if (!ERR_SupplyConvoySystem.ApproachDirected("6880 0 3500", center, angles, 500)) { Print("ERR HUNT FAILED test contact road"); m_HuntPhase = 3; return; } PrintFormat("ERR HUNT CONTACT: point=%1 water=%2", center, ChimeraWorldUtils.TryGetWaterSurfaceSimple(world, center)); m_HuntPlan = new ERR_HunterOpeningPlan(center, 1000); } array players = {}; m_HuntPlan.Step(players); if (!m_HuntPlan.Done()) return; if (!m_HuntPlan.Ready()) { Print("ERR HUNT FAILED opening"); m_HuntPhase = 3; return; } m_HuntService = new ERR_HunterService(mode, null); for (int i = 0; i < 3; i++) { ERR_HunterVehicle unit = m_HuntService.ProbeHuntUnit(m_HuntPlan.Positions[i], m_HuntPlan.Angles[i], i); if (!unit) { Print("ERR HUNT FAILED crew"); m_HuntPhase = 3; return; } m_HuntUnits.Insert(unit); m_HuntStarts.Insert(unit.Entity.GetOrigin()); } m_HuntPhase = 1; m_HuntNext = now + 10000; return; } if (m_HuntPhase == 1) { m_HuntAttack = new ERR_HunterAttack(); m_HuntAttack.ReportPosition = m_HuntPlan.Center; m_HuntAttack.Started = now; m_HuntAttack.Forward = ERR_MountedCover.Approach(m_HuntUnits[0].Entity.GetOrigin(), m_HuntAttack.ReportPosition, "0 0 1"); array occupied = {}; for (int n = 0; n < m_HuntUnits.Count(); n++) { ERR_HunterTactics team = new ERR_HunterTactics(mode, m_HuntUnits[n], m_HuntAttack, n); PrintFormat("ERR HUNT READY: role=%1 living=%2 crewValid=%3 members=%4", n, team.Living(), m_HuntUnits[n].CrewValid(mode), m_HuntUnits[n].Members.Count()); vector forward = ERR_MountedCover.Approach(m_HuntStarts[n], m_HuntAttack.ReportPosition, m_HuntAttack.Forward); vector seed = ERR_Actors.Ground(m_HuntAttack.ReportPosition - forward * 260); ERR_ConvoyPlacement placement = new ERR_ConvoyPlacement(); bool spawnFlat = placement.Clear(seed, ERR_ForceRules.Heading(seed, m_HuntAttack.ReportPosition, 0)); string spawnReason = placement.Diagnostic(); bool stageClear = placement.Clear(seed, ERR_ForceRules.Heading(seed, m_HuntAttack.ReportPosition, 0), 2.5); PrintFormat("ERR HUNT SURFACE: role=%1 spawnFlat=%2 stageClear=%3 previous=%4 staging=%5", n, spawnFlat, stageClear, spawnReason, placement.Diagnostic()); bool planned = team.Plan(occupied); bool ownSide = vector.Dot(team.Stage - m_HuntAttack.ReportPosition, m_HuntStarts[n] - m_HuntAttack.ReportPosition) > 0; bool lane = ERR_MountedCover.ClearLane(m_HuntUnits[n].Entity, team.Stage, m_HuntAttack.ReportPosition); PrintFormat("ERR HUNT PLAN: role=%1 planned=%2 ownSide=%3 lane=%4 start=%5 stage=%6", n, planned, ownSide, lane, m_HuntStarts[n], team.Stage); if (!planned) continue; occupied.Insert(team.Stage); m_HuntAttack.Teams.Insert(team); bool began = team.ProbeHuntBegin(now); PrintFormat("ERR HUNT BEGIN: role=%1 began=%2", n, began); } m_HuntStarted = now; m_HuntPhase = 2; return; } foreach (ERR_HunterTactics active : m_HuntAttack.Teams) active.Tick(ERR_HQ.Cast(mode.Command()), now); if (now - m_HuntStarted < 120000) return; foreach (ERR_HunterTactics finalTeam : m_HuntAttack.Teams) { PrintFormat("ERR HUNT MOVEMENT: role=%1 moved=%2 state=%3 stopped=%4", finalTeam.Role, vector.DistanceXZ(finalTeam.Unit.Entity.GetOrigin(), m_HuntStarts[finalTeam.Role]), finalTeam.State, finalTeam.Stopped); finalTeam.Stop(); } Print("ERR HUNT COMPLETE"); m_HuntPhase = 3; } }