Files
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

14 KiB
Raw Permalink Blame History

T10 — Migrating the old AI mod's proven behaviour under HQ control

Read docs/living-island/README.md first, including the rules section. Depends on T1, T2, T5, T8, T9. Mostly ai addon.

The predecessor project at /home/jakub/devel/escapists/escapists-ai already implements much of what the living-island plan describes — hunting UAZ convoys, a timed reconnaissance helicopter, reactive roadblocks, guard check-ins, body discovery, mortar sites and supply convoys. That work is the maintainer's own design and is the reference for this task.

This brief says what to carry across, what the real parameters were, and — most importantly — how the architecture must change on the way.


1. Provenance and licensing — read before opening any source file

Category Files What you may do
Maintainer's own design Most of escapists-ai Carry the design: timings, distances, sequences, failure handling. Re-express the code against vanilla and ERR interfaces.
Calls into protected API 36 of 48 files reference ESCT_* Those calls cannot come across — ERR has no Escapists dependency. Replace each with a vanilla or ERR equivalent. A call is not a copy, but the replacement must be written fresh.
Contains copied protected code EAI_GroupLookup.c Do not port, do not adapt, do not read as a model. An independent comparison found 666 matching token sequences with the protected ESCT_GroupLookup / ESCT_CharacterLookup. Build group composition from vanilla entity catalogs from scratch, as ERR_FactionCatalog already does.

Also binding:

  • tools/check.py:39 rejects any EAI_*, ESCT*, SCRTC_*, SCRT_* identifier. Everything is renamed to ERR_*, and no old prefix survives in a comment either.
  • Every {GUID}path must be in docs/vanilla-resources.json or owned here. The prefabs quoted below are vanilla and were verified against the installed resourceDatabase.rdb; add any that are missing from the manifest.
  • Do not copy the old files wholesale and rename the symbols. Each system below is re-implemented against the ledger, the belief layer and the presence budget.

2. The architectural change — this is the point of the task

In the old mod, each behaviour was an independent subsystem with its own timer and its own spawning: EAI_AirReconSystem ran a launch clock, the response system held a five-minute radio cooldown, the roadblock planner ran its own placement loop, mortars managed their own crews. They competed for the same world with no shared budget and no shared picture.

In this project every one of them becomes a capability the HQ planner selects, under one force pool, one agent budget and one belief:

ERR_HQ  ──  belief (T8)  ──  what HQ thinks it knows
   │
   ├── plans against objectives and beliefs (T5 scoring, T9 alert states)
   │
   └── chooses a capability and spends the pool:
         ground response · air search · roadblock · mortar fire ·
         supply convoy · garrison deployment (O1–O6)

Concretely, for every system below:

  • No private timers. A capability offers "available / not available, ETA, cost"; the planner decides when. The old per-system cooldowns become availability rules the planner reads.
  • No private spawning. Units come from the ledger and the pool. A capability requests a record; ERR_PresenceBudget decides what is physical.
  • No private world picture. Capabilities act on beliefs (T8). Nothing queries player positions directly.
  • Losses hit the shared pool. A destroyed hunter UAZ is a section gone from the same pool that garrisons checkpoints.

Delete rather than port: EAI_Performance.NearPlayer / ConvoyLOD. That was an embryonic presence system; T2 replaces it, and two competing presence systems is worse than either alone.


M1 — Detection: check-ins, losses and bodies

Source: EAI_HQWatch.c, EAI_HQBodySearch.c, EAI_HQStatus.c

This is the missing trigger for the occupation alarm, and it already exists.

  • Periodic check-ins. Each unit owes HQ a status report every CHECK_IN_MS (180 s), with REPLY_MS (30 s) to answer. A unit that misses its check-in is not assumed dead — HQ opens an investigation and sends someone to look. That is the mechanism OCCUPATION.md referred to as "a guard check-in missed".
  • Loss confirmation. OnControllableDestroyed records a loss as unconfirmed; HQ only knows once a unit reports it. SquadLimit(baseline, confirmedLosses) shrinks what HQ can commit as its confirmed losses mount.
  • Body discovery. Bodies are found by units that can actually see them — InView(distance, facing) plus a visibility trace, scanned at most every 15 s per unit, capped at 16 tracked bodies. A found body queues radio evidence: casualty evidence, cause unknown. Quiet kills stay quiet until someone walks past the corpse, which is exactly the stealth counterplay worth keeping.

