# Enemy skill and finite startup equipment migration Current policy (2026-09-23): [aggression and AI profile](aggression-ai.md) supersedes the historical Expert infantry floor below. All mission hostile military AI now use maximum decision skill with separate regular aim error. Adapted from independently authored, user-authorized AI code. Original files remain read-only; no original Escapists helpers, protected-derived `EAI_GroupLookup`, patched prefabs or asset bytes are imported. | Owned source | SHA-256 | Reused behavior | |---|---|---| | `escapists-ai/Scripts/Game/EscapistsAI/EAI_SniperOptics.c` | `96a302da44fdb9207c12cc1c9c93aad38eb510cb0cf9befd800f60a2945b08e8` | Preserve mounted magnified optics, randomized native-compatible attachment fitting, five startup checks and no replacement after removal | | `escapists-ai/Scripts/Game/EscapistsAI/EAI_StingerEquipment.c` | `b8ce09f2d3ed61e58beadc1f158daed6eceb17b08243f7979b46d8c27e917695` | One startup selection, native weapon-proxy insertion, five checks, no replacement after firing/dropping/looting | | `escapists-ai/Scripts/Game/EscapistsAI/EAI_AIResponseSystem.c` | `b3e1263e986837744a70fbaedaa6e57afae7f2981a21211d3a2066e2c63ac84d` | First combat-component section's Expert skill clamp and native reset handling only; no convoy spawning, original faction/group hooks or other sections imported | | `escapists-ai/Scripts/Game/EscapistsAI/EAI_AIConfig.c` | `8c320d3163d443b43e50547734702484c8ad51f2cffe88cf6dfd33aaf339ec01` | `stingerChanceOneIn`, default 15 and valid range 0..10000 | The successor HQ owns `ERR_EnemyEquipment`. Registration supplies exact physical groups; five startup scans discover initialized members. Entries retain exact actor/group identity, with 256 group and 2048 actor limits. Inventory grants are finite. Accepted pending operations are never repeated; a late callback after Stop cannot restart issuance. See the current loadout policy below for launcher and mine checks. The original fixed-FIM and one-in-N policy has been superseded by [percentage-based faction loadouts](enemy-loadouts.md). FIM-92 remains the fallback. Native slot constraints, mission ownership and finite grants remain enforced. Old `stingerChanceOneIn` settings migrate to the nearest integer percentage; 15 becomes 7%, 1 becomes 100%, and 0 stays off. The HQ page exposes both anti-air and AP-mine percentages. `/esc hq stinger` remains an alias but now accepts a percentage. ## Magnified optics `ERR_EnemyOptics` belongs to each existing equipment entry's exact actor/group and uses the same three-second startup cadence independently of Stinger completion. Its first eligible physical weapon roster is retained, with at most eight weapons. The automatic equipment grant explicitly registers its exact newly confirmed weapon, even after the original optics jobs finish; ordinary later pickups and replacement rifles are never enrolled. Duplicate registrations retain the original job and cannot replenish a removed optic. Rifle, sniper-rifle and machine-gun types qualify. Existing magnified optics are detected through the three native optics components on weapon children, attached sights and attachment slots. Inspection is bounded to 128 visited entities, four child levels and 16 attachment/storage slots; incomplete inspection refuses a grant. Occupied mounts remain occupied, including nonmagnified sights. The seven original candidate path/GUID pairs were independently checked against installed resource databases: vanilla PSO-1, ART II and 4x20; RHS PSO-1M2, 1P21, M8541 and 1P78. Their exact catalog entries belong in `vanilla-resources.json` and `external-addons.json`; no new dependency or external asset bytes are introduced. Candidates are drawn without replacement, and native `CanInsertResourceInStorage` must accept the same concrete free slot passed to `TrySpawnPrefabToStorage`. This does not override mounting compatibility or guarantee that every rifle accepts a scope. At most one native submission per registered rifle per check is allowed. Each explicitly issued weapon has its own five-check attempt window; the initial roster retains its original startup deadline. Explicit failure permits another candidate/slot before the fifth check; that final check only observes. An accepted unknown operation is never repeated, including after its deadline or Stop. A successful callback is terminal even if the optic is removed before physical observation. Ownership loss terminates processing, and Stop retains callback/tombstone state; the native API cannot cancel an insertion already accepted. No loose optics, replenishment, new actors or independent timer is added. `tests/test_enemy_optics.py` executes the actual service with native API doubles: all three scope component kinds, nested adapters, occupied/compatible mounts, original-rifle transfer, actor ownership loss, success/failure ordering, accepted-operation quarantine, late callbacks, bounded checks and malformed hierarchy limits. `tests/test_enemy_equipment.py` additionally verifies real entry Stop propagation, exact actor/group binding, optics cadence after Stinger completion, unregistration and ownership-loss teardown. These are policy proofs. Native compilation and physical attachment validation are pending for this optics change; they do not follow from earlier Stinger or convoy evidence. ### Native startup observation (2026-09-20, 05:09:06 run) The [archived full-addon native run](evidence/native-2026-09-20-050906-convoy-seat-diagnostic/report.json) compiled the optics service and executed it on ordinary mission/convoy equipment. Its `rereintroduced-hq.log` contains 59 terminal OPTICS records: six `physical magnified optic preserved/confirmed` and 53 startup deadlines without a confirmed compatible optic. The six confirmations occurred at world time 13.7 seconds. No explicit `native optic insertion completed` or unresolved-insertion quarantine record was emitted. This demonstrates normal startup execution and detection of physical magnified optics, not successful new attachment insertion. The physical-presence check runs before the callback check and uses the same event for preexisting and newly fitted scopes; the journal does not record actor/rifle identity or whether a request preceded confirmation. The 53 deadlines likewise do not distinguish an incompatible mount from other unconfirmed startup outcomes. The preservation path performs no insertion when a scope is already observed; a separate before/after observation of the same rifle would be required to qualify a new native insertion. No additional fixture or resource manipulation was performed for this checkpoint. The [final full-addon checkpoint](evidence/native-2026-09-20-053057-optics-security-hq-integration/report.json) compiles all current optics, vehicle and diagnostic classes and completes 56 HQ-memory assertions with zero script/runtime failures. Four installed external localization errors remain. This does not add new optic-insertion or multiplayer evidence. ## One-time group radio fitting `ERR_EnemyRadio` adapts the owner's one-basic-set-per-group behavior and distributed relay allocation. The inspected source sections are the radio capability helper and `LogConnection` relay block in `escapists-ai/Scripts/Game/EscapistsAI/EAI_HQ.c` (SHA-256 `4898ac471fb16433fc5d98244a8cec89c5e8e006af2c94bbcd89113a2b7107c8`) and the basic radio allocation block in `EAI_HQStatus.c` (SHA-256 `7127dcf23be7bcbb9415d8ef6c8f1da5bec551fbf16fc1054487dcd7a877d885`). Original files remain read-only. Original game-mode/helper dependencies and the unbounded later status retry are replaced with successor ownership and bounded startup state. HQ passes its stable registration ID to the existing equipment coordinator. A group whose positive ID is congruent to one modulo four is selected once for a manpack; other groups need only a basic radio. Duplicate registration cannot change that selection. The service uses the existing three-second equipment cadence, at most five checks, a completed native roster of at most 32 original soldiers, and at most 256 inventory items per soldier. There is no independent timer, tactical order or force creation. Candidate actors must first receive their canonical equipment entry. That coordinator retains exact-actor tombstones, so transferring a previously bound soldier into another newly registered group cannot grant it another pending radio. The radio service freezes the original complete crew, rejects changed/duplicate/dead/captured membership, and stops permanently on teardown. Unknown inventories block a new grant. Native default-loadout radios are inspected first: an existing basic set satisfies the basic allocation permanently, and an existing manpack satisfies both allocations. Removing that observed equipment does not reopen the allocation. Only the already-catalogued vanilla R148 (`E1A5D4B878AA8980`) and R107M (`54C68E438DD34265`) are requested; exact installed RDB path/GUID pairs were independently verified. Native `CanInsertResource(..., PURPOSE_ANY)` must accept a resource before insertion through the same actor's inventory manager. No occupied item is removed to make room. A selected manpack is attempted before a missing basic set, with a basic fallback if no original carrier has a fitting untried manpack slot. At most one native request may be submitted for the whole group per check, and each original actor/resource pair is attempted at most once. An accepted pending request blocks all other group radio requests. Explicit failure permits another original carrier before the fifth check, while callback success permanently spends that allocation even if the radio is removed before observation. The fifth check observes only; an unresolved accepted insertion is quarantined and is not repeated after deadline, Stop, group transfer or a late callback. Basic and relay allocations remain separate: an already observed basic set is never replaced, although a previously selected optional relay allocation may still finish during startup. Native operations already accepted cannot be cancelled by this service. Mortar groups explicitly opt out when HQ registers them: their existing readiness service owns gunner handsets and requires a dedicated physical RTO manpack. This prevents competing startup grants. Normal authored site/convoy radios are preserved by actual inventory inspection. HQ networking continues to derive capability solely from living physical carriers and inventories; fitting never declares a delivered report or invents a route. Journal outcomes distinguish an already equipped group with zero requests, recorded native callback completion, physical capability observed after a request without proven insertion provenance, and unresolved pending timeout. `tests/test_enemy_radio.py` executes the actual radio service and equipment coordinator against native API doubles, including cross-group pending-carrier transfer, no selection reroll, existing equipment/loss, malformed inventory/roster, explicit failure, success after removal, callback ordering, deadline and mortar opt-out. `tests/test_enemy_equipment.py` retains its separate equipment lifecycle regressions. The [native call/memory run](evidence/native-2026-09-20-062203-radio-call-memory/report.json) compiles this service and completes 59 assertions, with all six site groups reporting existing radios and zero new requests. Actual physical routes and interruption are exercised. New compatible insertion and ordinary/multiplayer loss/capture behavior remain pending. Four external localization errors remain; there are no script/runtime failures in this run. ### Scoped convoy gunner skill The existing mission-local combat binding already applies the owned extension's Expert (80) minimum to explicitly registered original military enemy actors, preserves higher settings, handles native reset and restores the pre-binding setting on release. The missing specialization now requests Cylon (100) only for a living original convoy turret occupant whose canonical task, consumed receipt, physical CONVOY ledger record, original member/seat pair and current native turret occupancy all agree. Driver and cargo occupants keep the ordinary minimum. Captured convoy groups are ineligible for equipment updates; cleanup restores our previous binding through the existing release path. The owned original forces a sticky convoy-gunner flag to exactly 100. This adaptation deliberately checks present physical ownership instead: leaving that original turret returns the actor to their underlying requested skill (with the ordinary 80 minimum); re-entering the same original turret restores 100. Higher underlying settings survive both transitions. Replacement actors, replacement seats, released or stopped tasks, transferred actors and player occupants cannot gain this specialization. The original server-wide mutation hook is not imported. Integration uses the existing equipment tick every three seconds, with no new scheduler. Native SetAISkill/ResetAISkill revalidate immediately. Native vehicle/capture state can therefore change between ticks; no continuous-frame guarantee is claimed. Existing release behavior removes the mission's previous contribution. No perception, aiming dispersion, target selection, force creation or equipment resources change. Policy tests execute the actual helper, scoped combat binding and equipment coordinator against native doubles: 25 individual authority/identity/seat failures, capture, floor/reset, 90/100 preservation, dismount/reboard, restoration and tick cadence. The [current native automatic-convoy run](evidence/native-2026-09-20-081658-automatic-convoy/report.json) compiles all changes, observes all nineteen original seated crew at Expert or higher and five actual turret occupants at Cylon, and completes93 assertions/one round. Zero script/runtime failures; four external localization errors remain. Native dismount/reset/capture transitions and multiplayer remain untested. Provenance (SHA-256; original inputs read-only): - Owner `EAI_AIResponseSystem.c`, skill setters/reset/init only: `b3e1263e986837744a70fbaedaa6e57afae7f2981a21211d3a2066e2c63ac84d`. - Owner `EAI_SupplyConvoys.c`, original turret designation in FillSeats only: `a896fdacfd9c0f2db52e588642623545a3a5d6e8041fb72000a68e720fc2b7a5`. - Vanilla `scripts/Game/AI/Components/SCR_AICombatComponent.c`, Expert=80/Cylon=100 and native setter/reset semantics: `79919aaf106d2d79caa83c948586cf6c3d284bd4a1f8db2e92179a1921f25cee`. - Vanilla `scripts/GameCode/Vehicle/BaseCompartmentSlot.c`, native slot-to-root-vehicle lookup: `c08cca13bb083a211c3a04019bb9a05a7f07ef4d4ce1dbd7112fcce6e8924f4c`. - Vanilla `scripts/Game/generated/Vehicle/TurretCompartmentSlot.c`, exact native turret type: `f6916f771f4ba51c677093fc5e4d91fec42bbb2ec28947985670b57617b96543`. No protected group lookup, original Escapists or ScrtCore implementation was read or reused.