Files
EscapistsReintroduced/docs/evidence/rescue-landing-2026-10-13/native-fixture.c
T
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

307 lines
20 KiB
C

#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<BaseCompartmentSlot> 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<Vehicle> 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<BaseCompartmentSlot> 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<Vehicle> 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