Files
EscapistsReintroduced/docs/living-island/T5-hq-integration.md
T
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

4.3 KiB
Raw Blame History

T5 — HQ commands the ledger

Read docs/living-island/README.md first, including the rules section. Depends on T1, T2. This task is in the ai addon. Core must not learn about HQ.

Goal

Today ERR_HQ.Assign() can only task groups that physically exist near a contact. After this task, HQ tasks ledger records — including dormant ones far away — so a response can come from across the map, travel virtually, and materialise when it arrives. This is what makes the island feel coordinated rather than reactive, and it costs nothing while the responder is off-screen.

What to build

  1. A core-side interface, implemented where the ledger lives. Add to ERR_ForceLedger (core):

    int   Available(vector near, float radius, out array<int> ids);
    float EstimateSeconds(int recordId, vector destination);   // distance / Speed()
    bool  Order(int recordId, ERR_ForceDuty duty, vector target);
    bool  Pin(int recordId, bool pinned);
    ERR_ForceKind KindOf(int recordId);
    int   StrengthOf(int recordId);
    

    These are generic force-management calls, not HQ concepts, so core owning them does not violate the dependency direction.

  2. HQ uses them. In ERR_HQ.Assign(), replace first-fit-within-radius with a scored choice over ledger candidates:

    score = ContactPriority(report) / max(EstimateSeconds(id, target), 1)
            - CostOfLeaving(KindOf(id))
    

    CostOfLeaving is high for a CHECKPOINT or a garrison at an objective and low for a roving PATROL. Put this in a pure ERR_HQTaskingRules class so it is testable.

  3. Ordering a dormant record. A dormant record receives the order through the ledger and changes duty to MOVE_TO/SEARCH; it travels virtually and materialises through T2's normal proximity rules when it nears players. HQ pins the record once it is within 1 km of the contact so it cannot go dormant mid-engagement.

  4. Radio realism is preserved. The existing ERR_HQNetwork rules apply unchanged to physical units — a carrier that dies mid-transmission still kills the message. For a dormant record, evaluate the same relay geometry against ledger positions and the record's radioCapability, with the same hop limits and latency, but without entities. Log both paths to the journal so the two are distinguishable.

  5. Fairness invariant, unchanged: dormant records never observe and never generate contacts. They only receive orders and move. Enforce it in code, not by convention — Observe() must refuse a record without a physical group.

Acceptance criteria

  1. A contact reported near the radio station can be answered by a patrol 3 km away, which travels while dormant and appears as real AI on arrival.
  2. Checkpoint garrisons are not stripped to chase distant contacts — verify that CostOfLeaving keeps them in place unless nothing else is available.
  3. HQ's journal shows the ETA it used and the record it chose, so the decision is auditable after the fact.
  4. Killing the radio operator of a physical reporting unit still severs the report, exactly as today.
  5. python3 tools/check.py passes.

Also fix while you are here

ERR_HQUnit.Eligible() allocates a fresh array<AIAgent> on every call, and Assign() calls it inside a contacts × units nested loop every 5 s. Cache the agent array on the unit and refresh it on the network tick instead. Likewise, replace the six linear scans over m_Units keyed by group (ReserveGroup, LogisticsToken, ReserveLogistics, MortarConnected, Downlink, QueueSupplyStatus) with a map<SCR_AIGroup, ERR_HQUnit> lookup.

Tests to write

tests/test_hq_tasking.py:

  • EstimateSeconds scales with distance and with kind speed.
  • The scored choice prefers a closer patrol over a distant one at equal priority, and prefers a distant patrol over a checkpoint garrison at equal distance.
  • With only checkpoint garrisons available and a high-priority contact, one is eventually released — the cost is a weight, not a veto.
  • A dormant record refuses to produce an observation.

Do not

  • Do not let HQ spawn units directly. It asks the ledger; the budget decides.
  • Do not add ERR_HQ references to core files.
  • Do not remove the existing radio latency or failure handling to simplify this.