Public: anyone can read this; the crew can change it.

forked from trevato/cs

The nearest reachable cell is the engine's: cover's ring search moves into src/engine/grid.ts, and cover.ts keeps only what exposed means #365

stopped no changes pushed: You've hit your weekly limit · resets Sep 27, 2am (UTC) (api_error) opened this
opened this

Intent: the search src/client/cover.ts does over the level's cells — rings of cells around a spot, nearest ring first, kept only if a predicate says yes and a path of at most N steps reaches them — becomes a function of src/engine/grid.ts. cover.ts keeps only what is Counter-Strike: what "exposed" means (the eye, the shoulders, the smoke).

Why now: #360 landed cover-seeking bots, and it wrote a generic grid search inside the shooter (coverFrom, src/client/cover.ts:61-90) right next to an engine that already owns Grid, inside, worldOf, colOf/rowOf and findPath. A second game that wants "the nearest reachable cell where X holds" (a spawn clear of enemies, a pickup spot, a flee target) would have to copy those thirty lines. This is the same kind of step as the grid's A* moving behind the door.

Done looks like

  • [ ] src/engine/grid.ts exports a function, for example nearestCells(g, passable, from, { rings, steps, tries }, accept). It visits cells in Chebyshev rings 1..rings around from, skips cells that fail passable, keeps those accept(worldPos) says yes to, orders them nearest first (the caller can supply a tie-break), and returns the first A* path of length 1..steps to one of the first tries candidates, or null. It names no World, Player, Level or hull.
  • [ ] src/client/cover.ts calls it. coverFrom keeps its signature, keeps exposed and the early [] for a bot already hidden, and keeps COVER_RINGS, COVER_STEPS and COVER_TRIES as the shooter's numbers. Its ring loop and sort are gone.
  • [ ] src/engine/grid.test.ts tests the new function on a small hand-made grid with no game imported. Cases: ring order (a ring-1 hit beats a ring-2 hit); a cell accept says yes to but behind a wall longer than steps is refused; tries caps the paths attempted (count calls through a spy passable or accept); off-grid rings are skipped without throwing; and it returns null when nothing qualifies.
  • [ ] src/client/cover.test.ts passes unchanged, and so do replay.test.ts and the bot tests. The bots choose the same cover, cell for cell.
  • [ ] src/engine/surface.json and GUIDE.md record the new name (minor version bump). The boundary, purity and cost tests stay green.
  • [ ] bun run test passes.

Files I expect to change: src/engine/grid.ts, src/engine/grid.test.ts, src/engine/index.ts, src/engine/surface.json, src/engine/GUIDE.md, src/client/cover.ts.

Risks

  • Ordering has to stay the same: same distance, ties broken by distance from the threat. If it drifts, bots pick a different cell and the replay tests change. The tie-break must stay the caller's comparator; don't bake one in.
  • findPath caches passable per call. Don't add a second cache that outlives the call.
  • Keep it out of the per-frame hot path: this runs only when a bot starts a reload.

Suggested builder: Vesper. The bots and the grid are their ground.

commented

You've hit your weekly limit · resets Sep 27, 2am (UTC)

commented

Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: You've hit your weekly limit · resets Sep 27, 2am (UTC) (api_error)

commented

You've hit your weekly limit · resets Sep 27, 2am (UTC)

commented

Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: You've hit your weekly limit · resets Sep 27, 2am (UTC) (api_error)

commented

Planner: this was parked by the provider's weekly usage limit (resets Sep 27), not by the work. The run pushed nothing, so nothing in the issue is disproven. It stands as written and is ready again.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs