#ifdef WORKBENCH // Arranged local native fixture: protects test aircraft and crew, directly // dispatches production rescue, and passively measures native landing times. // No simulation/compartment override is used by the landing/boarding flow. modded class ERR_RescueFlightComponent { protected float m_ERRMeasuredLanding = -1, m_ERRMeasuredReady = -1, m_ERRMeasuredLanded = -1, m_ERRMeasureLog; protected float m_ERRMaximumDescent, m_ERRMaximumLateral, m_ERRMaximumTilt; override void Update(float now) { super.Update(now); if (m_Escort || m_Departing || !m_Aircraft || m_Phase < ERR_ReconPhase.LANDING) return; if (m_ERRMeasuredLanding < 0) { m_ERRMeasuredLanding = m_LandingStarted; PrintFormat("ERR RESCUE LANDING START serial=%1 time=%2 agl=%3 horizontal=%4 prefab=%5", m_Serial, m_ERRMeasuredLanding, m_Aircraft.GetOrigin()[1] - SCR_TerrainHelper.GetTerrainY(m_Aircraft.GetOrigin(), GetGame().GetWorld(), noUnderwater: true), vector.DistanceXZ(m_Aircraft.GetOrigin(), LandingTarget()), m_Aircraft.GetPrefabData().GetPrefabName()); } Physics physics = m_Aircraft.GetPhysics(); if (!physics) return; vector velocity = physics.GetVelocity(); vector angles = m_Aircraft.GetYawPitchRoll(); vector horizontal = velocity; horizontal[1] = 0; m_ERRMaximumDescent = Math.Max(m_ERRMaximumDescent, -velocity[1]); m_ERRMaximumLateral = Math.Max(m_ERRMaximumLateral, horizontal.Length()); m_ERRMaximumTilt = Math.Max(m_ERRMaximumTilt, Math.Max(Math.AbsFloat(angles[1]), Math.AbsFloat(angles[2]))); bool ready = ERR_CasualtyLoadingRules.AircraftReady(m_Aircraft); if (ready && m_ERRMeasuredReady < 0) { m_ERRMeasuredReady = now; ERR_FixtureLandingTelemetry(now, "physical-ready"); } if (now >= m_ERRMeasureLog && m_ERRMeasuredLanded < 0) { m_ERRMeasureLog = now + 1000; ERR_FixtureLandingTelemetry(now, "flight"); } } override bool Landed() { bool landed = super.Landed(); if (landed && m_ERRMeasuredLanded < 0 && m_ERRMeasuredLanding >= 0) { float now = GetGame().GetWorld().GetWorldTime(); m_ERRMeasuredLanded = now; ERR_FixtureLandingTelemetry(now, "boardable"); PrintFormat("ERR RESCUE LANDING RESULT serial=%1 landingSeconds=%2 physicalReadySeconds=%3 maxSampledDescent=%4 maxSampledLateral=%5 maxSampledTiltDegrees=%6", m_Serial, (now - m_ERRMeasuredLanding) / 1000, (m_ERRMeasuredReady - m_ERRMeasuredLanding) / 1000, m_ERRMaximumDescent, m_ERRMaximumLateral, m_ERRMaximumTilt); } return landed; } void ERR_FixtureLandingTelemetry(float now, string sampleKind) { Physics physics = m_Aircraft.GetPhysics(); HelicopterControllerComponent controller = HelicopterControllerComponent.Cast(m_Aircraft.FindComponent(HelicopterControllerComponent)); VehicleHelicopterSimulation simulation; if (controller) simulation = controller.GetSimulation(); vector transform[4]; m_Aircraft.GetWorldTransform(transform); PrintFormat("ERR RESCUE LANDING SAMPLE serial=%1 event=%2 elapsed=%3 time=%4 position=%5 velocity=%6 angular=%7 up=%8 phase=%9", m_Serial, sampleKind, (now - m_ERRMeasuredLanding) / 1000, now, m_Aircraft.GetOrigin(), physics.GetVelocity(), physics.GetAngularVelocity(), transform[1][1], Phase()); PrintFormat("ERR RESCUE LANDING SUPPORT serial=%1 event=%2 elapsed=%3 nativeContact=%4 support=%5 awake=%6 engine=%7 ready=%8", m_Serial, sampleKind, (now - m_ERRMeasuredLanding) / 1000, simulation && simulation.HasAnyGroundContact(), ERR_CasualtyGroundSupport.Parked(m_Aircraft), physics.IsActive(), simulation && simulation.EngineIsOn(), ERR_CasualtyLoadingRules.AircraftReady(m_Aircraft)); } int ERR_FixtureCargo() { return CargoCapacity(m_Aircraft); } void ERR_FixtureProtect() { DamageManagerComponent damage = DamageManagerComponent.Cast(m_Aircraft.FindComponent(DamageManagerComponent)); if (damage) damage.EnableDamageHandling(false); foreach (IEntity actor : m_OriginalCrew) { if (!actor) continue; damage = DamageManagerComponent.Cast(actor.FindComponent(DamageManagerComponent)); if (damage) damage.EnableDamageHandling(false); } } BaseCompartmentSlot ERR_FixturePassengerSeat() { array seats = {}; CargoSeats(m_Aircraft, seats); if (seats.IsEmpty()) return null; return seats[0]; } } modded class ERR_CasualtyLoadingService { BaseCompartmentSlot ERR_FixtureAvailableSeat(IEntity patient, Vehicle aircraft) { return AvailableSeat(patient, aircraft); } } modded class ERR_ExtractionService { protected override bool Approach(out vector position) { string scope; System.GetCLIParam("errRescueFixtureScope", scope); if (scope != "flight-short") return super.Approach(position); position = ERR_Actors.Ground(m_Pickup + "400 0 0") + "0 80 0"; PrintFormat("ERR RESCUE FACTION ARRANGED: shortened initial approach origin=%1; native flight and landing untouched", position); return true; } void ERR_FixtureDispatch() { m_Signal = true; } bool ERR_FixturePads() { return LandingPads(); } bool ERR_FixtureAirportPickup(vector position) { if (!ERR_AirfieldPlacement.ClearGround(position)) return false; m_Pickup = position; m_TransportPickups.Clear(); m_TransportPickups.Insert(position); return LandingPads(); } } modded class ERR_GameMode { protected string m_ERRFixtureFactionId, m_ERRFixtureFactionKey; protected int m_ERRFixtureTransportCount; protected int m_ERRFixtureStep; protected string m_ERRFixtureScope; protected float m_ERRFixtureDeadline, m_ERRFixtureWait, m_ERRFixtureNextLog; protected float m_ERRFixtureDepartureDeadline, m_ERRFixtureDepartureLog; protected IEntity m_ERRFixturePlayer, m_ERRFixtureCasualty; protected BaseCompartmentSlot m_ERRFixtureCasualtySeat; protected Vehicle m_ERRFixtureFirst, m_ERRFixtureSecond; protected bool m_ERRFixturePadsReady; protected ref ERR_ReconAirports m_ERRFixtureAirports; protected SCR_CompartmentAccessComponent m_ERRFixtureCasualtyAccess; protected override void EOnInit(IEntity owner) { super.EOnInit(owner); string enabled, outcome; if (SCR_Global.IsEditMode() || !Replication.IsServer() || !System.GetCLIParam("errBaseSmoke", enabled) || enabled != "1" || !System.GetCLIParam("errSmokeOutcome", outcome) || outcome != "rescue-faction") return; System.GetCLIParam("errRescueFixtureScope", m_ERRFixtureScope); System.GetCLIParam("errRescueFixtureFaction", m_ERRFixtureFactionId); m_ERRFixtureFactionKey = "US"; if (m_ERRFixtureFactionId == "fia") m_ERRFixtureFactionKey = "FIA"; m_ERRFixtureTransportCount = ERR_RescueAssets.TransportCount(m_ERRFixtureFactionKey); m_ERRFixtureDeadline = System.GetTickCount() + 540000; GetGame().GetCallqueue().CallLater(ERR_RescueFactionTick, 250, true); } protected bool ERR_RescueFactionCheck(bool value, string detail) { if (value) { Print("ERR SMOKE PASS: rescue-faction " + detail); return true; } Print("ERR SMOKE FAIL: rescue-faction " + detail, LogLevel.ERROR); GetGame().GetCallqueue().Remove(ERR_RescueFactionTick); return false; } protected void ERR_RescueFactionMove(vector position) { vector transform[4]; m_ERRFixturePlayer.GetWorldTransform(transform); transform[3] = ERR_Actors.Ground(position); ChimeraCharacter.Cast(m_ERRFixturePlayer).Teleport(transform); } protected void ERR_RescueFactionTrace(float now) { if (now < m_ERRFixtureNextLog) return; m_ERRFixtureNextLog = now + 10000; foreach (IEntity entity : m_OwnedEntities) { if (!entity) continue; ERR_RescueFlightComponent flight = ERR_RescueFlightComponent.Cast(entity.FindComponent(ERR_RescueFlightComponent)); if (flight) PrintFormat("ERR RESCUE FACTION TRACE step=%1 stage=%2 prefab=%3 pos=%4 status=%5 cargo=%6", m_ERRFixtureStep, PickupStage(), entity.GetPrefabData().GetPrefabName(), entity.GetOrigin(), flight.Status(), flight.ERR_FixtureCargo()); } } protected void ERR_RescueFactionTick() { if (System.GetTickCount() > m_ERRFixtureDeadline) { ERR_RescueFactionCheck(false, "overall fixture deadline"); return; } if (!PreparationError().IsEmpty() || Phase() == ERR_Phase.DEFEAT) { ERR_RescueFactionCheck(false, "mission failed: " + PreparationError()); return; } if (!Active()) return; float now = GetWorld().GetWorldTime(); if (!m_ERRFixturePlayer) { PlayerController controller = GetGame().GetPlayerController(); if (!controller || !controller.GetControlledEntity() || !Extraction().PickupConfigured() || Phase() != ERR_Phase.PRISON) return; m_ERRFixturePlayer = controller.GetControlledEntity(); DamageManagerComponent.Cast(m_ERRFixturePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false); if (!ERR_RescueFactionCheck(PlayerFaction().GetFactionKey() == m_ERRFixtureFactionKey, "normal profile selected rescue faction " + m_ERRFixtureFactionKey)) return; if (m_ERRFixtureScope == "preparation") { if (!ERR_RescueFactionCheck(Extraction().ERR_FixturePads(), "current production preparation retains two surveyed landing pads")) return; Print("ERR SMOKE COMPLETE: rescue-faction final source compilation and production dual-pad preparation at arranged flat input"); GetGame().GetCallqueue().Remove(ERR_RescueFactionTick); return; } } foreach (IEntity entity : m_OwnedEntities) { if (!entity) continue; ERR_RescueFlightComponent flight = ERR_RescueFlightComponent.Cast(entity.FindComponent(ERR_RescueFlightComponent)); if (flight) flight.ERR_FixtureProtect(); } if (now < m_ERRFixtureWait) return; if (m_ERRFixtureStep == 0) { m_ERRFixtureStep = 1; } ERR_RescueFactionTrace(now); if (m_ERRFixtureStep == 1) { if (!m_ERRFixturePadsReady) { if (!m_ERRFixtureAirports && Extraction().ERR_FixturePads()) m_ERRFixturePadsReady = true; else { if (!m_ERRFixtureAirports) { PrintFormat("ERR RESCUE FACTION ARRANGED: original pickup %1 lacks a second surveyed pad; flight fixture will use surveyed airport grounds", Extraction().PickupPosition()); m_ERRFixtureAirports = new ERR_ReconAirports(); } for (int tile = 0; tile < 8; tile++) if (!m_ERRFixtureAirports.Complete()) m_ERRFixtureAirports.Update(); if (!m_ERRFixtureAirports.Complete()) return; foreach (vector centre : m_ERRFixtureAirports.m_Positions) { for (int band = 0; band < 4 && !m_ERRFixturePadsReady; band++) for (int bearing = 0; bearing < 16 && !m_ERRFixturePadsReady; bearing++) { float angle = bearing * Math.PI2 / 16; vector candidate = ERR_Actors.Ground(centre + Vector(Math.Cos(angle), 0, Math.Sin(angle)) * (band * 80)); if (Extraction().ERR_FixtureAirportPickup(candidate)) m_ERRFixturePadsReady = true; } if (m_ERRFixturePadsReady) break; } if (!ERR_RescueFactionCheck(m_ERRFixturePadsReady, "arranged airport pickup has two production-surveyed landing footprints")) return; } } if (!ERR_RescueFactionCheck(Transition(ERR_Phase.RADIO_SEARCH) && Transition(ERR_Phase.RADIO_DEFENCE) && Transition(ERR_Phase.EXTRACTION), "arranged valid phase path enables native rescue flight")) return; Extraction().OpenPickup(); Extraction().ERR_FixtureDispatch(); m_ERRFixtureStep = 10; return; } if (m_ERRFixtureStep == 10) { if (PickupStage() != 3) return; array vehicles = {}; Extraction().Vehicles(vehicles); if (!ERR_RescueFactionCheck(vehicles.Count() == m_ERRFixtureTransportCount, "production dispatch registers expected transport count " + m_ERRFixtureTransportCount.ToString())) return; m_ERRFixtureFirst = vehicles[0]; m_ERRFixtureSecond = vehicles[vehicles.Count() - 1]; m_ERRFixtureStep = 2; return; } if (m_ERRFixtureStep == 2) { if (PickupStage() != 4) return; int coverCount; foreach (IEntity coverEntity : m_OwnedEntities) { if (!coverEntity || !Vehicle.Cast(coverEntity) || Extraction().IsTransport(Vehicle.Cast(coverEntity))) continue; ERR_RescueFlightComponent cover = ERR_RescueFlightComponent.Cast(coverEntity.FindComponent(ERR_RescueFlightComponent)); if (cover && !cover.Lost() && cover.Phase() == ERR_ReconPhase.SEARCH && SCR_FactionManager.SGetFaction(coverEntity) == PlayerFaction()) coverCount++; } if (!ERR_RescueFactionCheck(coverCount == 2, "both friendly armed escorts remain airborne during pickup")) return; if (!ERR_RescueFactionCheck(ERR_CasualtyLoadingRules.AircraftReady(m_ERRFixtureFirst) && ERR_CasualtyLoadingRules.AircraftReady(m_ERRFixtureSecond), "all registered transports physically landed upright and stationary")) return; if (m_ERRFixtureTransportCount > 1 && !ERR_RescueFactionCheck(vector.DistanceXZ(m_ERRFixtureFirst.GetOrigin(), m_ERRFixtureSecond.GetOrigin()) >= 30, "actual transport landing positions keep rotor discs separated")) return; vector patientPosition = ERR_Actors.Ground(m_ERRFixtureSecond.GetOrigin() + "6 0 0"); m_ERRFixtureCasualty = ERR_Actors.Spawn(Factions().PrisonerPrefab, patientPosition); Own(m_ERRFixtureCasualty); if (!ERR_RescueFactionCheck(m_ERRFixtureCasualty != null, "independent living fixture survivor created beside last registered transport")) return; m_ERRFixtureCasualtyAccess = SCR_CompartmentAccessComponent.Cast(m_ERRFixtureCasualty.FindComponent(SCR_CompartmentAccessComponent)); SCR_CharacterDamageManagerComponent damage = SCR_CharacterDamageManagerComponent.Cast(m_ERRFixtureCasualty.FindComponent(SCR_CharacterDamageManagerComponent)); if (!ERR_RescueFactionCheck(m_ERRFixtureCasualtyAccess && damage, "native casualty components present")) return; damage.ForceUnconsciousness(); damage.EnableDamageHandling(false); ERR_RescueFactionMove(patientPosition + "2 0 0"); m_ERRFixtureWait = now + 6000; m_ERRFixtureStep = 3; return; } if (m_ERRFixtureStep == 3) { if (!ERR_RescueFactionCheck(ERR_Actors.Alive(m_ERRFixtureCasualty) && !ERR_Actors.CanFight(m_ERRFixtureCasualty) && !CompartmentAccessComponent.GetVehicleIn(m_ERRFixtureCasualty), "patient is already unconscious on ground before cargo request")) return; if (!ERR_RescueFactionCheck(CasualtyLoadingAircraftFor(m_ERRFixturePlayer, m_ERRFixtureCasualty) == m_ERRFixtureSecond, "production casualty selection chooses the nearby last registered transport")) return; ERR_RescueFlightComponent second = ERR_RescueFlightComponent.Cast(m_ERRFixtureSecond.FindComponent(ERR_RescueFlightComponent)); BaseCompartmentManagerComponent manager = BaseCompartmentManagerComponent.Cast(m_ERRFixtureSecond.FindComponent(BaseCompartmentManagerComponent)); array rootSeats = {}; if (manager) manager.GetCompartments(rootSeats); int rootCargo, rootBenches; foreach (BaseCompartmentSlot rootSeat : rootSeats) { if (rootSeat && rootSeat.GetType() == ECompartmentType.CARGO && rootSeat.IsCompartmentAccessible() && !rootSeat.IsOccupied() && !rootSeat.IsReserved() && !rootSeat.IsGetInLockedFor(m_ERRFixtureCasualty)) rootCargo++; if (ERR_CasualtyLoadingRules.TransportBench(rootSeat, m_ERRFixtureSecond)) rootBenches++; } PrintFormat("ERR RESCUE FACTION ROOT SEATS total=%1 freeCargo=%2 auditedBenches=%3 recursiveFreeCargo=%4", rootSeats.Count(), rootCargo, rootBenches, second.ERR_FixtureCargo()); if (!ERR_RescueFactionCheck(rootCargo >= ERR_RescueAssets.TransportSeats(m_ERRFixtureFactionKey) && rootBenches == rootCargo, "native root manager enumerates all audited accessible transport cargo benches")) return; if (!ERR_RescueFactionCheck(ERR_CasualtyFeedback.PhysicalReason(this, m_ERRFixturePlayer, m_ERRFixtureCasualty).IsEmpty(), "production physical feedback accepts native ground casualty beside last registered transport")) return; m_ERRFixtureCasualtySeat = CasualtyLoading().ERR_FixtureAvailableSeat(m_ERRFixtureCasualty, m_ERRFixtureSecond); if (!ERR_RescueFactionCheck(m_ERRFixtureCasualtySeat && ERR_CasualtyLoadingRules.TransportBench(m_ERRFixtureCasualtySeat, m_ERRFixtureSecond), "production casualty service selects an audited seat in last registered transport")) return; if (!ERR_RescueFactionCheck(m_ERRFixtureCasualtySeat != null && m_ERRFixtureCasualtyAccess.MoveInVehicle(m_ERRFixtureSecond, ECompartmentType.CARGO, false, m_ERRFixtureCasualtySeat), "native unconscious cargo loading accepted by last registered transport")) return; m_ERRFixtureWait = now + 2000; m_ERRFixtureStep = 4; return; } if (m_ERRFixtureStep == 4) { if (!ERR_RescueFactionCheck(CompartmentAccessComponent.GetVehicleIn(m_ERRFixtureCasualty) == m_ERRFixtureSecond && m_ERRFixtureCasualtySeat.GetOccupant() == m_ERRFixtureCasualty && ERR_Actors.Alive(m_ERRFixtureCasualty) && !ERR_Actors.CanFight(m_ERRFixtureCasualty), "living unconscious casualty physically occupies exact cargo seat in last registered transport")) return; if (!ERR_RescueFactionCheck(m_Roster.Bind(10210, "00e77200-0000-0000-0000-000000000210"), "isolated casualty fixture identity registered for fleet departure")) return; m_Roster.Spawned(10210, m_ERRFixtureCasualty); ERR_RescueFactionMove(m_ERRFixtureFirst.GetOrigin() + "6 0 0"); CompartmentAccessComponent access = CompartmentAccessComponent.Cast(m_ERRFixturePlayer.FindComponent(CompartmentAccessComponent)); ERR_RescueFlightComponent first = ERR_RescueFlightComponent.Cast(m_ERRFixtureFirst.FindComponent(ERR_RescueFlightComponent)); BaseCompartmentSlot seat = first.ERR_FixturePassengerSeat(); if (!ERR_RescueFactionCheck(access && seat && access.GetInVehicle(seat.GetOwner(), seat, true, -1, ECloseDoorAfterActions.INVALID, false), "original controlled player boards first transport through native cargo access")) return; m_ERRFixtureWait = now + 15000; m_ERRFixtureStep = 5; return; } if (m_ERRFixtureStep == 5) { if (!ERR_RescueFactionCheck(CompartmentAccessComponent.GetVehicleIn(m_ERRFixturePlayer) == m_ERRFixtureFirst && CompartmentAccessComponent.GetVehicleIn(m_ERRFixtureCasualty) == m_ERRFixtureSecond, "original player and living wounded survivor remain physically retained in their assigned transports")) return; if (!ERR_RescueFactionCheck(PickupStage() == 5 && Extraction().CarryingSurvivorsToSafety(), "production eight-second boarding hold accepts survivors aboard the registered fleet")) return; m_ERRFixtureDepartureDeadline = now + 45000; m_ERRFixtureStep = 6; } if (m_ERRFixtureStep == 6) { bool bothAirborne = true; array departing = {}; Extraction().Vehicles(departing); foreach (int index, Vehicle aircraft : departing) { Physics physics = aircraft.GetPhysics(); HelicopterControllerComponent controller = HelicopterControllerComponent.Cast(aircraft.FindComponent(HelicopterControllerComponent)); VehicleHelicopterSimulation simulation; if (controller) simulation = controller.GetSimulation(); ERR_RescueFlightComponent flight = ERR_RescueFlightComponent.Cast(aircraft.FindComponent(ERR_RescueFlightComponent)); if (!flight || flight.Lost()) { ERR_RescueFactionCheck(false, "departure must retain original living transport " + index.ToString()); return; } float altitude = aircraft.GetOrigin()[1] - SCR_TerrainHelper.GetTerrainY(aircraft.GetOrigin(), GetWorld(), noUnderwater: true); vector velocity; if (physics) velocity = physics.GetVelocity(); bool climbing = simulation && simulation.EngineIsOn() && !simulation.HasAnyGroundContact() && altitude > 10 && velocity[1] > 0.5; if (!climbing) bothAirborne = false; if (now >= m_ERRFixtureDepartureLog) PrintFormat("ERR RESCUE FACTION DEPARTURE aircraft=%1 engineOn=%2 contact=%3 physicsVelocity=%4 agl=%5 phase=%6 climbing=%7 physicsActive=%8", index, simulation && simulation.EngineIsOn(), simulation && simulation.HasAnyGroundContact(), velocity, altitude, flight.Status(), climbing, physics && physics.IsActive()); } if (now >= m_ERRFixtureDepartureLog) m_ERRFixtureDepartureLog = now + 1000; if (!bothAirborne) { if (now >= m_ERRFixtureDepartureDeadline) ERR_RescueFactionCheck(false, "all loaded transports must climb above ten metres without native ground contact before departure deadline"); return; } if (!ERR_RescueFactionCheck(CompartmentAccessComponent.GetVehicleIn(m_ERRFixturePlayer) == m_ERRFixtureFirst && CompartmentAccessComponent.GetVehicleIn(m_ERRFixtureCasualty) == m_ERRFixtureSecond && ERR_Actors.Alive(m_ERRFixtureCasualty), "all transports genuinely airborne and climbing above ten metres with original survivors retained")) return; Print("ERR SMOKE COMPLETE: rescue faction scope=" + m_ERRFixtureScope + " faction=" + m_ERRFixtureFactionKey + " measured landing, wounded boarding and verified airborne departure; arranged local fixture, not dedicated multiplayer or boundary qualification"); GetGame().GetCallqueue().Remove(ERR_RescueFactionTick); } } } #endif