Files
EscapistsReintroduced/docs/finite-mortar-operations.md
jakub cab998fb64 Combine Workshop addon and fix prison startup
Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
2026-09-20 16:42:52 +02:00

6.7 KiB

Finite mortar readiness and ammunition operations

This patch completes missing lifecycle behavior in the existing HQ-owned mortar path. It adds no gun/crew response spawn, depot, convoy or aircraft. Existing physical projectiles, firing safety and stock behavior outside the successor's registered battery remain native. Local tests pass; native compilation and new runtime behavior still require verification.

Startup

The authored one-gun/four-member battery is still created once by ERR_MortarSystem.Prepare. A new battery-owned readiness object polls before runtime Operational checks, so an initially empty group remains pending until its bounded deadline rather than bypassing initialization forever. Within 90 seconds it requires native IsExpandComplete, exactly three distinct configured mortar crew and one configured manpack operator, live correct-faction actors, initialized inventories and a valid native gun registration. The existing minimum ten-second startup delay remains, but no longer means readiness.

The original nine-shell budget per gunner is allocated once after the complete original population is present. Initial shell counts outside 0..9 fail. Each missing shell request receives a distinct retained completion callback; the allocation latch is set before the first native request. A rejection/partial failure permanently closes allocation, without a new budget or retry. All callbacks must finish successfully and each original gunner must actually carry nine unique HE entities, with zero on the RTO and 27 unique group shells, before StartupActivated becomes true. Stolen/consumed/missing initialization items are observed until the same deadline and never replenished. Optional short-range crew handsets retain their existing one-time attempt; the actual RTO manpack is mandatory.

The support owner does not replace injured, lost or substituted crew. Stop or failed pending initialization disables only its owned group's SetSpawnImmediately intent, empties only that group's initial prefab list, and purges its queued native requests. Existing physical actors, gun and items remain owned by the existing mission cleanup; the helper neither deletes them nor changes their health. Successfully initialized Stop retains asset references and readable inventory diagnostics.

Exact shell transfers

SupplyState(now) explicitly returns FAILED/PENDING/READY. SupplyGunner() remains a compatibility wrapper and only returns true for READY. The old request-accepted-as-supplied behavior is removed.

A transaction captures the exact shell, donor, gunner, source/destination managers, destination storage, gun, group and HQ order number. Native TryMoveItemToStorage is issued once; callback methods only record completion/failure and never launch an activity. Authorization is checked on the server against the still-active HQ battery/order, original delivered report timestamp, original gun/group, conscious current crew, factions, distance and turret occupant. Supply READY requires a successful callback and the exact shell absent from the donor inventory, present in the gunner inventory and attached to the requested storage. Callback GetItem() is deliberately not used because its installed contract excludes Move operations.

Each shell identity is attempted at most once for this battery during the round, including rejected/ambiguous attempts. A canceled operation cannot authorize fire. An accepted unresolved operation stays reserved and blocks another battery transfer even after its order is canceled. A late successful callback can resolve physical ownership, but cannot make the canceled/expired current order ready. No native retry, shell clone, replacement or health change is used to resolve uncertainty. A successful callback without physical ownership proof remains ambiguous; at the eight-second deadline that order fails, and further supply remains blocked until there is a definite outcome. This is deliberately conservative and can leave a battery unavailable rather than risk overlapping inventory mutations.

Once a transfer has genuinely completed for its current order, its transaction is released so later rounds can request a different existing shell. The attempted shell identity remains excluded from another move request. Ammo already physically in the current gunner remains usable; no new supply entity is spawned during firing.

Order and native shot counter integration

The system retains the radio-delivered snapshot in PendingSupplyReport while supply is pending, checks its unchanged observation age and eligibility every tick, and creates the stock artillery activity only once when READY. The scheduler excludes a pending supply report/unresolved transfer from new assignments.

The native ShootingLogic superclass increments its behavior shot counter. The successor hook therefore waits before calling super: first for a confirmed physical projectile, then for actual next-round supply. Pending ticks return RUNNING without incrementing; supply failure returns FAIL and closes authorization through the existing HQ rejection path. Once READY, super runs once and the next aim is requested. The final confirmed salvo round does not require an extra shell. Real OnWeaponFired remains the independent authoritative projectile count; no node success is relabeled as a shot.

Files and validation

New production helpers:

  • addons/core/Scripts/Game/ERR/10_AI/ERR_MortarReadiness.c
  • addons/core/Scripts/Game/ERR/10_AI/ERR_MortarSupplyTransfer.c

mortar-finite-operations.patch contains only Battery/System/Firing edits. No native probe, shared staging, Core source, resources or check.py was edited. New tests/test_mortar_transactions.py executes actual extracted population/allocation/order/ownership/cycle policies and the actual transfer Poll/Acknowledge control flow against narrow API fakes. Cases include zero/late/duplicate population, callback without inventory, wrong destination storage, simultaneous source/destination claims, stale order, cancellation, exact timeout, late completion, missing shell and repeated pending ticks without duplicate shot-counter increment. Source contracts additionally constrain allocation latching, single native move, cleanup and Firing's pre-super wait. Native inventory/expansion/firing remain separate qualification tasks.

Primary installed API references and hashes are in vanilla-reference-sha256.json. The native first-projectile fixture prepared separately by the other agent continues using existing public Gun, Group, StartupActivated, SpawnFailure, CountShells, OrderShots and TotalShots. Its first shot alone does not exercise donor transfer; a separate exact-item transfer/interruption test is still needed before claiming resupply acceptance.