Files
EscapistsReintroduced/docs/living-island/T1-force-ledger.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

94 lines
3.9 KiB
Markdown

# T1 — Force ledger and route simulation
Read `docs/living-island/README.md` first, including the rules section. Follow it.
## Goal
Introduce a server-owned record of every enemy formation on the island that does
not require those formations to exist as entities. Dormant records move along
routes using arithmetic on a slow tick. This is the foundation for everything
else in the living-island work.
## What to build
Create `addons/core/Scripts/Game/ERR/ERR_ForceLedger.c`:
```
enum ERR_ForceKind { GARRISON, PATROL, CHECKPOINT, CONVOY }
enum ERR_ForceDuty { HOLD, PATROL_ROUTE, MOVE_TO, SEARCH, RETURN }
class ERR_ForceRoute // ordered waypoints + loop flag
class ERR_ForceRecord // id, kind, position, heading, route, progress,
// strength, casualties, duty, dutyTarget,
// importance, radioCapability, group (null when dormant),
// lastSimulatedAt, stateSince
class ERR_ForceLedger // owns records; register/unregister/find/count/status
```
Create `addons/core/Scripts/Game/ERR/ERR_ForceSimulation.c` with a **pure rule
class** plus the tick that applies it:
```
class ERR_ForceRules
{
// pure, engine-free, unit-testable
static float Speed(ERR_ForceKind kind, ERR_ForceDuty duty); // m/s
static int Advance(...); // returns new route index
static vector Step(vector from, vector to, float speed, float seconds, out bool arrived);
static bool Due(int id, float now, float lastSimulatedAt, float interval); // staggered
}
```
Rules:
- Dormant records advance along their route polyline by `speed * elapsed`.
Walking speed default 1.4 m/s, vehicle convoy 11 m/s, a holding garrison 0.
- **Do not raycast, do not query the navmesh, do not touch the world** for
dormant records. Straight-line interpolation between authored route points is
the intended fidelity. Authored routes follow roads; that is the content's job,
not the simulation's.
- Y coordinate: keep the authored route point's Y. Only call `ERR_Actors.Ground()`
at the moment a record is materialised (that is T2's job, not yours).
- Tick interval default 2000 ms, staggered by `id % 8` so records do not all
update on the same frame.
- Cap the ledger at 128 records. Refuse beyond that and log once.
## Wiring
- `ERR_GameMode` owns the ledger, created next to the existing services
(`m_Sites`, `m_Discovery`, …). Expose `ERR_ForceLedger Forces()`.
- Tick it from the existing game-mode tick path. **Do not add a new timer or
`EOnFrame`.**
- `ERR_SiteService` registers a `GARRISON` record for each site guard group it
already creates, so the ledger has real content from day one. The site's
existing patrol cycle waypoints become the record's `ERR_ForceRoute`.
- Records whose group dies must be marked eliminated and stop simulating.
## Acceptance criteria
1. With five authored sites, the ledger holds five garrison records after
preparation, and `Status()` reports them.
2. A record with a 4-point looping route returns to its start after the expected
time, within 5% — verified by the Python test, not by eye.
3. Advancing 128 records for a simulated hour performs no world queries and no
per-record allocation.
4. `python3 tools/check.py` passes.
## Tests to write
`tests/test_force_ledger.py`, using `tests/policy_harness.py`:
- Extract `ERR_ForceRules.Step` and `Advance` with `body()` and run them as C++:
a 4-leg loop advanced in 2 s steps arrives at each leg in the expected order
and wraps correctly.
- `Speed` returns 0 for `HOLD`, and a convoy outruns a foot patrol.
- `Due` staggers: across ids 0..7 at the same `now`, not all are due.
- Off-by-one on the final leg of a non-looping route ends at the last point and
reports arrival exactly once.
## Do not
- Do not spawn or despawn anything in this task. T2 owns materialisation.
- Do not reference `ERR_HQ` — this is core.
- Do not add a `ref array` member that grows without a cap.