Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
183 lines
9.4 KiB
C
183 lines
9.4 KiB
C
#ifdef WORKBENCH
|
|
// Explicit isolated fixture. Native seating, dismounts, retries and release are
|
|
// observed; the runway, escaped phase and fault injection are arranged inputs.
|
|
class ERR_CessnaBoardingFixtureFlight : ERR_PlaneFlight
|
|
{
|
|
int TestMode;
|
|
int Dismounts;
|
|
int MaximumAttempts;
|
|
float LastAttemptAt;
|
|
float MinimumAttemptGap = 100000;
|
|
bool FaultFailed;
|
|
protected override bool PrepareCrewSeat(ERR_PlaneCrewSeat entry, int index, float now)
|
|
{
|
|
int before = entry.Attempts;
|
|
bool ready = super.PrepareCrewSeat(entry, index, now);
|
|
if (index == 0 && entry.Attempts != before)
|
|
{
|
|
if (LastAttemptAt > 0) MinimumAttemptGap = Math.Min(MinimumAttemptGap, now - LastAttemptAt);
|
|
LastAttemptAt = now; MaximumAttempts = entry.Attempts;
|
|
}
|
|
if (TestMode == 1 && index == 0 && ready && Dismounts < 3)
|
|
{
|
|
CompartmentAccessComponent access = CompartmentAccessComponent.Cast(entry.Actor.FindComponent(CompartmentAccessComponent));
|
|
bool accepted = access && access.GetOutVehicle(EGetOutType.TELEPORT, -1, ECloseDoorAfterActions.INVALID, false);
|
|
PrintFormat("ERR CESSNA INJECT native dismount accepted=%1 attempt=%2", accepted, entry.Attempts);
|
|
if (!accepted) FaultFailed = true;
|
|
Dismounts++;
|
|
return false;
|
|
}
|
|
// Keep the capture case in preparation after native seating, so takeover is
|
|
// tested while retries are still enabled rather than during established flight.
|
|
if (TestMode >= 2) return false;
|
|
return ready;
|
|
}
|
|
bool OriginalCrewReady()
|
|
{
|
|
if (m_CrewSeats.Count() != 2 || Actors.Count() != 2) return false;
|
|
foreach (ERR_PlaneCrewSeat entry : m_CrewSeats)
|
|
if (!OwnsCrewSeat(entry) || !CrewSeated(entry) || entry.Agent.GetLOD() != 0 || !entry.Agent.IsAIActivated()) return false;
|
|
return true;
|
|
}
|
|
bool RatesRestored()
|
|
{
|
|
vector actual;
|
|
return Aircraft && !m_HeldInputs && ERR_CessnaBridge.Rates(Aircraft, m_InputRates, actual) && actual == m_InputRates;
|
|
}
|
|
void FixtureDelete()
|
|
{
|
|
Stop();
|
|
foreach (IEntity actor : Actors) if (actor) SCR_EntityHelper.DeleteEntityAndChildren(actor);
|
|
Actors.Clear(); m_CrewSeats.Clear(); Pilot = null;
|
|
if (Crew) SCR_EntityHelper.DeleteEntityAndChildren(Crew);
|
|
Crew = null;
|
|
if (Aircraft) SCR_EntityHelper.DeleteEntityAndChildren(Aircraft);
|
|
Aircraft = null;
|
|
}
|
|
}
|
|
modded class ERR_PlaneRecon
|
|
{
|
|
void ERR_BoardingFixtureInstall(ERR_PlaneFlight flight)
|
|
{
|
|
if (m_Current) m_Current.Stop();
|
|
m_Checked = true; m_Enabled = false; m_Current = flight;
|
|
}
|
|
}
|
|
modded class ERR_GameMode
|
|
{
|
|
protected ref ERR_CessnaBoardingFixtureFlight m_ERRBoardingFlight;
|
|
protected ref ERR_CessnaCatalog m_ERRBoardingCatalog;
|
|
protected ref ERR_PlaneRunway m_ERRBoardingRunway;
|
|
protected int m_ERRBoardingCase;
|
|
protected float m_ERRBoardingDeadline, m_ERRBoardingStarted, m_ERRCaptureAt;
|
|
protected bool m_ERRBoardingReady, m_ERRPilotKilled;
|
|
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 != "plane-boarding") return;
|
|
m_ERRBoardingDeadline = System.GetTickCount() + 250000;
|
|
OnStop().Insert(ERR_BoardingFixtureStop);
|
|
GetGame().GetCallqueue().CallLater(ERR_BoardingFixtureTick, 100, true);
|
|
}
|
|
protected bool ERR_BoardingCheck(bool value, string detail)
|
|
{
|
|
if (value) { Print("ERR SMOKE PASS: cessna " + detail); return true; }
|
|
Print("ERR SMOKE FAIL: cessna " + detail, LogLevel.ERROR); ERR_BoardingFixtureStop(); return false;
|
|
}
|
|
protected void ERR_BoardingFixtureStop()
|
|
{
|
|
GetGame().GetCallqueue().Remove(ERR_BoardingFixtureTick);
|
|
if (m_ERRBoardingFlight) m_ERRBoardingFlight.FixtureDelete();
|
|
}
|
|
protected bool ERR_BoardingFixtureStart(int kind, float now)
|
|
{
|
|
m_ERRBoardingCase = kind; m_ERRBoardingStarted = now; m_ERRBoardingReady = false;
|
|
if (m_ERRBoardingFlight) m_ERRBoardingFlight.FixtureDelete();
|
|
m_ERRBoardingFlight = new ERR_CessnaBoardingFixtureFlight(); m_ERRBoardingFlight.TestMode = kind;
|
|
ERR_HQ.Get().PlaneRecon().ERR_BoardingFixtureInstall(m_ERRBoardingFlight);
|
|
return ERR_BoardingCheck(m_ERRBoardingFlight.Start(this, m_ERRBoardingCatalog.Prefab, m_ERRBoardingRunway.Position, m_ERRBoardingRunway.Heading), "starts original West crew case=" + kind.ToString());
|
|
}
|
|
protected void ERR_BoardingFixtureTick()
|
|
{
|
|
if (System.GetTickCount() > m_ERRBoardingDeadline) { ERR_BoardingCheck(false, "overall fixture deadline"); return; }
|
|
if (!Active() || !ERR_HQ.Get()) return;
|
|
float now = GetWorld().GetWorldTime();
|
|
if (!m_ERRBoardingCatalog)
|
|
{
|
|
if (Phase() != ERR_Phase.PRISON || !GetGame().GetPlayerController() || !GetGame().GetPlayerController().GetControlledEntity()) return;
|
|
if (!ERR_BoardingCheck(EnemyFaction().GetFactionKey() == "US", "normal faction settings selected US/West enemy")) return;
|
|
if (!ERR_BoardingCheck(ERR_CessnaBridge.Available() && ERR_CessnaBridge.Initialize(), "optional installed addon bridge loads")) return;
|
|
m_ERRBoardingCatalog = new ERR_CessnaCatalog(); m_ERRBoardingCatalog.Find();
|
|
if (!ERR_BoardingCheck(!m_ERRBoardingCatalog.Prefab.IsEmpty(), "installed Cessna prefab resolves")) return;
|
|
Transition(ERR_Phase.RADIO_SEARCH);
|
|
if (!ERR_BoardingCheck(Phase() == ERR_Phase.RADIO_SEARCH, "preparation runs after arranged prison escape")) return;
|
|
m_ERRBoardingRunway = new ERR_PlaneRunway(); return;
|
|
}
|
|
if (!m_ERRBoardingFlight)
|
|
{
|
|
if (!m_ERRBoardingRunway.Tick())
|
|
{
|
|
if (m_ERRBoardingRunway.Exhausted) ERR_BoardingCheck(false, "native airport survey finds a departure corridor");
|
|
return;
|
|
}
|
|
PrintFormat("ERR CESSNA RUNWAY position=%1 heading=%2", m_ERRBoardingRunway.Position, m_ERRBoardingRunway.Heading);
|
|
ERR_BoardingFixtureStart(0, now); return;
|
|
}
|
|
if (m_ERRBoardingCase == 0)
|
|
{
|
|
if (m_ERRBoardingFlight.Lost || m_ERRBoardingFlight.Captured) { ERR_BoardingCheck(false, "normal flight retains crew ownership"); return; }
|
|
if (!m_ERRBoardingReady && m_ERRBoardingFlight.OriginalCrewReady())
|
|
{
|
|
m_ERRBoardingReady = true;
|
|
if (!ERR_BoardingCheck(true, "both original West crew occupy exact assigned seats with LOD0 and active agents")) return;
|
|
}
|
|
if (!m_ERRBoardingFlight.Airborne()) return;
|
|
if (!ERR_BoardingCheck(m_ERRBoardingReady && m_ERRBoardingFlight.EnteredService(), "native engine start and airport takeoff after verified seating")) return;
|
|
ERR_BoardingFixtureStart(1, now); return;
|
|
}
|
|
if (m_ERRBoardingCase == 1)
|
|
{
|
|
if (m_ERRBoardingFlight.FaultFailed) { ERR_BoardingCheck(false, "native dismount fault injection accepted"); return; }
|
|
if (m_ERRBoardingFlight.EnteredService()) { ERR_BoardingCheck(false, "unseated pilot must block service"); return; }
|
|
if (!m_ERRBoardingFlight.Lost) return;
|
|
if (!ERR_BoardingCheck(m_ERRBoardingFlight.Dismounts == 3 && m_ERRBoardingFlight.MaximumAttempts == 3, "three real native seatings/dismounts exhaust the original pilot retry budget")) return;
|
|
if (!ERR_BoardingCheck(m_ERRBoardingFlight.MinimumAttemptGap >= 5000, "native boarding retries retain five second cooldown")) return;
|
|
if (!ERR_BoardingCheck(now - m_ERRBoardingStarted >= 45000 && now - m_ERRBoardingStarted < 46500, "original 45 second preparation deadline remains bounded")) return;
|
|
if (!ERR_BoardingCheck(!m_ERRBoardingFlight.Aircraft && !m_ERRBoardingFlight.Crew && m_ERRBoardingFlight.Actors.IsEmpty(), "failed setup cleans original aircraft and crew")) return;
|
|
ERR_BoardingFixtureStart(2, now); return;
|
|
}
|
|
if (m_ERRBoardingCase == 3)
|
|
{
|
|
if (m_ERRBoardingFlight.Captured) { ERR_BoardingCheck(false, "dead original pilot is a preparation failure, not capture"); return; }
|
|
if (!m_ERRPilotKilled)
|
|
{
|
|
if (!m_ERRBoardingFlight.OriginalCrewReady()) return;
|
|
DamageManagerComponent damage = DamageManagerComponent.Cast(m_ERRBoardingFlight.Pilot.FindComponent(DamageManagerComponent));
|
|
if (!ERR_BoardingCheck(damage != null, "original pilot damage manager resolves")) return;
|
|
damage.SetHealthScaled(0); m_ERRPilotKilled = true;
|
|
Print("ERR CESSNA INJECT original pilot killed during preparation"); return;
|
|
}
|
|
if (!m_ERRBoardingFlight.Lost) return;
|
|
if (!ERR_BoardingCheck(!m_ERRBoardingFlight.EnteredService() && !m_ERRBoardingFlight.Aircraft && !m_ERRBoardingFlight.Crew, "dead pilot reaches normal preparation failure and cleanup without a replacement actor")) return;
|
|
ERR_BoardingFixtureStop();
|
|
Print("ERR SMOKE COMPLETE: cessna West crew native seating after escaped phase, bounded dismount/retry failure, preparation capture release and dead pilot cleanup; arranged fixture, not multiplayer qualification");
|
|
return;
|
|
}
|
|
if (m_ERRCaptureAt == 0)
|
|
{
|
|
if (m_ERRBoardingFlight.Lost) { ERR_BoardingCheck(false, "capture setup survives native preparation"); return; }
|
|
if (!m_ERRBoardingFlight.OriginalCrewReady()) return;
|
|
if (!ERR_BoardingCheck(!m_ERRBoardingFlight.EnteredService() && ERR_Actors.SetFaction(m_ERRBoardingFlight.Pilot, PlayerFaction()), "arranges pilot faction takeover during preparation")) return;
|
|
m_ERRCaptureAt = now; return;
|
|
}
|
|
if (now - m_ERRCaptureAt < 5500) return;
|
|
m_ERRBoardingFlight.CancelSetup();
|
|
if (!ERR_BoardingCheck(m_ERRBoardingFlight.Captured && !m_ERRBoardingFlight.Lost && !m_ERRBoardingFlight.EnteredService(), "preparation takeover releases before another retry")) return;
|
|
if (!ERR_BoardingCheck(ERR_Actors.Alive(m_ERRBoardingFlight.Aircraft) && m_ERRBoardingFlight.Actors.Count() == 2 && m_ERRBoardingFlight.RatesRestored(), "takeover preserves aircraft/crew and restores original controls")) return;
|
|
ERR_BoardingFixtureStart(3, now);
|
|
}
|
|
}
|
|
#endif
|