#ifdef WORKBENCH modded class ERR_GameMode { ref ERR_DroneFlight m_TestDrone; float m_TestStart, m_TestLog; bool m_TestReturn, m_CheckedAdapter; override protected void EOnInit(IEntity owner) { super.EOnInit(owner); string kind; if (SCR_Global.IsEditMode() || !System.GetCLIParam("errSmokeOutcome", kind) || kind != "drone-recon") return; GetGame().GetCallqueue().CallLater(ERR_TestDroneTick, 50, true); } void ERR_TestDroneFail(string reason) { Print("ERR SMOKE FAIL: drone " + reason, LogLevel.ERROR); GetGame().GetCallqueue().Remove(ERR_TestDroneTick); if (m_TestDrone) m_TestDrone.Finish("fixture stopped"); } void ERR_TestDroneTick() { if (!m_CheckedAdapter) { m_CheckedAdapter = true; if (!ERR_DroneBridge.Initialize()) { ERR_TestDroneFail("adapter compiler"); return; } } if (!Active() || Phase() != ERR_Phase.PRISON) return; float now = GetWorld().GetWorldTime(); if (!m_TestDrone) { IEntity player = GetGame().GetPlayerController().GetControlledEntity(); if (!player) return; array loaded = {}; GameProject.GetLoadedAddons(loaded); PrintFormat("ERR DRONE DIAG loaded=%1 available=%2 server=%3", loaded, ERR_DroneBridge.Available(), Replication.IsServer()); bool compiled = ERR_DroneBridge.Initialize(); PrintFormat("ERR DRONE DIAG compiled=%1 ready=%2 manager=%3", compiled, ERR_DroneBridge.Ready(), SAL_DroneConnectionManager.GetInstance()); if (!compiled || !ERR_DroneBridge.Ready()) { ERR_TestDroneFail("optional adapter compiles and manager exists"); return; } Print("ERR SMOKE PASS: drone optional adapter compiled and manager exists"); ERR_DroneCatalog catalog = new ERR_DroneCatalog(); catalog.Find(); if (catalog.Prefab.IsEmpty()) { ERR_TestDroneFail("catalog prefab"); return; } vector pad; if (!ERR_ReconAirports.FindClearPad(player.GetOrigin() + Vector(150,0,0), pad)) { ERR_TestDroneFail("clear test pad"); return; } IEntity drone = ERR_Actors.Spawn(catalog.Prefab, pad); Own(drone); IEntity caller = ERR_Actors.Spawn("{C31F210ABE078199}Prefabs/ERR/ReconPilotWest.et", ERR_Actors.Ground(pad + Vector(3,0,0))); Own(caller); if (!drone || !caller) { ERR_TestDroneFail("native allocations"); return; } m_TestDrone = new ERR_DroneFlight(); m_TestDrone.Drone = drone; m_TestDrone.Operator = caller; m_TestDrone.Home = pad; m_TestDrone.Search = ERR_Actors.Ground(pad + Vector(100,0,0)); m_TestDrone.Created = now; m_TestStart = now; PrintFormat("ERR DRONE TEST start=%1 search=%2", pad, m_TestDrone.Search); return; } m_TestDrone.Advance(now); if (now >= m_TestLog) { m_TestLog = now + 5000; TraceParam linkTrace = new TraceParam(); linkTrace.Start = m_TestDrone.Drone.GetOrigin(); linkTrace.End = m_TestDrone.Operator.GetOrigin() + Vector(0,1.5,0); linkTrace.Exclude = m_TestDrone.Drone; linkTrace.Flags = TraceFlags.ENTS | TraceFlags.WORLD; float linkFraction = GetWorld().TraceMove(linkTrace,null); PrintFormat("ERR DRONE LINK live=%1 jam=%2 operator=%3 trace=%4 hit=%5 target=%6", ERR_Actors.CanFight(m_TestDrone.Operator), ERR_DroneBridge.Jammed(m_TestDrone.Drone), m_TestDrone.Operator.GetOrigin(), linkFraction, linkTrace.TraceEnt, m_TestDrone.Operator); PrintFormat("ERR DRONE TEST dt=%1 pos=%2 vel=%3 reason=%4", now-m_TestStart, m_TestDrone.Drone.GetOrigin(), m_TestDrone.Drone.GetPhysics().GetVelocity(), m_TestDrone.Reason); } if (m_TestDrone.Finished) { ERR_TestDroneFail("unexpected retirement " + m_TestDrone.Reason); return; } vector displacement = m_TestDrone.Drone.GetOrigin() - m_TestDrone.Home; if (!m_TestReturn && displacement[1] >= 30 && vector.DistanceXZ(m_TestDrone.Drone.GetOrigin(),m_TestDrone.Home) >= 30) { Print("ERR SMOKE PASS: drone native powered takeoff and horizontal search flight"); SAL_DroneControllerComponent c = SAL_DroneControllerComponent.Cast(m_TestDrone.Drone.FindComponent(SAL_DroneControllerComponent)); c.m_iOwner = 7; c.m_bIsConnected = true; m_TestDrone.Advance(now+50); if (!m_TestDrone.Finished || !c.m_bIsArmed || !ERR_Actors.Alive(m_TestDrone.Drone)) { ERR_TestDroneFail("takeover preservation"); return; } Print("ERR SMOKE PASS: drone takeover releases and preserves active aircraft"); c.m_iOwner = -1; c.m_bIsConnected = false; ERR_DroneBridge.Release(m_TestDrone.Drone); if(c.m_bIsArmed) { ERR_TestDroneFail("release disarms unowned drone"); return; } Print("ERR SMOKE PASS: drone unowned release disarms"); GetGame().GetCallqueue().Remove(ERR_TestDroneTick); Print("ERR SMOKE COMPLETE: drone-recon"); } if(now-m_TestStart > 100000) ERR_TestDroneFail("native powered flight deadline"); } } #endif