The map tool renders and stores state. The Map Engine is the intelligence sitting in front of it. Everything in this chapter was proven by test — a validation chamber (TEST 01 / 01-R) and a full live combat loop (TEST 02) — not designed on paper. Build on top of it; do not redesign it.
The authority split
Two authorities share one world and neither may silently overrule the other:
- The 3E combat resolver owns legality in inches. Movement allowance (M7 = 7", M6 = 6"), Rush, Charge, Reposition, Overwatch, every modifier, every wound and save. It decides what is legal.
- The Map Engine owns geometry in metres. Positions, distances, footprints, terrain, elevation, line of sight, cover, path cost. It decides whether a legal action physically fits the world.
The map converts resolver inches to world distance only through a declared scale contract, map by map. In the validation chamber that contract is 1" ≙ 2 m — a local declaration, not a universal rule. Never let the map invent a second locomotion statistic, and never resolve a distance by eyeballing pixels: the measure actions return exact values.
The legality gate
Every movement runs the same sequence, and an INVALID result must never touch map state:
- REQUEST_MOVE — player/GM states intent, route, and endpoint.
- RESOLVER_ALLOWANCE — is the entity allowed to spend this distance?
- MAP_VALIDATE_PATH — does the legal action physically fit the world?
- MAP_APPLY_MOVE — only if both authorities agree.
MAP_VALIDATE_PATH evaluates the start position, the proposed path, the endpoint, the entity footprint, static collision geometry, dynamic token footprints, aperture clearance, terrain access and cost, elevation transition, movement-mode compatibility, and map boundaries. It returns VALID or a structured reason: COLLISION, INSUFFICIENT_CLEARANCE, BLOCKED_PATH, IMPASSABLE_TERRAIN, INSUFFICIENT_MOVEMENT, OUT_OF_BOUNDS, INVALID_ELEVATION_TRANSITION, UNSUPPORTED_MOVEMENT_MODE, RULE_PENDING.
Collision
Gameplay footprints, never token artwork. A moving footprint intersecting an occupied footprint beyond tolerance is COLLISION. Footprints by real size: human 1×1, Astartes 1×1–2×2, Terminator 2×2, Primarch/Dreadnought 2×2–3×3, vehicles true hull, Titans 6×6+. Exceptions (embarked, mounted, carried, grappling, swarm) need explicit rules; otherwise, no overlap.
Clearance
Openings declare aperture width/height; entities declare envelope width/length/height. A 1×1 Legionary passes a 1.2 m door; a 2 m Cataphractii is INSUFFICIENT_CLEARANCE. The token does not move.
Cost and routing
The map never changes M. It returns weighted path cost — sum over segments of (length × terrain multiplier) — and the resolver decides whether that cost may be spent. Waypoint routes are summed segment by segment; a bent route never costs its straight-line displacement. When a requested route is illegal, the engine proposes — never silently chooses: reject with a reason, compute legal route options, return PROPOSED_ROUTE with distance, cost, hazards, and reaction exposure, and let the player or GM confirm before the resolver re-checks and the map executes.
Elevation, LOS, cover
State is x, y, z even where rendering is 2D; relevant distances use the 3D form. LOS is traced from stored geometry — walls, bulkheads, terrain, smoke, large entities, elevation blockers — and returns only CLEAR / PARTIAL / HEAVILY_OBSCURED / BLOCKED. Cover is geometric (how much of the footprint is obstructed → NONE / LIGHT / PARTIAL / HEAVY / TOTAL) and is recomputed from current geometry on every attack, never cached. LOS and detection are separate systems: obscuration does not mean detection. Until automation exists, detection state (HIDDEN / SOUND_DETECTED / PARTIALLY_DETECTED / VISUAL_CONTACT) is GM-adjudicated through a reserved interface.
Building a map that survives contact
- Scale first. Set world size, grid, and snapping before any token exists. The scale contract is fixed before placement.
- One entity, one persistent token. Relocate by move, never by copying. Unique labels, distinct footprints.
- Terrain is tagged polygons, typed (OPEN, ROUGH, WALL, SMOKE, WRECKAGE…), each carrying movement modifier, cover value, height, visibility, destructibility, structural HP, hazard. Solid terrain blocks; non-solid terrain (smoke, elevated walkway markers) is annotated state, not collision.
- Place at logical entry points, never beside the player unless arrival permits it.
- Every lasting change is a mutation that persists. Combat reads its starting positions, distances, cover, and LOS from the map — never from arbitrary reset positions. When combat ends, the map receives final positions, casualties, wrecks, dropped weapons, fires, smoke, and breaches. A slain model becomes a named corpse token; a dropped weapon becomes a pinned object; a destroyed wall is renamed with a breach aperture area. Nothing resets, ever.
Extending the engine
v1 is frozen. New requirements ship as numbered patches (MAP-v1.1 formations, MAP-v1.2 detection automation, MAP-v1.3 vehicle collision) or as movement-mode modules (JUMP, VEHICLE, FLYER/AIRSPACE, TITAN, VOID, PSYCHIC). The tested infantry/Zone Mortalis foundation changes only on a demonstrated regression.
Before extending, reproduce the regression on Map Engine Validation Test 01 — the disposable Zone Mortalis chamber (60 × 30 m, bulkhead, destructible wall, 1.2 m door, 0.9 m choke, elevated catwalk, smoke spur, debris ×1.5, three cover grades, hidden patrol). Its sequence is the acceptance test: scale and boot scan, pre-mutation collision and clearance rejection with zero mutation, weighted multi-segment paths, LOS traces including dynamic cover recompute, a live MAP → resolver → combat → map loop, casualty and breach persistence, and a revisit check. A feature that cannot pass that harness is a MAP-v1.x candidate, not a license to touch the core.
What v1 does not do — and must not quietly grow: automatic detection or sound propagation, vehicle/flyer/Titan movement, void and psychic movement, and squad formation automation. Each is a module waiting for its own validation run, in that order of priority.