Extraction¶
Source: PROJECT_CONTEXT.md §6, §8.2, §8.5, §9 (portal-guarding is an added system);
config.jsextraction;game.jscallExtraction,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 Gate —
closesAt 0(always available the whole raid). - Old Well —
closesAt 180. - Hollow Stump —
closesAt 300. - "Some close earlier than others" (§6) — each exit has its own availability window keyed off
closesAt. - Call → incoming → window → board flow (
callExtraction→updateExtraction, phasesidle/incoming/open): - idle — walk onto the pad to summon the portal (no remote calling).
callExtractionfires. - incoming — the portal travels in over
extraction.incoming(theEXTRACT_INCOMING 22sarrival window per §8.2; live default is testing-set to0). 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 atextraction.boardForce(BOARD_FORCE 3s). Leaving the zone drains progress. At full meterendRun(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 toextraction.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 callsendRun(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¶
incomingdefault 0 vs §8.2's 22s. The live config zeroes portal travel for arrival-time testing; the §8.2 reference isEXTRACT_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.
closesAtsemantics. InupdateExtraction, a zone withclosesAt > 0is treated as unavailable whileG.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."