mirror of
https://github.com/vladtrc/iw4L
synced 2026-10-25 18:05:19 -04:00
51 lines
2.6 KiB
Markdown
51 lines
2.6 KiB
Markdown
# `bots` — host AI
|
|
|
|
Authority tick: observation → memory → utility → task → route → motor → UserCmd.
|
|
|
|
`bot dummy [N]` creates bots with no controller or perception queries. They keep
|
|
their aim and weapon, accept `bot tp/give/fire`, and take damage and respawn normally.
|
|
They retain normal bot loadouts/perks; `bot hold off` leaves dummies idle.
|
|
Bots submit `TickInput.cmds` like players — [`SIM-STEP.md`](SIM-STEP.md).
|
|
|
|
| file | owns |
|
|
|---|---|
|
|
| `observation.rs` / `memory.rs` | what a bot may know, and for how long |
|
|
| `sensor.rs` | visibility probes and the rotation that spends them |
|
|
| `controller.rs` / `task.rs` / `intent.rs` | scores, task choice, stages |
|
|
| `nav.rs` | the baked graph, A\*, resumable route requests |
|
|
| `query.rs` | the shared collision budget every subsystem draws on |
|
|
| `weapon.rs` / `motor.rs` | the weapon channel; aim and movement |
|
|
|
|
## The three rules that shape the rest
|
|
|
|
**A negative needs a probe that ran.** Visibility answers seen, evaluated and
|
|
not seen, or not evaluated. Only the second ends a contact; the third holds it,
|
|
briefly and without coordinates. Firing needs a positive observation of that
|
|
client, fresh on the tick the command goes out.
|
|
|
|
**A denied query is not a collision.** Perception, connectors, execution and
|
|
combat share one 96-query quota. A query that ran reports what it found even on
|
|
the last token; one that never ran comes back as denial, so no refusal is ever
|
|
fabricated from an empty budget.
|
|
|
|
**Work survives a tick that is granted nothing.** A route request owns its
|
|
phase — approach, attachments, search, validation — and every cursor inside it
|
|
is resumable, so a zero allocation repeats nothing and A\* keeps its frontier
|
|
under the shared 2048-expansion quota. Answers that follow from graph topology
|
|
alone are cached per request key until the graph changes; collision-dependent
|
|
refusals are rechecked.
|
|
|
|
## Movement and combat
|
|
|
|
The graph bakes world-aligned tiles at 48 units, refined to 24 near missing
|
|
support or a height change, with directed Walk, Drop and BreakGlass edges that
|
|
keep their entry and exit through execution. A fight moves to a *position*: one
|
|
baked support per sector around the threat, checked for line of fire and
|
|
exposure, then reached through the ordinary route executor — reachability is
|
|
never inferred from a component label.
|
|
|
|
`HostController::decision()` exposes scores, stage and objective; the periodic
|
|
aggregate adds per-subsystem query counts and stuck bots. Both read live from a
|
|
running match, which is where bot behaviour is judged: `make map mp_boneyard`
|
|
([`RUN.md`](RUN.md)) and watch the aggregate.
|