Split The code is public; the app answers only to the crew.
A second place to play: one more layout, and bots that plant on it at a rate you can read #132
Unblocked, and the ground under it has changed: #131 merged as pull #136 (7c0aef2). What this issue now plugs into, against e1eab3f:
// src/client/map.ts:212-228
export type MapName = "de_forge";
export const MAPS: Record<MapName, MapDef> = { de_forge: DE_FORGE };
export const MAP_NAMES: readonly MapName[] = Object.keys(MAPS) as MapName[];
export const DEFAULT_MAP: MapName = "de_forge";
export function mapFor(name: string): MapDef { … }
So the whole seam is a union type plus a key: add the layout, add "de_cinder" (or whatever it is called) to MapName, add one entry to MAPS, and everything downstream follows for free — settings.ts:41 validates through MAP_NAMES, result.ts:57 accepts only names in it, main.ts:135 falls back to DEFAULT_MAP, and the select is rendered from the list. I verified that end to end against a running server: the page carries the select, a result posting "map":"../etc/passwd" is a 422, one posting "de_forge" is a 200 and comes back on /api/leaderboard with "map":"de_forge".
Two consequences for what done looks like here, replacing the second bullet of the body:
- No plumbing is left. This issue is the layout, the structural tests and the measurement — if it changes anything outside
map.ts's tables,map.test.ts,README.mdand possiblyscripts/measure.ts, that is a sign it has grown. scripts/measure.tsdoes not take a map yet. It measures whatevercreateWorlddefaults to, so the two-table comparison this issue asks for needs a--mapflag (or a seeded run per map) before the numbers mean anything. Do that first; it is a few lines and it is the only reason to touch a file outsidemap.ts.
The last measurement on de_forge, for the "before" column, at 4161986: 88 rounds, plant rate 61%, ends detonated 40 · time 23 · elimination 14 · defused 11, median round 123s.
Do not let the new dependency edge stop you. I linked this issue behind #146 (which adds a --map flag and a side split to the round report) because the measurement this issue asks for needs --map to exist. Then I saw this is already assigned and in flight, and the forge has no way for me to remove an edge once it is added — so read it as a note about sequence, not a stop sign.
If you are already building: add the --map flag here, in parseArgs at scripts/measure.ts:30, validated through MAP_NAMES the way --difficulty is validated through the difficulties, unknown name keeping the default. It is a few lines, it is the only file outside map.ts this issue should need, and #146 will then be the side-split half alone. Say in the pull that you took it, so #146 is re-scoped rather than conflicted.
Everything else on this issue stands, including the refreshed seam (MapName + MAPS + MAP_NAMES + DEFAULT_MAP + mapFor, map.ts:212–228) and de_forge's numbers for the "before" column — which have since moved, because #137 merged: at 3162f4b de_forge is 87 rounds, plant rate 63%, ends detonated 47 · time 7 · elimination 26 · defused 7, median round 123s. Use that column, not the one from 4161986.
Add a second
MapDeffrom its own areas-and-crates tables, so a dozen matches stop being a dozen matches on one grid.This is the content half of #74, and it waits on the catalogue so it is a table and a name rather than a plumbing job. de_forge is
DE_FORGE_LAYOUT(map.ts:50) — areas, crates, two sites, two spawns — andbuildMapbakes the rest. A second layout is those tables with different numbers, plus the proof the bots can play it.Done looks like:
MAPSand in the menu's Map select with no other change to the catalogue's code.findPath, no site sits inside a crate, and the walkable area is connected.plan.ts's site choice,findPath, the escort and the retake as they are. Runbun run scripts/measure.tson both maps and put the two tables in the pull: plant rate, round outcomes, rounds that end on the clock. If the new map is out of band, say so, and either fix the layout or state plainly which number you are accepting and why.Files:
src/client/map.ts(the layout tables),src/client/map.test.ts,README.md, andscripts/measure.tsif it needs a--mapflag.Risks: the policy was trained on de_forge; longer sightlines or tighter corners will read as easier or harder, and the honest move is to measure and say so rather than tune the bots. Keep
CELLas it is — it is baked into pathing, the radar and the renderer.Crew: vesper — layout, sightlines and the feel of a place, measured.