Port as: an ingest path into T8's belief and an alarm source for the occupation plan. A discovered body creates a low-confidence belief at that position; a missed check-in creates an investigation belief at the unit's last known location. Keep the trace budget (m_Traces) — it is what stops body scanning from costing a fortune.


M2 — Ground response: the hunter convoy

Source: EAI_AIResponseSystem.c

The proven behaviour, with its real numbers:

  • Two armed UAZs — {0B4DEA8078B78A9B}Prefabs/Vehicles/Wheeled/UAZ469/UAZ469_PKM.et — spawned on roads EAI_RESPONSE_DISTANCE (1000 m, ±100 m tolerance) from the contact, on opposite sides: candidate bearings must be at least 30° from directly opposite (dot ≤ -0.866), up to 12 placement attempts.
  • Each vehicle is filled with spec-ops and exactly one medic, all seats occupied.
  • One convoy is kept alive and re-tasked when a later report gives a new contact, rather than spawning a fresh one per sighting. It is replaced only when a vehicle is lost.
  • A global radio cooldown of 300 s gates how often a response can be triggered.
  • Convoy gunners were given maximum AI skill. Keep a deliberate skill choice, but make it a setting rather than a constant — see the pacing rules in T9.

Port as: the ground hunting capability in T9. The 1000 m opposite-approach placement is exactly T9's "at most two bearings, escape vector left open" rule — implement it once, here, and have T9 use it. Respect T9's minHunterSpawnMetres (700 m): never place a response vehicle closer than that to any player, which the old EAI_ResponseSafety and EAI_SettlementSafety checks were already approximating.


M3 — Air search: the reconnaissance helicopter

Source: EAI_AirRecon.c (1335 lines — the richest system in the old mod)

This is T9's hunter helicopter. Build one system, not two.

Behaviour worth carrying:

  • Launch timer. heliTimerMinutes (default 15, range 1–1440) schedules the first departure and each subsequent one. Losing the aircraft schedules a replacement rather than ending air search permanently.
  • Airport discovery, spread over time. The island is scanned in 2000 m columns across successive updates — never in one frame — matching runway and control-tower prefabs, clustering structures within 1000 m into one airport and tracking the cluster centre. A named marker entity short-circuits the search. Keep the incremental scan pattern; it is a good model for any map-wide query in this project.
  • Landing pad selection. 12 attempts at 35–220 m from the centre, rejecting water, requiring flatness within 1.5 m across a 12 m cross, a 14 m radius cylinder clear of low obstacles, and a clear box up to 150 m overhead.
  • Phased flight with a landing retry: if a landing has not settled within 180 s, search for a new pad (re-checked every 30 s within 150 m of home).
  • Air observation feeds HQ through the same report path as ground units.

Change on the way across:

  • Fold into T9's air search: one airborne at a time, endurance-capped, observing under the same line-of-sight rules as infantry.
  • The launch timer becomes availability, not a trigger. The planner asks for air search when a belief justifies it; the timer only says whether an airframe is ready. A helicopter must not launch into an empty sky because a clock fired.
  • Draw the airframe from the shared pool, so searching competes with lifting.
  • Replace ESCT_Misc.IsPositionInWater and ESCT_RoadNavigation calls with vanilla equivalents (SCR_TerrainHelper, SCR_WorldTools, vanilla road API).

M4 — Reactive roadblocks

Source: EAI_HQRoadblocks.c

Distinct from T3's authored checkpoints: these are placed in response to a contact, ahead of where HQ thinks the player is going.

  • Ahead(position, velocity, site) rejects any site that is not in front of the contact's travel. FreshDirection(distress, hasVelocity, age, speed) decides whether a heading estimate is trustworthy enough to predict from at all.
  • Sites are snapped to real roads via a road-approach search, within 200 m of the chosen point, with a 25 m probe to orient the block along the road.
  • Placement requires ground clearance, distance from players, and being outside settlements.

Port as: the cordon mechanism in T9. T8's belief gives a better input than the old raw velocity: use the uncertainty circle and the objective-route inference to choose chokepoints between the belief and its likely destination. Keep Ahead and FreshDirection as pure rules — they are good, testable logic.


M5 — Mortar sites

