Advance standalone admission, finite artillery and native validation
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
#ifdef WORKBENCH
|
||||
// Read-only evidence hooks. Every production method delegates unchanged.
|
||||
modded class ERR_HQ
|
||||
{
|
||||
void ERR_ResponseUnits(out array<ERR_HQUnit> units)
|
||||
{
|
||||
units.Clear();
|
||||
if (!ERR_NativeHQResponseProof.Enabled()) return;
|
||||
foreach (ERR_HQUnit unit : m_Units) units.Insert(unit);
|
||||
}
|
||||
protected override void Observe(ERR_HQUnit unit, float now)
|
||||
{
|
||||
ERR_HQReport previous = unit.PendingReport;
|
||||
super.Observe(unit, now);
|
||||
ERR_NativeHQResponseProof proof = ERR_NativeHQResponseProof.Active();
|
||||
if (proof && unit.PendingReport && unit.PendingReport != previous) proof.Observed(this, unit, now);
|
||||
}
|
||||
protected override void Accept(ERR_HQReport report, float now)
|
||||
{
|
||||
super.Accept(report, now);
|
||||
ERR_NativeHQResponseProof proof = ERR_NativeHQResponseProof.Active();
|
||||
if (!proof || !report) return;
|
||||
foreach (ERR_HQReport accepted : m_Contacts)
|
||||
if (accepted.MessageId == report.MessageId) { proof.Accepted(this, accepted, now); break; }
|
||||
}
|
||||
protected override void DeliverOrder(ERR_HQUnit unit, float now)
|
||||
{
|
||||
ERR_HQReport order = unit.PendingOrder;
|
||||
ERR_HQRoute route = unit.Downlink;
|
||||
super.DeliverOrder(unit, now);
|
||||
ERR_NativeHQResponseProof proof = ERR_NativeHQResponseProof.Active();
|
||||
if (proof && order && route && unit.Assignment == order && unit.Waypoint) proof.Delivered(this, unit, route, now);
|
||||
}
|
||||
}
|
||||
modded class ERR_HQJournal
|
||||
{
|
||||
override void Write(string kind, string message, int messageId = 0)
|
||||
{
|
||||
super.Write(kind, message, messageId);
|
||||
ERR_NativeHQResponseProof proof = ERR_NativeHQResponseProof.Active();
|
||||
if (proof) proof.JournalEvent(this, kind, message, messageId);
|
||||
}
|
||||
}
|
||||
modded class SCR_AIGroupUtilityComponent
|
||||
{
|
||||
IEntity ERR_ResponseVisualObserver(ERR_HQReport report, float now)
|
||||
{
|
||||
foreach (SCR_AIInfoComponent info : m_aInfoComponents)
|
||||
{
|
||||
if (!info || !info.m_Perception) continue;
|
||||
AIAgent agent = AIAgent.Cast(info.GetOwner());
|
||||
if (!agent || !ERR_Actors.CanFight(agent.GetControlledEntity())) continue;
|
||||
array<BaseTarget> targets = {}; info.m_Perception.GetTargetsList(targets, ETargetCategory.ENEMY);
|
||||
foreach (BaseTarget target : targets)
|
||||
{
|
||||
ERR_HQVisualContact sample = ERR_HQObservation.Capture(target, now);
|
||||
if (sample && sample.Entity == report.Target && sample.Escapist && Math.AbsFloat(sample.ObservedAt - report.ObservedAt) < 1 && vector.Distance(sample.Position, report.Position) < 0.1) return agent.GetControlledEntity();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
class ERR_NativeResponseUnit
|
||||
{
|
||||
ERR_HQUnit Unit;
|
||||
SCR_AIGroup Group;
|
||||
IEntity Radio;
|
||||
ref array<IEntity> Actors = {};
|
||||
}
|
||||
class ERR_NativeResponseJournal
|
||||
{
|
||||
bool Report;
|
||||
bool Transmit;
|
||||
bool HQReceive;
|
||||
bool HQTransmit;
|
||||
bool UnitReceive;
|
||||
bool Delivered;
|
||||
}
|
||||
class ERR_NativeResponseLineage
|
||||
{
|
||||
ref ERR_HQReport Report;
|
||||
ERR_HQUnit Source;
|
||||
IEntity Observer;
|
||||
IEntity SourceRadio;
|
||||
ref ERR_HQRoute Uplink;
|
||||
bool Accepted;
|
||||
float AcceptedAt;
|
||||
ERR_HQUnit Recipient;
|
||||
IEntity RecipientRadio;
|
||||
int DeliveryId;
|
||||
AIWaypoint Waypoint;
|
||||
IEntity MovingActor;
|
||||
vector DeliveredOrigin;
|
||||
float DeliveredAt;
|
||||
}
|
||||
class ERR_NativeHQResponseProof
|
||||
{
|
||||
protected static ERR_NativeHQResponseProof s_Active;
|
||||
protected ERR_GameMode m_Mode;
|
||||
protected ERR_HQ m_HQ;
|
||||
protected IEntity m_Player;
|
||||
protected SCR_PlayerController m_Controller;
|
||||
protected ERR_PlayerLife m_Life;
|
||||
protected ERR_HQUnit m_Source;
|
||||
protected DamageManagerComponent m_Damage;
|
||||
protected bool m_DamageWasEnabled;
|
||||
protected bool m_Protected;
|
||||
protected bool m_Started;
|
||||
protected bool m_Stopped;
|
||||
protected bool m_Failed;
|
||||
protected string m_Failure;
|
||||
protected float m_Deadline;
|
||||
protected float m_NextDiagnostic;
|
||||
protected ref array<ref ERR_NativeResponseUnit> m_Units = {};
|
||||
protected ref array<IEntity> m_Forces = {};
|
||||
protected ref array<ref ERR_NativeResponseLineage> m_Reports = {};
|
||||
protected ref map<int, ref ERR_NativeResponseJournal> m_Journal = new map<int, ref ERR_NativeResponseJournal>();
|
||||
static bool Enabled()
|
||||
{
|
||||
string enabled, outcome;
|
||||
return Replication.IsServer() && System.GetCLIParam("errSmoke", enabled) && enabled == "1" && System.GetCLIParam("errSmokeOutcome", outcome) && outcome == "hq-response";
|
||||
}
|
||||
static ERR_NativeHQResponseProof Active() { return s_Active; }
|
||||
void ERR_NativeHQResponseProof(ERR_GameMode mode, IEntity player)
|
||||
{
|
||||
m_Mode = mode; m_Player = player; m_HQ = ERR_HQ.Get(); m_Deadline = GetGame().GetWorld().GetWorldTime() + 140000;
|
||||
if (Enabled() && !s_Active) s_Active = this;
|
||||
}
|
||||
protected bool Fail(string reason) { m_Failed = true; m_Failure = reason; return false; }
|
||||
protected bool Check(bool condition, string detail)
|
||||
{
|
||||
if (condition) { Print("ERR SMOKE PASS: HQ response " + detail); return true; }
|
||||
Print("ERR SMOKE FAIL: HQ response " + detail, LogLevel.ERROR); Stop(); return false;
|
||||
}
|
||||
protected ERR_NativeResponseUnit Original(ERR_HQUnit unit)
|
||||
{
|
||||
foreach (ERR_NativeResponseUnit original : m_Units) if (original.Unit == unit && original.Group == unit.Group) return original;
|
||||
return null;
|
||||
}
|
||||
protected ERR_NativeResponseLineage Report(int id)
|
||||
{
|
||||
foreach (ERR_NativeResponseLineage report : m_Reports) if (report.Report.MessageId == id) return report;
|
||||
return null;
|
||||
}
|
||||
protected bool Canonical()
|
||||
{
|
||||
return m_Player && m_Controller && m_Life && m_Mode.Players().CurrentActor(m_Player) == m_Life && m_Controller == GetGame().GetPlayerController() && m_Controller.GetControlledEntity() == m_Player && m_Life.Actor == m_Player && m_Life.Connected && m_Life.UsedLife;
|
||||
}
|
||||
protected bool UnchangedForces()
|
||||
{
|
||||
array<ERR_HQUnit> current = {}; m_HQ.ERR_ResponseUnits(current);
|
||||
if (current.Count() != m_Units.Count()) return false;
|
||||
foreach (ERR_HQUnit unit : current)
|
||||
{
|
||||
ERR_NativeResponseUnit original = Original(unit);
|
||||
if (!original) return false;
|
||||
array<AIAgent> agents = {}; unit.Group.GetAgents(agents);
|
||||
if (agents.Count() != original.Actors.Count()) return false;
|
||||
foreach (AIAgent agent : agents) if (!agent || !original.Actors.Contains(agent.GetControlledEntity())) return false;
|
||||
}
|
||||
array<IEntity> forces = {}; m_HQ.PhysicalForces(forces);
|
||||
if (forces.Count() != m_Forces.Count()) return false;
|
||||
foreach (IEntity entity : forces) if (!m_Forces.Contains(entity)) return false;
|
||||
return true;
|
||||
}
|
||||
protected bool Arrange()
|
||||
{
|
||||
array<ERR_HQUnit> units = {}; m_HQ.ERR_ResponseUnits(units);
|
||||
foreach (ERR_HQUnit unit : units)
|
||||
{
|
||||
if (!unit.Group || !unit.Utility || !unit.Radio || ERR_HQRadio.Capability(unit.Radio) != 2) return false;
|
||||
array<AIAgent> agents = {}; unit.Group.GetAgents(agents);
|
||||
if (agents.IsEmpty() || !unit.Group.IsExpandComplete()) return false;
|
||||
ERR_NativeResponseUnit original = new ERR_NativeResponseUnit(); original.Unit = unit; original.Group = unit.Group; original.Radio = unit.Radio;
|
||||
foreach (AIAgent agent : agents)
|
||||
{
|
||||
if (!agent || !ERR_Actors.CanFight(agent.GetControlledEntity())) return false;
|
||||
original.Actors.Insert(agent.GetControlledEntity());
|
||||
}
|
||||
m_Units.Insert(original);
|
||||
if (!m_Source && !unit.ReservedForSupport) m_Source = unit;
|
||||
}
|
||||
if (!m_Source || m_Units.Count() < 2) return false;
|
||||
m_HQ.PhysicalForces(m_Forces);
|
||||
m_Controller = SCR_PlayerController.Cast(GetGame().GetPlayerController()); m_Life = m_Mode.Players().CurrentActor(m_Player);
|
||||
if (!Canonical()) return false;
|
||||
m_Damage = DamageManagerComponent.Cast(m_Player.FindComponent(DamageManagerComponent));
|
||||
if (!m_Damage) return false;
|
||||
m_DamageWasEnabled = m_Damage.IsDamageHandlingEnabled(); m_Damage.EnableDamageHandling(false); m_Protected = true;
|
||||
// Preserve the established fixture arrangement: move only the real prisoner.
|
||||
// Native perception must discover him; neither targets nor reports are seeded.
|
||||
vector position = ERR_Actors.Ground(m_Source.Group.GetOrigin() + "0 0 20");
|
||||
vector transform[4]; m_Player.GetWorldTransform(transform); transform[3] = position;
|
||||
ChimeraCharacter.Cast(m_Player).Teleport(transform);
|
||||
m_Started = true;
|
||||
PrintFormat("ERR HQ RESPONSE ARRANGEMENT: canonical prisoner moved to=%1 near original source group=%2; temporary player damage protection=%3; no AI/report/radio cadence changes", position, m_Source.Id, m_Protected);
|
||||
return true;
|
||||
}
|
||||
void JournalEvent(ERR_HQJournal journal, string kind, string message, int messageId)
|
||||
{
|
||||
if (!m_Started || m_Stopped || !m_HQ || journal != m_HQ.Journal() || messageId <= 0) return;
|
||||
ERR_NativeResponseJournal entry = m_Journal.Get(messageId);
|
||||
if (!entry)
|
||||
{
|
||||
if (m_Journal.Count() >= 128) { Fail("bounded journal evidence map exhausted"); return; }
|
||||
entry = new ERR_NativeResponseJournal(); m_Journal.Insert(messageId, entry);
|
||||
}
|
||||
if (kind == "REPORT") entry.Report = true;
|
||||
if (kind == "TRANSMIT") { entry.Transmit = true; if (message.StartsWith("HQ -> ")) entry.HQTransmit = true; }
|
||||
if (kind == "RECEIVE") { if (message.StartsWith("HQ received from ")) entry.HQReceive = true; else if (message.StartsWith("unit ")) entry.UnitReceive = true; }
|
||||
if (kind == "ORDER DELIVERED") entry.Delivered = true;
|
||||
}
|
||||
void Observed(ERR_HQ hq, ERR_HQUnit unit, float now)
|
||||
{
|
||||
if (!m_Started || m_Stopped || hq != m_HQ || unit != m_Source || unit.PendingReport.Target != m_Player) return;
|
||||
ERR_HQReport report = unit.PendingReport;
|
||||
ERR_NativeResponseUnit original = Original(unit);
|
||||
IEntity observer = unit.Utility.ERR_ResponseVisualObserver(report, now);
|
||||
if (!Canonical() || !original || !original.Actors.Contains(observer) || !unit.Uplink || unit.Uplink.Nodes.IsEmpty() || unit.Uplink.Nodes[0].Carrier != unit.Radio || unit.Uplink.MessageId != report.MessageId || unit.Radio != original.Radio || !original.Actors.Contains(unit.Radio) || report.Source != original.Group || report.ObservedAt > now || Report(report.MessageId)) { Fail("real observed report lacks canonical original observer/radio/source lineage"); return; }
|
||||
if (m_Reports.Count() >= 32) { Fail("bounded report evidence exhausted"); return; }
|
||||
ERR_NativeResponseLineage proof = new ERR_NativeResponseLineage(); proof.Report = report.Snapshot(); proof.Source = unit; proof.Observer = observer; proof.SourceRadio = unit.Radio; proof.Uplink = unit.Uplink; m_Reports.Insert(proof);
|
||||
PrintFormat("ERR HQ RESPONSE SIGHTING: source=%1 report=M%2 observer=%3 radio=%4 target=%5 observedAt=%6; actual native visual sample", unit.Id, report.MessageId, observer, unit.Radio, m_Player, report.ObservedAt);
|
||||
}
|
||||
void Accepted(ERR_HQ hq, ERR_HQReport report, float now)
|
||||
{
|
||||
if (!m_Started || m_Stopped || hq != m_HQ) return;
|
||||
ERR_NativeResponseLineage proof = Report(report.MessageId); if (!proof) return;
|
||||
if (report.Target != m_Player || report.Source != proof.Report.Source || report.ObservedAt != proof.Report.ObservedAt || vector.Distance(report.Position, proof.Report.Position) > 0.01 || !proof.Uplink || proof.Uplink.Failed || proof.Uplink.Sending || proof.Uplink.Cursor < proof.Uplink.Nodes.Count()) { Fail("accepted report lacks completed actual uplink or immutable observed time"); return; }
|
||||
proof.Accepted = true; proof.AcceptedAt = now;
|
||||
}
|
||||
void Delivered(ERR_HQ hq, ERR_HQUnit unit, ERR_HQRoute route, float now)
|
||||
{
|
||||
if (!m_Started || m_Stopped || hq != m_HQ || !unit.Assignment) return;
|
||||
ERR_NativeResponseLineage proof = Report(unit.Assignment.MessageId); if (!proof || proof.Recipient) return;
|
||||
ERR_NativeResponseUnit original = Original(unit);
|
||||
if (!proof.Accepted || !original || unit == proof.Source || !unit.Assignment || unit.Assignment.Target != m_Player || unit.Assignment.Source != proof.Report.Source || unit.Assignment.ObservedAt != proof.Report.ObservedAt || vector.Distance(unit.Assignment.Position, proof.Report.Position) > 0.01 || unit.Radio != original.Radio || !original.Actors.Contains(unit.Radio) || !route.Downlink || route.Nodes.IsEmpty() || route.Nodes[route.Nodes.Count() - 1].Carrier != unit.Radio || route.Failed || route.Sending || route.Cursor != route.Nodes.Count() - 1 || !unit.Waypoint) { Fail("delivered response lacks immutable accepted report and original physical recipient/downlink"); return; }
|
||||
proof.Recipient = unit; proof.RecipientRadio = unit.Radio; proof.DeliveryId = route.MessageId; proof.Waypoint = unit.Waypoint; proof.DeliveredAt = now;
|
||||
foreach (IEntity actor : original.Actors) if (ERR_Actors.CanFight(actor)) { proof.MovingActor = actor; break; }
|
||||
if (proof.MovingActor) proof.DeliveredOrigin = proof.MovingActor.GetOrigin();
|
||||
PrintFormat("ERR HQ RESPONSE DELIVERED: report=M%1 downlink=M%2 source=%3 recipient=%4 radio=%5 waypoint=%6 observedAt=%7", proof.Report.MessageId, route.MessageId, proof.Source.Id, unit.Id, unit.Radio, unit.Waypoint, unit.Assignment.ObservedAt);
|
||||
}
|
||||
int Tick(float now)
|
||||
{
|
||||
if (m_Stopped) return -1;
|
||||
if (!Enabled() || s_Active != this || !m_Mode || !m_Mode.Active() || !m_HQ || now > m_Deadline || m_Failed) { Check(false, "bounded active evidence context: " + m_Failure); return -1; }
|
||||
if (!m_Started)
|
||||
{
|
||||
if (!m_HQ.ERR_ProbeSquadsReady()) return 0;
|
||||
array<IEntity> guns = {}; m_HQ.Mortars().AppendGuns(guns);
|
||||
foreach (IEntity gun : guns) { ERR_MortarBattery battery = m_HQ.Mortars().FindGun(gun); if (!battery || !battery.StartupActivated || !battery.Operational() || !m_HQ.MortarConnected(battery.Group)) return 0; }
|
||||
if (!Check(Arrange(), "original physical force, RTOs and canonical prisoner captured before arranged sighting")) return -1;
|
||||
return 0;
|
||||
}
|
||||
if (!Canonical() || !UnchangedForces()) { Check(false, "canonical player and all original physical group/actor identities retained without added force"); return -1; }
|
||||
if (now >= m_NextDiagnostic)
|
||||
{
|
||||
PrintFormat("ERR HQ RESPONSE PROOF: observed source reports=%1; %2", m_Reports.Count(), m_HQ.ERR_ProbePerception()); m_NextDiagnostic = now + 10000;
|
||||
}
|
||||
foreach (ERR_NativeResponseLineage proof : m_Reports)
|
||||
{
|
||||
if (!proof.Recipient || !proof.MovingActor) continue;
|
||||
if (proof.Recipient.Waypoint != proof.Waypoint || !proof.Recipient.Assignment || proof.Recipient.Assignment.MessageId != proof.Report.MessageId) continue;
|
||||
ERR_NativeResponseJournal uplink = m_Journal.Get(proof.Report.MessageId);
|
||||
ERR_NativeResponseJournal downlink = m_Journal.Get(proof.DeliveryId);
|
||||
if (!uplink || !downlink || !uplink.Report || !uplink.Transmit || !uplink.HQReceive || !downlink.HQTransmit || !downlink.UnitReceive || !downlink.Delivered) continue;
|
||||
if (proof.Recipient.Group.GetCurrentWaypoint() != proof.Waypoint || vector.DistanceXZ(proof.MovingActor.GetOrigin(), proof.DeliveredOrigin) < 3) continue;
|
||||
if (vector.DistanceXZ(proof.MovingActor.GetOrigin(), proof.Report.Position) >= vector.DistanceXZ(proof.DeliveredOrigin, proof.Report.Position) - 1) continue;
|
||||
if (!Check(proof.SourceRadio && proof.RecipientRadio && m_HQ.ERR_ProbeUniqueAssignments(), "actual sighting/report/uplink/HQ receipt/downlink journal lineage reaches distinct original infantry with bounded unique waypoints")) return -1;
|
||||
if (!Check(UnchangedForces(), "original recipient physically moves toward its native Search waypoint with no replacement or additional force")) return -1;
|
||||
Stop(); return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void Stop()
|
||||
{
|
||||
if (m_Stopped) return;
|
||||
m_Stopped = true;
|
||||
if (m_Protected && m_Damage) m_Damage.EnableDamageHandling(m_DamageWasEnabled);
|
||||
m_Protected = false;
|
||||
if (s_Active == this) s_Active = null;
|
||||
}
|
||||
void ~ERR_NativeHQResponseProof() { Stop(); }
|
||||
}
|
||||
#endif
|
||||
@@ -17,8 +17,13 @@ modded class ERR_GameMode
|
||||
protected bool m_ERRTestRadioNetwork;
|
||||
protected bool m_ERRTestHQResponse;
|
||||
protected bool m_ERRTestMortar;
|
||||
protected bool m_ERRTestMortarFire;
|
||||
protected bool m_ERRTestMortarTransfer;
|
||||
protected ref ERR_NativeMortarTransferProbe m_ERRMortarTransfer;
|
||||
protected ref ERR_NativeMortarFiringProbe m_ERRMortarFire;
|
||||
protected float m_ERRNextProbeLog;
|
||||
protected ref ERR_NativeRadioProbe m_ERRRadioProbe;
|
||||
protected ref ERR_NativeHQResponseProof m_ERRHQResponseProof;
|
||||
protected ref array<IEntity> m_ERRCacheFolders = {};
|
||||
|
||||
protected override void EOnInit(IEntity owner)
|
||||
@@ -31,9 +36,13 @@ modded class ERR_GameMode
|
||||
m_ERRTestRadioNetwork = outcome == "radio-network";
|
||||
m_ERRTestHQResponse = outcome == "hq-response";
|
||||
m_ERRTestMortar = outcome == "mortar-inventory";
|
||||
m_ERRTestMortarFire = outcome == "mortar-fire" || outcome == "mortar-expiry";
|
||||
m_ERRTestMortarTransfer = outcome == "mortar-transfer";
|
||||
m_ERRTestPatrolHQ = outcome == "patrol-hq";
|
||||
m_ERRTestPlayerDeath = outcome == "player-death" || m_ERRTestRadioNetwork || m_ERRTestHQResponse || m_ERRTestMortar;
|
||||
m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 150000;
|
||||
if (m_ERRTestMortarTransfer) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 330000;
|
||||
if (m_ERRTestMortarFire) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 330000;
|
||||
if (m_ERRTestPatrolHQ) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 420000;
|
||||
OnStop().Insert(ERR_StopHQPatrol);
|
||||
OnPhaseChanged().Insert(ERR_SmokePhase);
|
||||
@@ -52,6 +61,9 @@ modded class ERR_GameMode
|
||||
}
|
||||
protected void ERR_StopHQPatrol()
|
||||
{
|
||||
if (m_ERRHQResponseProof) m_ERRHQResponseProof.Stop();
|
||||
if (m_ERRMortarTransfer) m_ERRMortarTransfer.Stop();
|
||||
if (m_ERRMortarFire) m_ERRMortarFire.Stop();
|
||||
if (m_ERRHQPatrolMovement) m_ERRHQPatrolMovement.Stop();
|
||||
if (m_ERRHQPatrolOrder) m_ERRHQPatrolOrder.Stop();
|
||||
}
|
||||
@@ -87,6 +99,24 @@ modded class ERR_GameMode
|
||||
protected void ERR_SmokePhase(ERR_Phase previous, ERR_Phase current)
|
||||
{
|
||||
if (m_ERRSmokeDone || !ERR_MissionRules.Terminal(current)) return;
|
||||
if (m_ERRTestMortarTransfer)
|
||||
{
|
||||
if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 161, "native exact shell transfers and original-owner restoration complete before explicit reset")) return;
|
||||
m_ERRSmokeDone = true;
|
||||
GetGame().GetCallqueue().Remove(ERR_SmokeTick);
|
||||
ERR_StopHQPatrol();
|
||||
Print("ERR SMOKE COMPLETE: native exact mortar inventory transfer, accepted-operation cancellation and original-owner restoration; radio bypassed; fixture reset requested");
|
||||
return;
|
||||
}
|
||||
if (m_ERRTestMortarFire)
|
||||
{
|
||||
if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 151, "native mortar first shot and stop complete before explicit reset")) return;
|
||||
m_ERRSmokeDone = true;
|
||||
GetGame().GetCallqueue().Remove(ERR_SmokeTick);
|
||||
ERR_StopHQPatrol();
|
||||
Print("ERR SMOKE COMPLETE: native HQ radio mortar projectile and configured cancellation/expiry; fixture reset requested");
|
||||
return;
|
||||
}
|
||||
if (m_ERRTestPatrolHQ)
|
||||
{
|
||||
if (!ERR_Check(current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 133, "HQ patrol preemption and physical resumption before explicit reset")) return;
|
||||
@@ -149,6 +179,20 @@ modded class ERR_GameMode
|
||||
if (m_ERRSmokeDone) return;
|
||||
if (now > m_ERRSmokeDeadline) { ERR_Check(false, "timeout at step " + m_ERRSmokeStep.ToString()); return; }
|
||||
if (now < m_ERRSmokeWait) return;
|
||||
if (m_ERRSmokeStep == 160)
|
||||
{
|
||||
int result = m_ERRMortarTransfer.Tick(now);
|
||||
if (result < 0) { ERR_Check(false, "native mortar exact-shell transfer fixture"); return; }
|
||||
if (result == 1) { m_ERRSmokeStep = 161; Transition(ERR_Phase.DEFEAT); }
|
||||
return;
|
||||
}
|
||||
if (m_ERRSmokeStep == 150)
|
||||
{
|
||||
int result = m_ERRMortarFire.Tick(now);
|
||||
if (result < 0) { ERR_Check(false, "native mortar firing probe failed; see diagnostics"); return; }
|
||||
if (result == 1) { m_ERRSmokeStep = 151; Transition(ERR_Phase.DEFEAT); }
|
||||
return;
|
||||
}
|
||||
if (m_ERRSmokeStep == 130 || m_ERRSmokeStep == 132)
|
||||
{
|
||||
int result = m_ERRHQPatrolMovement.Tick(now);
|
||||
@@ -181,6 +225,20 @@ modded class ERR_GameMode
|
||||
m_ERRSmokeStep = 130;
|
||||
return;
|
||||
}
|
||||
if (m_ERRTestMortarTransfer)
|
||||
{
|
||||
DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false);
|
||||
m_ERRMortarTransfer = new ERR_NativeMortarTransferProbe(this);
|
||||
m_ERRSmokeStep = 160;
|
||||
return;
|
||||
}
|
||||
if (m_ERRTestMortarFire)
|
||||
{
|
||||
DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false);
|
||||
m_ERRMortarFire = new ERR_NativeMortarFiringProbe(this);
|
||||
m_ERRSmokeStep = 150;
|
||||
return;
|
||||
}
|
||||
if (m_ERRTestMortar)
|
||||
{
|
||||
DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false);
|
||||
@@ -189,7 +247,7 @@ modded class ERR_GameMode
|
||||
}
|
||||
if (m_ERRTestHQResponse)
|
||||
{
|
||||
DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false);
|
||||
m_ERRHQResponseProof = new ERR_NativeHQResponseProof(this, m_ERRSmokePlayer);
|
||||
m_ERRSmokeStep = 110;
|
||||
return;
|
||||
}
|
||||
@@ -343,23 +401,9 @@ modded class ERR_GameMode
|
||||
}
|
||||
else if (m_ERRSmokeStep == 110)
|
||||
{
|
||||
ERR_HQ hq = ERR_HQ.Cast(Command());
|
||||
if (!hq || !hq.ERR_ProbeSquadsReady()) return;
|
||||
ERR_MovePlayer(hq.ERR_ProbeResponseOrigin());
|
||||
m_ERRSmokeStep = 111;
|
||||
m_ERRSmokeWait = now + 1000;
|
||||
}
|
||||
else if (m_ERRSmokeStep == 111)
|
||||
{
|
||||
ERR_HQ hq = ERR_HQ.Cast(Command());
|
||||
if (now >= m_ERRNextProbeLog)
|
||||
{
|
||||
Print("ERR HQ PROBE: " + hq.ERR_ProbePerception());
|
||||
m_ERRNextProbeLog = now + 10000;
|
||||
}
|
||||
if (!hq.ERR_ProbeDeliveredResponse()) return;
|
||||
if (!ERR_Check(true, "native visual contact reaches HQ and orders a different existing squad")) return;
|
||||
if (!ERR_Check(hq.ERR_ProbeUniqueAssignments(), "HQ uses distinct waypoints within the existing force and order limits")) return;
|
||||
int result = m_ERRHQResponseProof.Tick(now);
|
||||
if (result < 0) { ERR_Check(false, "native HQ response evidence failed; inspect report lineage diagnostics"); return; }
|
||||
if (result == 0) return;
|
||||
m_ERRSmokeStep = 9;
|
||||
SCR_CharacterDamageManagerComponent damage = SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent));
|
||||
damage.EnableDamageHandling(true);
|
||||
|
||||
Reference in New Issue
Block a user