// Explicit, local Workbench diagnostic only. Never compiled into game/server builds. #ifdef WORKBENCH modded class ERR_GameMode { protected bool m_ERRTestPatrolHQ; protected ref ERR_NativePatrolProbe m_ERRHQPatrolMovement; protected ref ERR_NativePatrolHQProbe m_ERRHQPatrolOrder; protected int m_ERRSmokeStep; protected float m_ERRSmokeDeadline; protected float m_ERRSmokeWait; protected IEntity m_ERRSmokePlayer; protected BaseDoorComponent m_ERRGate; protected ERR_LocationComponent m_ERRSmokeRadio; protected bool m_ERRSmokeDone; protected bool m_ERRTestLostHelicopter; protected bool m_ERRTestPlayerDeath; protected bool m_ERRTestRadioNetwork; protected bool m_ERRTestHQResponse; protected bool m_ERRTestHQMemory; protected bool m_ERRTestHQBody; protected ref ERR_NativeHQBodyProbe m_ERRHQBodyProbe; protected bool m_ERRTestConvoy; protected ref ERR_NativeConvoyProbe m_ERRConvoyProbe; protected ref ERR_NativeHQMemoryProbe m_ERRHQMemoryProbe; protected bool m_ERRTestMortar; protected bool m_ERRTestMortarFire; protected bool m_ERRTestMapOwnership; protected bool m_ERRTestAircraftField; protected ref ERR_NativeAircraftFieldProbe m_ERRAircraftField; protected bool m_ERRTestAircraftRoute; protected ref ERR_NativeAircraftRouteProbe m_ERRAircraftRoute; protected bool m_ERRTestAircraftControl; protected bool m_ERRTestAircraftCancel; protected bool m_ERRTestAircraftTranslate; protected ref ERR_NativeAircraftControlProbe m_ERRAircraftControl; protected ref ERRM_NativeMapOwnershipProbe m_ERRMapOwnership; protected bool m_ERRTestMortarSalvo; protected ref ERR_NativeMortarSalvoProbe m_ERRMortarSalvo; protected bool m_ERRTestMortarCourier; protected ref ERR_NativeMortarCourierProbe m_ERRMortarCourier; protected bool m_ERRTestMortarTransfer; protected ref ERR_NativeMortarTransferProbe m_ERRMortarTransfer; protected ref ERR_NativeMortarFiringProbe m_ERRMortarFire; protected float m_ERRNextProbeLog; protected ref ERR_NativeRadioProbe m_ERRRadioProbe; protected ref ERR_NativeHQResponseProof m_ERRHQResponseProof; protected ref array m_ERRCacheFolders = {}; protected int m_ERRIntelRerollStage; protected float m_ERRIntelRerollDeadline; protected ref array m_ERRIntelActors = {}; protected ref array m_ERRRetiredIntel = {}; protected override void EOnInit(IEntity owner) { super.EOnInit(owner); string enabled; if (SCR_Global.IsEditMode() || !Replication.IsServer() || !System.GetCLIParam("errSmoke", enabled) || enabled != "1") return; string outcome; m_ERRTestLostHelicopter = System.GetCLIParam("errSmokeOutcome", outcome) && outcome == "lost-helicopter"; m_ERRTestRadioNetwork = outcome == "radio-network"; m_ERRTestHQResponse = outcome == "hq-response"; m_ERRTestHQMemory = outcome == "hq-memory"; m_ERRTestHQBody = outcome == "hq-body"; m_ERRTestConvoy = outcome == "convoy"; m_ERRTestMortar = outcome == "mortar-inventory"; m_ERRTestMapOwnership = outcome == "map-ownership"; m_ERRTestAircraftField = outcome == "aircraft-field"; m_ERRTestAircraftRoute = outcome == "aircraft-route"; m_ERRTestAircraftCancel = outcome == "aircraft-cancel"; m_ERRTestAircraftTranslate = outcome == "aircraft-translate"; m_ERRTestAircraftControl = outcome == "aircraft-control" || m_ERRTestAircraftCancel || m_ERRTestAircraftTranslate; m_ERRTestMortarFire = outcome == "mortar-fire" || outcome == "mortar-expiry"; m_ERRTestMortarCourier = outcome == "mortar-courier"; m_ERRTestMortarSalvo = outcome == "mortar-salvo" || outcome == "mortar-refresh"; m_ERRTestMortarTransfer = outcome == "mortar-transfer"; m_ERRTestPatrolHQ = outcome == "patrol-hq"; m_ERRTestPlayerDeath = outcome == "player-death" || m_ERRTestRadioNetwork || m_ERRTestHQResponse || m_ERRTestMortar || m_ERRTestHQMemory || m_ERRTestHQBody || m_ERRTestConvoy; m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 150000; if (m_ERRTestConvoy) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 540000; if (m_ERRTestHQMemory || m_ERRTestHQBody) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 240000; if (m_ERRTestAircraftControl || m_ERRTestAircraftRoute || m_ERRTestAircraftField) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 330000; if (m_ERRTestMortarCourier) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 450000; if (m_ERRTestMortarTransfer) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 330000; if (m_ERRTestMortarSalvo) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 330000; if (m_ERRTestMortarFire) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 330000; if (m_ERRTestPatrolHQ) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 420000; OnStop().Insert(ERR_StopHQPatrol); OnPhaseChanged().Insert(ERR_SmokePhase); GetGame().GetCallqueue().CallLater(ERR_SmokeTick, 500, true); Print("ERR SMOKE: scripted integration test enabled; gameplay acceptance remains separate"); } // Ordinary victory fixture additionally exercises the actual administrator // reroll against native enemy inventories. Scripted, not remote UI evidence. protected bool ERR_CheckIntelReroll(float now) { if (m_ERRIntelRerollStage == 3) return true; if (m_ERRIntelRerollStage == 0) { if (!ERR_Check(Sites() && Sites().Find("everon-supply-2") && Sites().Find("everon-supply-2").Group, "reroll cache group is ready")) return false; array guards = {}; Sites().Find("everon-supply-2").Group.GetAgents(guards); foreach (AIAgent guard : guards) { if (!guard) continue; IEntity actor = guard.GetControlledEntity(); if (ERR_Actors.Alive(actor) && !ERR_Actors.Player(actor)) m_ERRIntelActors.Insert(actor); } if (!ERR_Check(!m_ERRIntelActors.IsEmpty(), "reroll observes original living cache guards")) return false; array replies = {}; string before = m_Intel.RerollStatus(); m_Admin.Execute(this, false, "intel reroll", replies); if (!ERR_Check(m_Intel.RerollStatus() == before && !m_Intel.RerollRunning(), "unauthorized reroll cannot start a batch")) return false; if (!ERR_Check(m_Settings.Set("aiIntelChancePercent", 100), "native reroll captured chance configured")) return false; m_Admin.Execute(this, true, "intel reroll", replies); if (!ERR_Check(m_Intel.RerollRunning() && !m_Intel.BeginReroll(), "administrator starts one batch; overlapping reroll rejected")) return false; if (!ERR_Check(m_Settings.Set("aiIntelChancePercent", 0), "live setting change does not alter captured batch chance")) return false; m_ERRIntelRerollDeadline = now + 90000; m_ERRIntelRerollStage = 1; return false; } if (now >= m_ERRIntelRerollDeadline) return ERR_Check(false, "native reroll exceeded bounded fixture deadline"); if (m_Intel.RerollRunning()) return false; Print("ERR INTEL REROLL: " + m_Intel.RerollStatus()); if (!ERR_Check(m_Intel.RerollStatus().IndexOf(", 0 failed,") >= 0, "native inventory reroll completes without failed operations")) return false; foreach (IEntity actor : m_ERRIntelActors) { if (!ERR_Check(ERR_Actors.Alive(actor), "original cache guard survives the reroll fixture")) return false; array folders = {}; ERR_DiscoveryService.Folders(InventoryStorageManagerComponent.Cast(actor.FindComponent(InventoryStorageManagerComponent)), folders); if (m_ERRIntelRerollStage == 1) { if (!ERR_Check(folders.Count() == 1, "captured 100 percent batch assigns one native folder despite live zero setting")) return false; m_ERRRetiredIntel.Insert(folders[0]); } else if (!ERR_Check(folders.IsEmpty(), "zero percent reroll removes original native AI folders without replacements")) return false; } array carried = {}; ERR_DiscoveryService.Folders(InventoryStorageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(InventoryStorageManagerComponent)), carried); foreach (IEntity document : m_ERRCacheFolders) if (!ERR_Check(carried.Contains(document), "reroll preserves player's exact collected clue documents")) return false; if (!ERR_Check(m_ERRSmokeRadio.Knowledge() == 2, "reroll preserves already identified radio")) return false; if (m_ERRIntelRerollStage == 1) { if (!ERR_Check(m_Intel.BeginReroll(), "next independent batch uses current zero probability")) return false; m_ERRIntelRerollStage = 2; return false; } foreach (IEntity retired : m_ERRRetiredIntel) if (!ERR_Check(retired && Discovery().IsSpent(retired) && m_OwnedEntities.Contains(retired), "retired native document remains spent and owned for round cleanup")) return false; m_ERRIntelRerollStage = 3; return true; } protected bool ERR_Check(bool condition, string name) { if (condition) { Print("ERR SMOKE PASS: " + name); return true; } ERR_StopHQPatrol(); Print("ERR SMOKE FAIL: " + name, LogLevel.ERROR); m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); return false; } protected void ERR_StopHQPatrol() { if (m_ERRMapOwnership) m_ERRMapOwnership.Stop(); if (m_ERRAircraftControl) m_ERRAircraftControl.Stop(); if (m_ERRAircraftRoute) m_ERRAircraftRoute.Stop(); if (m_ERRAircraftField) m_ERRAircraftField.Stop(); if (m_ERRHQResponseProof) m_ERRHQResponseProof.Stop(); if (m_ERRMortarSalvo) m_ERRMortarSalvo.Stop(); if (m_ERRMortarCourier) m_ERRMortarCourier.Stop(); if (m_ERRMortarTransfer) m_ERRMortarTransfer.Stop(); if (m_ERRMortarFire) m_ERRMortarFire.Stop(); if (m_ERRHQPatrolMovement) m_ERRHQPatrolMovement.Stop(); if (m_ERRHQPatrolOrder) m_ERRHQPatrolOrder.Stop(); } protected void ERR_MovePlayer(vector position) { vector transform[4]; m_ERRSmokePlayer.GetWorldTransform(transform); transform[3] = ERR_Actors.Ground(position); ChimeraCharacter.Cast(m_ERRSmokePlayer).Teleport(transform); } protected ERR_UnlockPrisonAction ERR_FindLock(IEntity entity) { BaseActionsManagerComponent manager = BaseActionsManagerComponent.Cast(entity.FindComponent(BaseActionsManagerComponent)); if (manager) { array actions = {}; manager.GetActionsList(actions); foreach (BaseUserAction action : actions) { ERR_UnlockPrisonAction lock = ERR_UnlockPrisonAction.Cast(action); if (lock) return lock; } } IEntity child = entity.GetChildren(); while (child) { ERR_UnlockPrisonAction lock = ERR_FindLock(child); if (lock) return lock; child = child.GetSibling(); } return null; } protected void ERR_SmokePhase(ERR_Phase previous, ERR_Phase current) { if (m_ERRSmokeDone || !ERR_MissionRules.Terminal(current)) return; if (m_ERRTestAircraftField) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 241, "actual aircraft field fixture completed before explicit reset")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); ERR_StopHQPatrol(); string fieldCancel; string fieldResult = "actual immutable100m field route, measured cruise/braking, destination hold and contact landing; bounded prototype, not HQ support"; if (System.GetCLIParam("errSmokeFieldServiceCancel", fieldCancel) && fieldCancel == "1") fieldResult = "actual moving field service Stop retains control through braking, frozen-point contact landing and engine shutdown; no destination arrival or HQ support claim"; Print("ERR SMOKE COMPLETE: " + fieldResult); return; } if (m_ERRTestAircraftRoute) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 231, "actual aircraft route completed before explicit fixture reset")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); ERR_StopHQPatrol(); string serviceCancel; string routeResult = "actual immutable short aircraft route, destination hold and contact landing; experimental mechanism, not HQ transport"; if (System.GetCLIParam("errSmokeRouteServiceCancel", serviceCancel) && serviceCancel == "1") routeResult = "actual airborne service Stop retains original control through frozen-point contact landing and engine shutdown; no destination arrival or HQ transport claim"; Print("ERR SMOKE COMPLETE: " + routeResult); return; } if (m_ERRTestAircraftControl) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 221, "actual aircraft controller completed before explicit fixture reset")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); ERR_StopHQPatrol(); if (m_ERRTestAircraftCancel) Print("ERR SMOKE COMPLETE: actual airborne aircraft cancellation retains inputs through settled contact landing and engine-off; isolated mechanism, not HQ dispatch"); else if (m_ERRTestAircraftTranslate) Print("ERR SMOKE COMPLETE: actual aircraft controller immutable target translation, observed target hold and contact landing; bounded mechanism, not route support or HQ dispatch"); else Print("ERR SMOKE COMPLETE: actual aircraft controller and post-spawn qualification, powered hover and contact landing; isolated physical mechanism, not HQ dispatch"); return; } if (m_ERRTestMapOwnership) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 201, "native map ownership probe cleaned up before explicit reset")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); ERR_StopHQPatrol(); Print("ERR SMOKE COMPLETE: native replacement map/config/root ownership and spare deletion; camera authorization observed, render flag not measured"); return; } if (m_ERRTestMortarSalvo) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 191, "native configured salvo and unchanged-report replay observation complete before reset")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); ERR_StopHQPatrol(); Print("ERR SMOKE COMPLETE: native full configured mortar salvo, exact original ammunition and unchanged-report replay refusal; fixture reset requested"); return; } if (m_ERRTestMortarCourier) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 181, "native finite courier reached an exhausted battery before explicit reset")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); ERR_StopHQPatrol(); Print("ERR SMOKE COMPLETE: native finite courier, real supply uplink/downlink, original patrol walking and exact physical shell delivery; original 27 shells sequestered in fixture boxes; reset requested"); return; } if (m_ERRTestMortarTransfer) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 161, "native exact shell transfers and original-owner restoration complete before explicit reset")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); ERR_StopHQPatrol(); Print("ERR SMOKE COMPLETE: native exact mortar inventory transfer, accepted-operation cancellation and original-owner restoration; radio bypassed; fixture reset requested"); return; } if (m_ERRTestMortarFire) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 151, "native mortar first shot and stop complete before explicit reset")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); ERR_StopHQPatrol(); Print("ERR SMOKE COMPLETE: native HQ radio mortar projectile and configured cancellation/expiry; fixture reset requested"); return; } if (m_ERRTestPatrolHQ) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 133, "HQ patrol preemption and physical resumption before explicit reset")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); Print("ERR SMOKE COMPLETE: native HQ patrol preemption and physical resumption"); return; } if (m_ERRTestPlayerDeath) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 91, "death exhausts round life and reaches defeat after spectator grace")) return; } else if (m_ERRTestLostHelicopter) { if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 8, "lost extraction helicopter causes defeat")) return; } else if (!ERR_Check(current == ERR_Phase.VICTORY && m_ERRSmokeStep == 7, "scripted escape reaches victory after physical vehicle occupancy")) return; m_ERRSmokeDone = true; GetGame().GetCallqueue().Remove(ERR_SmokeTick); PrintFormat("ERR SMOKE COMPLETE: terminal=%1 lostHelicopterCase=%2 playerDeathCase=%3", current, m_ERRTestLostHelicopter, m_ERRTestPlayerDeath); GetGame().GetCallqueue().CallLater(ERR_EndScreenshot, 4000); } protected bool ERR_CheckRoster() { ERR_PlayerRoster roster = new ERR_PlayerRoster(); UUID first = "00e77100-0000-0000-0000-000000000101"; UUID second = "00e77100-0000-0000-0000-000000000202"; if (!ERR_Check(roster.Bind(101, first) && roster.CanEnter(101, ERR_Phase.PRISON), "new identity may enter prison")) return false; roster.Spawned(101, m_ERRSmokePlayer); if (!ERR_Check(!roster.CanEnter(101, ERR_Phase.PRISON), "spawn consumes identity life")) return false; roster.Disconnect(101); if (!ERR_Check(roster.HasSurvivor() && !roster.Get(101), "disconnect retains living actor and clears connection")) return false; if (!ERR_Check(roster.Bind(202, first) && !roster.CanEnter(202, ERR_Phase.PRISON), "reconnected identity retains spent life")) return false; if (!ERR_Check(!roster.Bind(303, first), "duplicate active identity rejected")) return false; if (!ERR_Check(roster.Bind(101, second) && roster.CanEnter(101, ERR_Phase.RADIO_DEFENCE) && !roster.CanEnter(101, ERR_Phase.EXTRACTION), "recycled connection receives independent life and extraction admission policy")) return false; return true; } protected bool ERR_CheckCompanionCommands() { array replies = {}; array commands = {"hq interval show", "hq squads show", "hq radius show", "intel carrying show", "intel reveal show"}; array keys = {"reportIntervalSeconds", "supportSquadLimit", "responseRadiusMetres", "aiIntelChancePercent", "intelRevealChancePercent"}; for (int i = 0; i < commands.Count(); i++) { Admin().Execute(this, true, commands[i], replies); if (!ERR_Check(replies.Count() == 1 && replies[0] == keys[i] + "=" + Settings().Get(keys[i]).ToString(), "companion command retained: " + commands[i])) return false; } Admin().Execute(this, false, "hq log", replies); if (!ERR_Check(replies.Count() == 1 && replies[0] == "Administrator access required.", "companion journal is behind Core admin authorization")) return false; Admin().Execute(this, true, "hq show", replies); ERR_HQ hq = ERR_HQ.Cast(Command()); if (!ERR_Check(hq && replies.Count() == 1 && replies[0] == hq.Status(), "companion HQ status uses the shared command service")) return false; return true; } protected void ERR_PrisonScreenshot() { System.MakeScreenshot("$logs:err-prison"); } protected void ERR_EndScreenshot() { System.MakeScreenshot("$logs:err-result"); } protected void ERR_SmokeTick() { float now = GetWorld().GetWorldTime(); if (m_ERRSmokeDone) return; if (now > m_ERRSmokeDeadline) { ERR_Check(false, "timeout at step " + m_ERRSmokeStep.ToString()); return; } if (now < m_ERRSmokeWait) return; if (m_ERRSmokeStep == 240) { int result = m_ERRAircraftField.Tick(now); if (result < 0) { ERR_Check(false, "native actual aircraft field fixture"); return; } if (result == 1) { m_ERRSmokeStep = 241; Transition(ERR_Phase.DEFEAT); } return; } if (m_ERRSmokeStep == 230) { int result = m_ERRAircraftRoute.Tick(now); if (result < 0) { ERR_Check(false, "native actual aircraft route fixture"); return; } if (result == 1) { m_ERRSmokeStep = 231; Transition(ERR_Phase.DEFEAT); } return; } if (m_ERRSmokeStep == 220) { int result = m_ERRAircraftControl.Tick(now); if (result < 0) { ERR_Check(false, "native actual aircraft controller fixture"); return; } if (result == 1) { m_ERRSmokeStep = 221; Transition(ERR_Phase.DEFEAT); } return; } if (m_ERRSmokeStep == 200) { int result = m_ERRMapOwnership.Tick(now); if (result < 0) { ERR_Check(false, "native map ownership fixture"); return; } if (result == 1) { m_ERRSmokeStep = 201; Transition(ERR_Phase.DEFEAT); } return; } if (m_ERRSmokeStep == 190) { int result = m_ERRMortarSalvo.Tick(now); if (result < 0) { ERR_Check(false, "native complete mortar salvo fixture; inspect source diagnostics"); return; } if (result == 1) { m_ERRSmokeStep = 191; Transition(ERR_Phase.DEFEAT); } return; } if (m_ERRSmokeStep == 180) { int result = m_ERRMortarCourier.Tick(now); if (result < 0) { ERR_Check(false, "native finite courier fixture"); return; } if (result == 1) { m_ERRSmokeStep = 181; Transition(ERR_Phase.DEFEAT); } return; } if (m_ERRSmokeStep == 160) { int result = m_ERRMortarTransfer.Tick(now); if (result < 0) { ERR_Check(false, "native mortar exact-shell transfer fixture"); return; } if (result == 1) { m_ERRSmokeStep = 161; Transition(ERR_Phase.DEFEAT); } return; } if (m_ERRSmokeStep == 150) { int result = m_ERRMortarFire.Tick(now); if (result < 0) { ERR_Check(false, "native mortar firing probe failed; see diagnostics"); return; } if (result == 1) { m_ERRSmokeStep = 151; Transition(ERR_Phase.DEFEAT); } return; } if (m_ERRSmokeStep == 130 || m_ERRSmokeStep == 132) { int result = m_ERRHQPatrolMovement.Tick(now); if (result < 0) { ERR_StopHQPatrol(); GetGame().GetCallqueue().Remove(ERR_SmokeTick); return; } if (result == 1) { if (m_ERRSmokeStep == 130) { m_ERRHQPatrolOrder = new ERR_NativePatrolHQProbe(this); m_ERRSmokeStep = 131; } else { m_ERRSmokeStep = 133; Transition(ERR_Phase.DEFEAT); } } return; } if (m_ERRSmokeStep == 131) { int result = m_ERRHQPatrolOrder.Tick(now); if (result < 0) { ERR_StopHQPatrol(); GetGame().GetCallqueue().Remove(ERR_SmokeTick); return; } if (result == 1) { m_ERRHQPatrolMovement = new ERR_NativePatrolProbe(this); m_ERRSmokeStep = 132; } return; } if (m_ERRSmokeStep == 0) { array players = {}; ERR_Actors.Players(players, true); if (players.Count() != 1 || Phase() != ERR_Phase.PRISON) return; m_ERRSmokePlayer = players[0]; if (!ERR_CheckRoster() || !ERR_NativeContractsProbe.Run(this, m_ERRSmokePlayer) || !ERR_CheckCompanionCommands()) return; if (m_ERRTestAircraftField) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRAircraftField = new ERR_NativeAircraftFieldProbe(this); m_ERRSmokeStep = 240; return; } if (m_ERRTestAircraftRoute) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRAircraftRoute = new ERR_NativeAircraftRouteProbe(this); m_ERRSmokeStep = 230; return; } if (m_ERRTestAircraftControl) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRAircraftControl = new ERR_NativeAircraftControlProbe(this); m_ERRSmokeStep = 220; return; } if (m_ERRTestPatrolHQ) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRHQPatrolMovement = new ERR_NativePatrolProbe(this); m_ERRSmokeStep = 130; return; } if (m_ERRTestMapOwnership) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRMapOwnership = new ERRM_NativeMapOwnershipProbe(); m_ERRSmokeStep = 200; return; } if (m_ERRTestMortarSalvo) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRMortarSalvo = new ERR_NativeMortarSalvoProbe(this); m_ERRSmokeStep = 190; return; } if (m_ERRTestMortarCourier) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRMortarCourier = new ERR_NativeMortarCourierProbe(this); m_ERRSmokeStep = 180; return; } if (m_ERRTestMortarTransfer) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRMortarTransfer = new ERR_NativeMortarTransferProbe(this); m_ERRSmokeStep = 160; return; } if (m_ERRTestMortarFire) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRMortarFire = new ERR_NativeMortarFiringProbe(this); m_ERRSmokeStep = 150; return; } if (m_ERRTestMortar) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRSmokeStep = 120; return; } if (m_ERRTestHQResponse) { m_ERRHQResponseProof = new ERR_NativeHQResponseProof(this, m_ERRSmokePlayer); m_ERRSmokeStep = 110; return; } if (m_ERRTestConvoy) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRConvoyProbe = new ERR_NativeConvoyProbe(this); m_ERRSmokeStep = 106; return; } if (m_ERRTestHQBody) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRHQBodyProbe = new ERR_NativeHQBodyProbe(this); m_ERRSmokeStep = 107; return; } if (m_ERRTestHQMemory) { DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRHQMemoryProbe = new ERR_NativeHQMemoryProbe(this); m_ERRSmokeStep = 105; return; } if (m_ERRTestRadioNetwork) { m_ERRRadioProbe = new ERR_NativeRadioProbe(); DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); m_ERRSmokeStep = 100; return; } if (m_ERRTestPlayerDeath) { m_ERRSmokeStep = 9; SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent)).Kill(Instigator.CreateInstigator(m_ERRSmokePlayer)); m_ERRSmokeWait = now + 4000; return; } DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); if (!ERR_Check(vector.DistanceXZ(m_ERRSmokePlayer.GetOrigin(), PrisonPosition()) < 5, "initial prisoner position")) return; foreach (ERR_LocationComponent location : m_Locations) if (location.Kind() == ERR_LocationKind.RADIO) m_ERRSmokeRadio = location; if (!ERR_Check(m_ERRSmokeRadio && ERR_Actors.Alive(ExtractionVehicle()), "radio and extraction vehicle exist")) return; ERR_UnlockPrisonAction lock; foreach (IEntity tracked : m_OwnedEntities) { if (tracked) lock = ERR_FindLock(tracked); if (lock) break; } if (!ERR_Check(lock != null, "authored gate exposes lock action")) return; ERR_MovePlayer(lock.GetOwner().GetOrigin() + "1 0 1"); vector gateLow, gateHigh; lock.GetOwner().GetWorldBounds(gateLow, gateHigh); PrintFormat("ERR GEOMETRY: gate low=%1 high=%2", gateLow, gateHigh); IEntity wall = lock.GetOwner().GetParent().GetChildren(); while (wall) { vector wallLow, wallHigh; wall.GetWorldBounds(wallLow, wallHigh); PrintFormat("ERR GEOMETRY: child origin=%1 low=%2 high=%3", wall.GetOrigin(), wallLow, wallHigh); wall = wall.GetSibling(); } GetGame().GetCallqueue().CallLater(ERR_PrisonScreenshot, 2000); if (!ERR_Check(lock.CanBePerformedScript(m_ERRSmokePlayer), "lock permits prisoner")) return; m_ERRGate = BaseDoorComponent.Cast(lock.GetOwner().FindComponent(BaseDoorComponent)); lock.PerformAction(lock.GetOwner(), m_ERRSmokePlayer); if (!ERR_Check(Phase() == ERR_Phase.RADIO_SEARCH, "lock action advances mission")) return; array cacheStock = {}; ERR_Inventory.Items(InventoryStorageManagerComponent.Cast(Sites().Find("everon-supply-1").Container.FindComponent(InventoryStorageManagerComponent)), cacheStock); foreach (IEntity tracked : cacheStock) { if (tracked && tracked.GetPrefabData() && tracked.GetPrefabData().GetPrefabName() == ERR_Resources.ObjectiveDocument()) m_ERRCacheFolders.Insert(tracked); } if (!ERR_Check(m_ERRCacheFolders.Count() == 2, "two guaranteed physical cache documents")) return; if (!ERR_Check(m_Settings.Set("aiIntelChancePercent", 0), "test does not rely on random intel")) return; if (!ERR_Check(m_Settings.Set("radioDefenceSeconds", 30), "isolated test profile defence duration")) return; m_ERRSmokeStep = 1; } else if (m_ERRSmokeStep == 1 || m_ERRSmokeStep == 2) { if (m_ERRSmokeStep == 2 && !ERR_Check(m_ERRGate && m_ERRGate.IsOpen() && m_ERRGate.CanCharacterPass(0.6), "unlocked gate physically permits passage")) return; ERR_MovePlayer(Sites().Find("everon-supply-1").Container.GetOrigin() + "0 0 2"); SCR_InventoryStorageManagerComponent inventory = SCR_InventoryStorageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_InventoryStorageManagerComponent)); InventoryStorageManagerComponent source = InventoryStorageManagerComponent.Cast(Sites().Find("everon-supply-1").Container.FindComponent(InventoryStorageManagerComponent)); BaseInventoryStorageComponent destination = inventory.FindStorageForItem(m_ERRCacheFolders[m_ERRSmokeStep - 1]); if (!ERR_Check(destination && source.TryMoveItemToStorage(m_ERRCacheFolders[m_ERRSmokeStep - 1], destination), "authored cache document recovered into inventory")) return; m_ERRSmokeStep++; m_ERRSmokeWait = now + 2500; } else if (m_ERRSmokeStep == 3) { int adminMenu = ERR_ProbeAdminMenu(now); if (adminMenu < 0) { ERR_Check(false, "integrated admin menu"); return; } if (adminMenu == 0) return; if (!ERR_CheckIntelReroll(now)) return; if (!ERR_Check(m_ERRSmokeRadio.Knowledge() == 2, "carried intel identifies radio through intel service")) return; if (!ERR_Check(!TuneRadio(m_ERRSmokePlayer, m_ERRSmokeRadio), "radio rejects distant player")) return; ERR_MovePlayer(m_ERRSmokeRadio.Position() + "2 0 0"); m_ERRSmokeStep = 30; m_ERRSmokeWait = now + 1000; } else if (m_ERRSmokeStep == 30) { PrintFormat("ERR SMOKE: radio=%1 player=%2", m_ERRSmokeRadio.Position(), m_ERRSmokePlayer.GetOrigin()); if (!ERR_Check(TuneRadio(m_ERRSmokePlayer, m_ERRSmokeRadio), "identified radio starts defence")) return; m_ERRSmokeStep = 4; m_ERRSmokeWait = now + 3000; } else if (m_ERRSmokeStep == 4) { if (!ERR_Check(DefenceOccupied(), "occupied defence timer running")) return; ERR_MovePlayer(m_ERRSmokeRadio.Position() + "90 0 0"); m_ERRSmokeStep = 5; m_ERRSmokeWait = now + 2500; } else if (m_ERRSmokeStep == 5) { if (!ERR_Check(!DefenceOccupied() && Phase() == ERR_Phase.RADIO_DEFENCE, "leaving area resets defence")) return; ERR_MovePlayer(m_ERRSmokeRadio.Position() + "2 0 0"); m_ERRSmokeStep = 6; m_ERRSmokeWait = now + 33000; } else if (m_ERRSmokeStep == 6) { if (!ERR_Check(Phase() == ERR_Phase.EXTRACTION, "continuous occupied defence completes")) return; if (m_ERRTestLostHelicopter) { m_ERRSmokeStep = 8; ERR_Actors.DeleteSpawned(ExtractionVehicle()); return; } CompartmentAccessComponent access = CompartmentAccessComponent.Cast(m_ERRSmokePlayer.FindComponent(CompartmentAccessComponent)); BaseCompartmentSlot slot = access.FindFreeCompartment(ExtractionVehicle(), ECompartmentType.PILOT); if (!ERR_Check(slot && access.GetInVehicle(ExtractionVehicle(), slot, true, -1, ECloseDoorAfterActions.INVALID, false), "boarding extraction vehicle")) return; m_ERRSmokeStep = 7; m_ERRSmokeWait = now + 3000; } else if (m_ERRSmokeStep == 120) { ERR_MortarBattery battery = ERR_MortarSystem.Get().ERR_ProbeBattery(); if (!battery || !battery.StartupActivated) return; if (!ERR_Check(battery.Operational() && battery.Group.GetAgentsCount() == 4, "authored physical mortar and four-person crew initialize")) return; if (!ERR_Check(ERR_HQRadio.Capability(battery.RadioOperator) == 2, "mortar has a dedicated physical manpack operator")) return; if (!ERR_Check(battery.CountShells() == 27, "mortar starts with exactly 27 physical HE shells")) return; array agents = {}; battery.Group.GetAgents(agents); array intelCrew = {}; foreach (AIAgent intelAgent : agents) { IEntity intelActor; if (intelAgent) intelActor = intelAgent.GetControlledEntity(); if (!ERR_Check(intelActor && !intelCrew.Contains(intelActor), "mortar Intel observation uses distinct actual crew actors")) return; if (!ERR_Check(m_Intel && m_Intel.ERR_ProbeWasRolled(intelActor), "ready mortar crew actor reached its one optional Intel carrying roll")) return; intelCrew.Insert(intelActor); } if (!ERR_Check(intelCrew.Count() == 4, "all four original ready physical crew reached Intel without forcing documents or changing carrying chance")) return; foreach (AIAgent agent : agents) { InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(agent.GetControlledEntity().FindComponent(InventoryStorageManagerComponent)); array items = {}; ERR_Inventory.Items(inventory, items); foreach (IEntity item : items) if (item && item.GetPrefabData() && item.GetPrefabData().GetPrefabName() == ERR_MortarBattery.SHELL) SCR_EntityHelper.DeleteEntityAndChildren(item); } m_ERRSmokeStep = 121; m_ERRSmokeWait = now + 15000; } else if (m_ERRSmokeStep == 121) { ERR_MortarBattery battery = ERR_MortarSystem.Get().ERR_ProbeBattery(); if (!ERR_Check(battery.CountShells() == 0 && battery.TotalShots == 0, "depleted mortar inventory stays empty without fabricated ammunition")) return; ERR_Actors.DeleteSpawned(battery.Gun); ERR_Actors.DeleteSpawned(battery.Group); m_ERRSmokeStep = 122; m_ERRSmokeWait = now + 12000; } else if (m_ERRSmokeStep == 122) { ERR_MortarBattery battery = ERR_MortarSystem.Get().ERR_ProbeBattery(); if (!ERR_Check(battery && !battery.Gun && !battery.Group && !battery.Operational(), "lost mortar and crew remain lost without replacement spawning")) return; m_ERRSmokeStep = 9; SCR_CharacterDamageManagerComponent damage = SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent)); damage.EnableDamageHandling(true); damage.Kill(Instigator.CreateInstigator(m_ERRSmokePlayer)); m_ERRSmokeWait = now + 4000; } else if (m_ERRSmokeStep == 110) { int result = m_ERRHQResponseProof.Tick(now); if (result < 0) { ERR_Check(false, "native HQ response evidence failed; inspect report lineage diagnostics"); return; } if (result == 0) return; m_ERRSmokeStep = 9; SCR_CharacterDamageManagerComponent damage = SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent)); damage.EnableDamageHandling(true); damage.Kill(Instigator.CreateInstigator(m_ERRSmokePlayer)); m_ERRSmokeWait = now + 4000; } else if (m_ERRSmokeStep == 107) { int result = m_ERRHQBodyProbe.Tick(ERR_HQ.Cast(Command()), now); if (result == 0) return; m_ERRHQBodyProbe.Stop(); if (!ERR_Check(result == 1, "native visual body discovery, delivered casualty and status overlap")) return; m_ERRSmokeStep = 9; SCR_CharacterDamageManagerComponent damage; damage = SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent)); damage.EnableDamageHandling(true); damage.Kill(Instigator.CreateInstigator(m_ERRSmokePlayer)); m_ERRSmokeWait = now + 4000; } else if (m_ERRSmokeStep == 106) { int result = m_ERRConvoyProbe.Tick(ERR_HQ.Cast(Command()), now); if (result == 0) return; if (!ERR_Check(result == 1, "native six-vehicle convoy readiness, cargo and road movement")) return; m_ERRSmokeStep = 9; SCR_CharacterDamageManagerComponent damage; damage = SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent)); damage.EnableDamageHandling(true); damage.Kill(Instigator.CreateInstigator(m_ERRSmokePlayer)); m_ERRSmokeWait = now + 4000; } else if (m_ERRSmokeStep == 105) { int result = m_ERRHQMemoryProbe.Tick(ERR_HQ.Cast(Command()), now); if (result == 0) return; if (!ERR_Check(result == 1, "native HQ memory delivery and search lineage")) return; m_ERRSmokeStep = 9; SCR_CharacterDamageManagerComponent damage; damage = SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent)); damage.EnableDamageHandling(true); damage.Kill(Instigator.CreateInstigator(m_ERRSmokePlayer)); m_ERRSmokeWait = now + 4000; } else if (m_ERRSmokeStep == 100) { int result = m_ERRRadioProbe.Tick(ERR_HQ.Cast(Command()), now); if (result == 0) return; if (!ERR_Check(result == 1, "native radio delivery and interruption sequence")) return; m_ERRSmokeStep = 9; SCR_CharacterDamageManagerComponent damage = SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent)); damage.EnableDamageHandling(true); damage.Kill(Instigator.CreateInstigator(m_ERRSmokePlayer)); m_ERRSmokeWait = now + 4000; } else if (m_ERRSmokeStep == 9) { SCR_PlayerController controller = SCR_PlayerController.Cast(GetGame().GetPlayerController()); if (!ERR_Check(!ERR_Actors.Alive(m_ERRSmokePlayer), "native damage kills prisoner")) return; if (!ERR_Check(controller && controller.ERR_ObserverState() == ERR_ObserverReason.SPENT_LIFE, "death selects spectator without another life")) return; if (!ERR_Check(controller.ERR_HasObserverCamera() && SCR_ManualCamera.Cast(GetGame().GetCameraManager().CurrentCamera()), "spectator camera activates after native death")) return; m_ERRSmokeStep = 91; } else if (m_ERRSmokeStep == 7) { if (!ERR_Check(CompartmentAccessComponent.GetVehicleIn(m_ERRSmokePlayer) == ExtractionVehicle(), "physical extraction occupancy")) return; // Controlled transport tests the boundary detector, not piloting skill. ExtractionVehicle().SetOrigin(m_EscapeCenter + Vector(m_EscapeRadius + 100, 300, 0)); m_ERRSmokeWait = now + 5000; } } void ~ERR_GameMode() { if (GetGame()) { GetGame().GetCallqueue().Remove(ERR_SmokeTick); GetGame().GetCallqueue().Remove(ERR_PrisonScreenshot); GetGame().GetCallqueue().Remove(ERR_EndScreenshot); } } } #endif