Files
EscapistsReintroduced/docs/evidence/dedicated-2026-09-19-083213/source/docs/native-mortar-firing.md
T

6.1 KiB

Native mortar first shot and cancellation fixture

ERR_NativeMortarFiringProbe is opt-in WORKBENCH code for --project chat --smoke mortar-fire --rounds 1. It observes one real HQ-authorized shot, then explicitly stops support and watches for duplicate orders/shots or replacement ammunition. This is not a full eight-shot salvo, hit-accuracy, real enemy perception, remote-client or FPS test. No engine run was performed while authoring it.

The probe waits for the existing authored gun/four-person crew, native expansion, operational state and physical manpack route. It snapshots exactly 27 unique inventory shells. A bounded eight-point terrain survey checks no characters/vehicles in a 400m square and applies the production settlement/friendly safety checks to the target and all prospective salvo offsets. An inert fixture-owned vanilla intel folder supplies target identity. The observation describing that identity as a stationary contact is explicitly synthetic; it is queued on the existing battery RTO's actual uplink. There is no direct contact-list insertion or battery Order call. Normal HQ acceptance, mortar scheduling, real downlink, native artillery activity, aim, final shell transfer and native OnWeaponFired remain unchanged. No report is refreshed or retimestamped to make firing pass.

The independent native-event hook records only a non-null projectile from this gun. It rejects duplicate entity callbacks and requires this report/order, an open committed shot and fresh aim with positive flight time. Later polling requires matching battery projectile counts and exactly one original inventory shell consumed. It stops support only on that later tick, never inside the firing callback, and verifies unchanged order/projectile/ammunition counts for another twelve seconds. Already-fired projectiles remain engine-owned; cleanup does not delete or move them. Inventory loss and actual projectile origin are recorded, but impact/flight accuracy is not measured.

Cleanup removes only the test report and orders referring to its target, cancels its battery order if still present, deletes the inert target and detaches the static observer. It leaves mission guns/crew, inventory and physics alone. Success intentionally stops the support service, so the parent fixture must end/reset this disposable mission. On failure, stop the probe and end the fixture; do not continue ordinary gameplay with the test report. Existing contacts or an already-tasked battery cause a diagnostic refusal rather than erasing unrelated reports. Begin this case immediately after the real initial player is admitted. If actual perception has already produced competing reports, diagnose and choose a disclosed fixture arrangement; do not suppress production observation or relax report freshness.

The startup wait is bounded to 180 seconds, report-to-first-shot to 90 seconds, and stopped observation to 12 seconds. Battery status/failure/route/activity/aim diagnostics are emitted every 5 seconds. A native failure is useful evidence; successful node or inventory-request returns never substitute for a projectile.

Parent-owned integration

Copy only addons/ai/Scripts/Game/ERR/ERR_NativeMortarFiringProbe.c and tests/test_native_mortar_probe.py, plus this document. The new source adds no resource identities and no production behavior outside WORKBENCH. Preserve the separate Battery/System/Firing fixes; the probe relies only on their existing public counters, identity fields, CountShells, SiteStatus, Operational, and normal HQ routes.

In the existing Chat ERR_NativeSmoke.c layer (not another modded mode), add:

protected bool m_ERRTestMortarFire;
protected ref ERR_NativeMortarFiringProbe m_ERRMortarFire;

After outcome parsing, set m_ERRTestMortarFire = outcome == "mortar-fire"; and give that case a 330000ms outer smoke deadline. Add if (m_ERRMortarFire) m_ERRMortarFire.Stop(); to the existing cleanup helper used by error/OnStop. In the step0 branch, after the usual real-player/contracts checks and before existing inventory/death branches:

if (m_ERRTestMortarFire)
{
 DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false);
 m_ERRMortarFire = new ERR_NativeMortarFiringProbe(this);
 m_ERRSmokeStep = 150;
 return;
}

Before normal step dispatch:

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;
}

In ERR_SmokePhase, after the terminal-phase guard but before generic victory/death expectations, handle this case only if current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 151. Mark smoke done, remove its polling callback, run existing cleanup and print ERR SMOKE COMPLETE: native HQ radio to first mortar projectile and explicit stop; fixture reset requested. A premature natural defeat is a failure. This completion means the targeted mechanism and cancellation observations passed, not a completed escape.

Add mortar-fire to the runner smoke choices; explicitly require Chat and one round for this case. Keep Core unsupported. Run with an outer timeout at least 400 seconds. Add test_native_mortar_probe.py to tools/check.py if retaining the probe. Its C++ harness executes the real native-event evidence method and checks wrong-gun, null/duplicate, uncommitted, wrong-source, missing/stale aim, stopped-observer and post-stop event refusal. It does not simulate the native firing behavior.

Further required cases

After a real first-shot pass, qualify the complete eight-shot salvo under unchanged 60-second contact freshness, finite donor-to-gunner transfer, receiver-radio loss before delivery, stale report during supply/aim, crew/gun loss, depletion, and Stop during an accepted but unfinished shell transfer. The fixture's first shot may not require resupply because the native gunner already owns shells; do not claim transfer-race coverage from this result. Real visual perception→radio→HQ→fire and multiplayer need separate evidence.