Quick Design Spec: Enemy AI
Type: New Small System Scope: Enemy behaviors, the AI architecture (state machines + separation steering), spawning/aggro/leash rules, per-docking guard variation, and density caps. Does NOT own: the combat interface (combat Rule 11 — telegraphs, damage, stagger, interrupt flags, archetype HP/damage bands, all locked there), spawn positions (LDU's layout), or node/carcass semantics (Harvesting). Date: 2026-08-27 Estimated Implementation: ~5–6 days (3 archetypes on one shared architecture)
Overview
Enemies are the risk half of every docked land's offer. This system gives combat's three locked interface exemplars their actual behavior: simple host-simulated state machines with separation steering — not behavior trees, not utility AI; three archetypes at MVP scale don't justify the machinery (PR tripwire honored: the behaviors are *named below*, and anything beyond them is scope creep by definition). Enemies exist only on docked lands (home is hostile-free by definition), are placed by LDU's deterministic layout, vary per docking through the same variationSeed, and are ephemeral — nothing about them persists, ever.
Core Rules
- The three MVP behaviors, named (PR flag closed). All parameters per-archetype in data; bands cited from combat's Formulas baseline (HP/damage locked there, not here):
- Rusher — chase-and-lunge: direct pursuit at high move speed; in reach → lunge melee (weapon-raise telegraph, ≥ 400 ms, interruptible); short recovery. Teaches punish timing. The swarm archetype: spawns in 2–3s.
- Spacer — kite-and-throw: maintains
preferredRange(backpedals if closed on); thrown attack (long visible wind-up arc, uninterruptible); repositions after each throw. Teaches repositioning under pressure. - Bulwark — advance-and-slam: slow relentless approach; heavy single-target slam (long telegraph, uninterruptible); long recovery — the universal punish window writ large. Teaches commit-vs-bail. Guards deep-band value.
- Architecture: flat state machine per enemy, host-simulated. `Dormant → Aggro → (Approach ⇄ Attack cycle per combat's Telegraph/Active/Recovery) → Dormant`. The host runs all AI; clients render replicated transforms + combat's telegraph events — no client-side AI, no prediction of enemies (the confirmed netcode model). Behavior trees/utility systems are **explicitly out of scope at MVP** — a future archetype that doesn't fit a flat machine is a Tier 1 design conversation, not a refactor smuggled in.
- Separation steering (the prototype's flagged fix). All moving enemies apply a separation force within
separationRadius— enemies never stack into one blob (prototype REPORT: they did). Steering is movement-layer only; it never delays or cancels an attack cycle. - Aggro and leash. Aggro on proximity (
aggroRadius) or on taking damage (always). De-aggro when the target is farther thanleashRadiusfrom the enemy's guard post or unreachable fordeAggroSecs; on de-aggro the enemy returns to post at patrol speed and heals to full via combat'sLeashReset()(ADR-0012 — the AI never writes HP; no partial-HP cheese on a leashed guard; a fight you leave is a fight reset). Enemies never pursue onto the home island — the shore threshold is an absolute leash (home hostile-free, stated everywhere). - Aim disambiguation: enemies always win (harvesting's rule, cited): a strike that could hit a node or an enemy resolves against the enemy. This system adds nothing — the rule lives in harvesting/combat; named so no reader looks for it here.
- **The telegraph-density cap (combat's binding CD advisory, mechanized). At most one** uninterruptible telegraph may target a given player at any instant (
maxUninterruptibleTelegraphsPerTarget = 1). Before a Spacer/Bulwark enters Telegraph, it checks the cap; if held, it repositions/waits — it never queues into a lockout. Rushers (interruptible) are exempt. The CC ban is on the experience, not the mechanism. - Spawning: at land activation, fixed for the docking. LDU hands
(template, variationSeed, spawnPoints[]); this system chooses composition per point. No respawn within a docking — a cleared approach stays cleared until the land departs (mirrors node depletion; "the world heals" on recurrence). **Enemy state is fully ephemeral**: never saved (save-persistence two-class rule — no enemy table exists). Honest consequence: reloading mid-docking re-derives enemies fresh fromvariationSeed— killed enemies return while harvest diffs persist. Accepted for a friends-only game; the alternative (a per-docking kill diff) is a new save table with one beneficiary and is deliberately not built. - **Guard variation is load-bearing (harvesting review H5, delivered here).** Composition per spawn point is a pure function of
variationSeed: which archetypes guard which posts, patrol path selection, and facing vary per docking within authored per-template bounds. Node counts never change (harvesting's fixed content) — *who stands between you and the node* does. This is the live-variance mechanism that keeps a memorized template's push decision alive; if playtest shows repeat visits feel solved anyway, this rule is the falsified claim (harvesting OQ8's other half). - **Density scales with value (harvesting's joint constraint, given numbers).** Guard presence per band: shore 0–1, mid 1–2, deep 2–3 per approach (
guardDensityByBand, provisional). A rich unguarded node breaks the risk premise — deep-band spawn points must outnumber shore's in every template (authoring rule, load-warned). - Fauna clause (standing constraint, no MVP content). Any future fauna-type enemy never drops materials on death (Pillar 3; harvesting's handshake) and never spawns a carcass node (carcass placement stays a pure function of the seed — harvesting CD A1). Stated now so Tier 2 husbandry inherits it.
- Party scaling: the lever lives here, pre-armed (combat H4 contract): if the friend-group playtest shows 5-player mob-shredding, the response is raising
guardDensityByBand/ HP within combat's bands — never per-hit damage reduction (combat owns that ban). No scaling ships at MVP (scalingContextarrives empty from LDU, reserved).
Tuning Knobs
| Knob | Default | Range | Category | Rationale |
|---|---|---|---|---|
aggroRadius | 6 u | 4–10 | feel | Big enough that greed gets punished, small enough that shore harvesting isn't ambushed |
leashRadius | 14 u | 10–20 | gate | Fights stay near the guarded thing; kiting a Bulwark across the land is a choice, not an exploit |
deAggroSecs | 6 s | 3–12 | feel | Unreachable-target give-up timer |
separationRadius | 1.2 u | 0.8–2.0 | feel | Anti-blob force radius (prototype fix); too high scatters packs unnaturally |
maxUninterruptibleTelegraphsPerTarget | 1 | fixed at MVP | gate | The lockout cap — combat's CD advisory; raising it is a combat-GDD conversation, not a tune |
guardDensityByBand | shore 0–1 / mid 1–2 / deep 2–3 | ±1 per band, monotonic across bands | curve | The risk gradient AND the party-scaling lever (Rule 11); monotonicity load-checked |
Values live in assets/data/enemy-ai.json; per-archetype movement/attack parameters in per-archetype data validated against combat's load rules (telegraph ≥ 400 ms etc. — combat AC-20 already rejects violations).
Acceptance Criteria
- [ ] [UNIT] Composition/patrol selection is a pure function of
(template, variationSeed)— same docking key → identical guards on every machine and reload; differentcycleIndex→ different composition within authored bounds (Rule 8). - [ ] [UNIT] The telegraph-density cap: with two uninterruptible archetypes aggroed on one player, the second never enters Telegraph while the first's is active — it repositions (Rule 6; the AC combat's Dependencies row mandates).
- [ ] [UNIT]
guardDensityByBandmonotonicity (shore ≤ mid ≤ deep) is load-checked; a template whose deep spawn points don't exceed shore's produces a loud authoring warning (Rule 9). - [ ] [UNIT] De-aggro resets HP to full and returns the enemy to post; the home-island shore threshold is never crossed by any pursuit path (Rule 4).
- [ ] [UNIT] Schema-negative: no enemy state appears in any save table; no fauna drop table exists (Rules 7/10).
- [ ] [INTEGRATION] Full docking cycle: spawn at activation → some killed → no respawn for the docking's remainder → land departs → next docking of the same template re-derives a different guard composition (Rules 7/8 under NGO runtime).
- [ ] [INTEGRATION] Separation: 5 Rushers aggroed on one player never overlap into a single blob silhouette (the prototype's failure case, re-tested).
- [ ] [EXPERIENTIAL] Each archetype's behavior is readable before its telegraph (chase vs kite vs advance) — a new friend can name which enemy does what after one land (silhouette + behavior legibility).
- [ ] Regression: AI never calls anything but
EnterTelegraph(attackId)andLeashReset()(the two-call boundary, ADR-0012 §3 / ADR-0015 amended 2026-09-11) on the combat boundary (combat Rule 11 owns everything downstream); Hurt never interrupts a harvest swing (harvesting's rule unbroken by any AI behavior).
Systems Index
Already tracked as MVP system #12 (Gameplay, quick-spec, "Separation flagged by prototype"). On approval: status → Designed (quick-spec) — the PR "name the behaviors" tripwire is closed, combat's mandated density AC exists, and harvesting OQ8's Enemy AI half has its delivery mechanism (verify at playtest).
Forward refs owned elsewhere: AI tick replication/relevancy → decided by ADR-0012 (2026-09-11): one NetworkObject per enemy, EnemyTransform Server-authority at tick rate, EnemyNet{Phase, AnimFrame, Archetype, ActorId}, no relevancy (ADR-0008); host-only EnemyAI.Tick as step 3; straight-line steering, no pathfinding — originally: netcode ADR; archetype art/silhouettes → art bible §5 + /asset-spec; prosperity scaling values → Tier 1 (via LDU's reserved scalingContext); base-defense behaviors → Tier 1 first-to-slip (explicitly not designed).