Skip to content

Extraction

Source: PROJECT_CONTEXT.md §6, §8.2, §8.5, §9 (portal-guarding is an added system); config.js extraction; game.js callExtraction, updateExtraction, assignPortalGuards, endRun. Status: ✅ Implemented.

What it is

Extraction is how you bank a raid's haul. The whole run is loot collected but not yet safe; only by boarding a portal and leaving do you keep it. Extraction takes time and is loud, so it's the climax decision of every raid — get out clean, or push for one more chest and risk losing it all. Failing to extract (death or the storm) forfeits the run's loot, but never your equipped/stashed gear (the no-gear-loss loop, §1).

How it works

  • 3 extraction points (§8.5), placed by map gen with minimum spacing (extraction.spread) and kept away from spawn (extraction.spawnGap):
  • North GateclosesAt 0 (always available the whole raid).
  • Old WellclosesAt 180.
  • Hollow StumpclosesAt 300.
  • "Some close earlier than others" (§6) — each exit has its own availability window keyed off closesAt.
  • Call → incoming → window → board flow (callExtractionupdateExtraction, phases idle/incoming/open):
  • idle — walk onto the pad to summon the portal (no remote calling). callExtraction fires.
  • incoming — the portal travels in over extraction.incoming (the EXTRACT_INCOMING 22s arrival window per §8.2; live default is testing-set to 0). The call is loud — it recruits a capped number of nearby creatures (noise.recruitCap); repeating incoming pulses are player-warning sonar only.
  • open — the portal is boardable for extraction.window (EXTRACT_WINDOW 32s). You must reach the pad and board before it closes.
  • board — stand in the zone to fill the board meter. Passive boarding (free to act) takes extraction.boardPassive (BOARD_PASSIVE 9s); rooting to force it (channeling on the pad) is faster at extraction.boardForce (BOARD_FORCE 3s). Leaving the zone drains progress. At full meter endRun(true, …) banks the haul.
  • If the open window expires before you board, the portal returns to idle — call it again.
  • Clear the area first. Boarding takes real seconds of presence on a loud pad, so extraction means ensuring no enemies are near (§6). Rival raiders board under the same rules (extraction.boardBot = passive board time); a rival extracting raises an "intercept them" warning — you can ambush a boarding rival.
  • Portal-guarding AI (assignPortalGuards, §9 — an added system not in the concept): when a portal goes active, up to extraction.guardCap (GUARD_CAP 4) nearby ordinary creatures (not stationary, not boss, currently unalerted) are assigned to guard that one portal, circling it on a wide ring with a slip-in pocket. This watches the zone without rushing the whole map to the center. Guards release back to free patrol when the portal closes. Tutorial enemies are never repurposed as guards.
  • Failure = forfeit. If the round timer (map.roundTime, ~600s) runs out, the Wildmagic Storm consumes the map — escalating damage in the final 30s (updateStorm), and anyone still on the map dies. Dying or being caught by the storm calls endRun(false, …), which banks only the Safe Pocket (loot.safeSlots) and forfeits the rest of the run's loot — but equipped and stashed gear is untouched (§1).

Tunables

extraction group:

Key Default Meaning
extraction.incoming 0 portal travel time before it opens (s) — §8.2 reference is 22s; live default 0 for arrival testing
extraction.window 32 open window to board (s)
extraction.boardPassive 9 presence time to board while free to act (s)
extraction.boardForce 3 channel time if you root to force it (s)
extraction.boardBot 9 rival raider boarding time (s) — kept = boardPassive for symmetric rules
extraction.guardCap 4 max creatures guarding one portal
extraction.spawnGap 1000 min distance exits keep from the player spawn (px)
extraction.spread 850 min distance between two extraction zones (px)
extraction.tutorialIncoming 0 FTUE portal travel time (s) — no dead-wait
extraction.tutorialBoard 4 FTUE presence time to board (s)

Related: map.roundTime 600 (raid length → storm), loot.safeSlots 1 (protected slots that survive death), noise.extractCall 1160 / noise.portalIncoming 880 / noise.portalOpen 600 (the loud-pad noise radii).

Design intent

Extraction is where all the suspense, none of the gear-wipe punishment (§2 pillar 4) becomes concrete: the tension of getting out with the haul is real, but the only thing at stake is this run's loot. The call→incoming→window→board timing makes leaving a committed, exposed beat rather than an instant escape — you announce yourself (loud call), hold ground while the portal arrives, then stand exposed to board. Portal-guarding (§9) keeps the exit defended and beatable without funnelling the whole map to the center, supporting "route over reflexes" (§2 pillar 2). Staggered closes (Old Well @180, Hollow Stump @300) push the player to read the map's timing and pick a route, not camp one safe pad.

Open questions / deltas

  • incoming default 0 vs §8.2's 22s. The live config zeroes portal travel for arrival-time testing; the §8.2 reference is EXTRACT_INCOMING 22s. Restore before balancing the real arrival tension.
  • Portal-guarding is an added system (§9). Not in the original concept doc; flagged to carry forward to Unity unless deliberately cut.
  • closesAt semantics. In updateExtraction, a zone with closesAt > 0 is treated as unavailable while G.time < closesAt — confirm with design whether each named exit (Old Well, Hollow Stump) should open at or close at its timestamp before the Unity port; the §6 wording is "some close earlier than others."