Integrate startup optics and supply vehicle lock picking

This commit is contained in:
2026-09-20 05:34:30 +02:00
parent 9205e2129a
commit 963cab50c0
104 changed files with 16171 additions and 25 deletions
@@ -59,6 +59,7 @@ class ERR_NativeConvoyRoadSurvey
class ERR_NativeConvoyProbe
{
protected ERR_GameMode m_Mode;
protected ref ERR_NativeConvoyCoverProbe m_Cover;
protected ref ERR_ConvoyTask m_Task;
protected ref array<vector> m_Origins = {};
protected ref array<IEntity> m_OriginalVehicles = {};
@@ -165,6 +166,38 @@ class ERR_NativeConvoyProbe
PrintFormat("ERR CONVOY MOTION: vehicle=%1 groupAction=%2 driverBehavior=%3", i, groupAction, driverBehavior);
}
}
// Failure-only readout distinguishes incapacitation, ownership, native seat
// switching and dismounts without changing the exact original-seat assertion.
protected void SeatDiagnostic(ERR_ConvoyVehicle vehicle, int index, IEntity actor, BaseCompartmentSlot intended, bool duplicateActor, bool duplicateSeat)
{
IEntity aboard, occupant;
SCR_AIGroup actualGroup;
BaseCompartmentSlot actual;
ChimeraCharacter character = ChimeraCharacter.Cast(actor);
if (actor) { aboard = CompartmentAccessComponent.GetVehicleIn(actor); actualGroup = ERR_Actors.Group(actor); }
if (intended) occupant = intended.GetOccupant();
if (character && character.GetCompartmentAccessComponent()) actual = character.GetCompartmentAccessComponent().GetCompartment();
int intendedType = -1, actualType = -1, actualManager = -1, actualSlot = -1;
if (intended) intendedType = intended.GetType();
if (actual) { actualType = actual.GetType(); actualManager = actual.GetCompartmentMgrID(); actualSlot = actual.GetCompartmentSlotID(); }
PrintFormat("ERR CONVOY SEAT: vehicle=%1 member=%2 actor=%3 alive=%4 conscious=%5 groupMatches=%6 duplicateActor=%7 duplicateSeat=%8",
vehicle.Index, index, actor, ERR_Actors.Alive(actor), ERR_Actors.CanFight(actor), actualGroup == vehicle.Group, duplicateActor, duplicateSeat);
PrintFormat("ERR CONVOY SEAT: intended=%1 occupant=%2 type=%3 actual=%4 actualType=%5 manager=%6 slot=%7 sameSeat=%8",
intended, occupant, intendedType, actual, actualType, actualManager, actualSlot, actual == intended);
PrintFormat("ERR CONVOY SEAT: aboard=%1 originalVehicle=%2 originalVehicleTree=%3",
aboard, vehicle.Entity, ERR_ConvoyRules.PartOf(aboard, vehicle.Entity));
AIControlComponent control;
AIAgent agent;
SCR_AIUtilityComponent utility;
if (actor) control = AIControlComponent.Cast(actor.FindComponent(AIControlComponent));
if (control) agent = control.GetControlAIAgent();
if (agent) utility = SCR_AIUtilityComponent.Cast(agent.FindComponent(SCR_AIUtilityComponent));
string behavior = "no actor utility", groupAction = "no group utility";
if (utility) behavior = MovementAction(utility.GetCurrentBehavior());
SCR_AIGroupUtilityComponent groupUtility = vehicle.Group.GetGroupUtilityComponent();
if (groupUtility) groupAction = MovementAction(groupUtility.GetCurrentAction());
PrintFormat("ERR CONVOY SEAT: actorBehavior=%1 groupAction=%2", behavior, groupAction);
}
protected bool Population(ERR_HQ hq)
{
if (!Check(m_Task.Vehicles.Count() == 6, "six original vehicles remain tracked")) return false;
@@ -191,10 +224,11 @@ class ERR_NativeConvoyProbe
{
IEntity actor = vehicle.Members[seatIndex];
BaseCompartmentSlot seat = vehicle.Seats[seatIndex];
if (!Check(actor && ERR_Actors.CanFight(actor) && !crew.Contains(actor)
bool occupied = actor && ERR_Actors.CanFight(actor) && !crew.Contains(actor)
&& ERR_Actors.Group(actor) == vehicle.Group && seat && !slots.Contains(seat) && seat.GetOccupant() == actor
&& ERR_ConvoyRules.PartOf(CompartmentAccessComponent.GetVehicleIn(actor), vehicle.Entity),
"original crew occupies intended native compartment " + crew.Count().ToString())) return false;
&& ERR_ConvoyRules.PartOf(CompartmentAccessComponent.GetVehicleIn(actor), vehicle.Entity);
if (!occupied) SeatDiagnostic(vehicle, seatIndex, actor, seat, crew.Contains(actor), slots.Contains(seat));
if (!Check(occupied, "original crew occupies intended native compartment " + crew.Count().ToString())) return false;
crew.Insert(actor); slots.Insert(seat);
bool nativeMember;
foreach (AIAgent agent : agents) if (agent && agent.GetControlledEntity() == actor) nativeMember = true;
@@ -247,6 +281,7 @@ class ERR_NativeConvoyProbe
int Tick(ERR_HQ hq, float now)
{
if (!Enabled() || !hq || !m_Mode || m_Mode != ERR_GameMode.Get() || m_Failed) return -1;
if (m_Step == 4) return m_Cover.Tick(hq, now);
if (m_Deadline == 0) m_Deadline = now + 480000;
if (now >= m_Deadline) { Check(false, "native fixture deadline"); return -1; }
if (m_Step == 0)
@@ -340,7 +375,13 @@ class ERR_NativeConvoyProbe
&& m_Mode.Forces().Count() == m_InitialLedger + 6 && m_Task.Cargo.Count() == 56,
"later repeated dispatch preserves exact task, force and cargo counts")) return -1;
Check(true, "all six native vehicles drove at least 20m and leader at least 100m without fixture movement");
if (ERR_NativeConvoyCoverProbe.Enabled())
{
m_Cover = new ERR_NativeConvoyCoverProbe(m_Mode); m_Step = 4;
return 0;
}
return 1;
}
void Stop() { if (m_Cover) m_Cover.Stop(); }
}
#endif