Source: EAI_MortarSystem.c, EAI_MortarEngagement.c, EAI_MortarFiring.c, EAI_MortarPrediction.c, EAI_MortarSalvo.c

Much of this is already migrated (ERR_Mortar*). What is missing is site placement as an HQ capability: the old system chose where a battery stands, spawned a 2B14 with crew and an RTO, equipped nine HE shells per crewman, pulled shells from nearby donors when the gunner ran dry, reserved airspace over the impact area, and audited site status (claimed / startup / operational / crew fighting / shells / radio connected / cooldown).

Port as: a MORTAR_SITE objective in the occupation plan (O1). HQ deploys a battery to a site like any other garrison — it costs a section from the pool, travels by the normal methods, and takes time to become operational. A mortar battery that is spent, overrun or out of shells stays spent. Keep the airspace reservation and the existing fairness: a battery fires at beliefs, delivered by radio, never at live player positions.


M6 — Logistics and the threat extras

Lower priority; schedule after M1–M5.

Source What it gives Port as
EAI_SupplyConvoys.c (1463 lines) Road convoy logistics with real routing The convoy method in O4; reuse the road-following and slot logic, not the ESCT calls
EAI_Resupply.c, EAI_AmmoSupply.c, EAI_DepotLoading.c, EAI_LogisticsVehicle.c Ammunition and depot chains A resupply capability that keeps garrisons and batteries fighting — finite, so cutting a depot matters
EAI_StingerEquipment.c A rare Launcher_FIM92_Stinger on enemy infantry, one in N Anti-air threat against the player's stolen helicopter — the escape must not be trivially safe. Keep it rare and keep it a setting
EAI_ImprovisedPrisons.c Recapture rather than only killing A strong escape-fiction feature: an unconscious escapist can be taken, not just killed. Worth its own task later
EAI_Mines.c, EAI_MineTask.c Mines laid on routes Optional; only with clear warning cues, or it is pure frustration
EAI_AirAssault.c, EAI_AssaultParachute.c Airborne insertion Already covered by O3 air lift; do not build a second insertion path
EAI_HelicopterRecovery.c, EAI_Landing.c, EAI_AircraftAmmo.c Aircraft servicing and recovery Feed into the transport provider rather than a separate system

Acceptance criteria

  1. No EAI_*, ESCT_* or SCRTC_* identifier appears anywhere in addons/; python3 tools/check.py passes.
  2. EAI_GroupLookup.c has not been ported in any form; group composition comes from vanilla catalogs through ERR_FactionCatalog.
  3. Every migrated capability draws units from the ledger and the shared pool. Grep proves it: no capability calls a spawn helper directly.
  4. No migrated system owns a private timer that triggers behaviour. Timers only report availability to the planner.
  5. A missed check-in produces an investigation; a discovered body produces a low-confidence belief; both are visible in the journal.
  6. A contact triggers one re-taskable hunter convoy, not one per sighting, and never places a vehicle within 700 m of a player.
  7. Air search launches because a belief justifies it, never because a clock fired into an empty sky.
  8. Destroying hunters, the helicopter or a mortar battery permanently reduces what HQ can do next — verified in the metrics.
  9. Active agents stay inside activeAgentBudget with every capability in play.

Tests to write

tests/test_detection.py — check-in timing and reply windows; SquadLimit shrinks with confirmed losses; InView rejects a body behind the observer; the body-scan interval and tracking cap hold.

tests/test_ground_response.py — opposite-bearing placement satisfies the 30° rule and the 1000 m ± 100 m band; the 700 m minimum to players holds; a second contact re-tasks the existing convoy instead of spawning another; cooldown gates repeats.

tests/test_air_search.py — the launch timer reports availability but never triggers a launch on its own; pad selection rejects water, slopes over 1.5 m and obstructed overhead; landing retry fires after 180 s.

tests/test_roadblock_siting.py — Ahead rejects sites behind the contact; FreshDirection refuses a stale or speedless heading; chosen sites lie between the belief and its inferred objective.

Do not

  • Do not port a file by renaming its symbols. Re-implement against the ledger, the belief and the budget.
  • Do not recreate the old parallel-subsystem architecture. One planner, one pool, one budget, one picture.
  • Do not port EAI_GroupLookup.c, and do not use it as a reference while writing the replacement.
  • Do not let any migrated capability read player positions directly. Everything acts on beliefs earned through observation and radio.