docs(runicnpc): stage 6 built and walked; API 5; protocol §19.14

API.md version 5: the profile's boss and use blocks, the passive role
and stand, the boss hooks and OnRunicNpcUsed, role and boss in
RunicNpc_List, RunicNpc_Despawn taking a boss's adds, the example kits
written once, and a Kits reload taking RunicNPC with it (D283).

PROTOCOL.md §19.14: npc.boss.spawned, npc.boss.phase and npc.boss.died,
their classes, and runicnpc_api 5.

PLAN.md stage 6: what was built, the builds it was tested on, the
harness and the site walk on both rigs, and what building it found.
The example kits' permission is kits.runicnpc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-05 13:12:16 -05:00
parent 023ba77ceb
commit 6d319c843b
3 changed files with 174 additions and 12 deletions

View File

@@ -2541,3 +2541,44 @@ placements), a new one by clicking the live map (D245, D246). It adds the trigge
and titles (D247, D250, D252).
**Walked on both rigs, 2026-09-30** (runicnpc PLAN.md stage 4).
### 19.14 RunicNPC stage 6: bosses (runicnpc PLAN.md stage 6)
Stage 6's wire changes **join protocol 13** while it is unreleased (D282); no message changes shape, and
`PROTOCOL_VERSION` stays 13. The bridge now needs **RunicNPC API 5**: `RunicNpcApiNeeded = 5`,
**`runicnpc_api = 5`** in `overlay.toml`. An older RunicNPC answers `npc.error` `runicnpc-old` as before.
**A profile's `boss` and `use` blocks** travel in `npc.profiles` and `npc.profiles.set` as RunicNPC holds them
(runicnpc `API.md`); the bridge reads neither.
**Three events,** from RunicNPC API 5's boss hooks, for the site's public boss triggers (D277):
```json
{"kind":"npc.boss.spawned","type":"event","netId":"981204","profile":"juggernaut","name":"Juggernaut",
"owner":"run:42","runId":"42","x":-2123.7,"z":2282.7,"maxHealth":2500}
{"kind":"npc.boss.phase","type":"event","netId":"981204","profile":"juggernaut","name":"Juggernaut",
"owner":"run:42","runId":"42","x":-2120.1,"z":2290.4,"phase":2,"at":0.25,"health":611.3,"maxHealth":2500}
{"kind":"npc.boss.died","type":"event","netId":"981204","profile":"juggernaut","name":"Juggernaut",
"owner":"run:42","runId":"42","x":-2118.0,"z":2291.2,"killerId":"76561198000000002","killerName":"Marisol",
"damagers":5}
```
- The NPC fields are `npc.died`'s (§19.12): `owner`, and `runId` or `placement` from it.
- `phase` counts from 1; `at` is the phase's health fraction. A hit that crosses two thresholds sends both,
highest first.
- `npc.boss.died` is sent **beside** `npc.died`, which still carries every contributor. It names no Steam id
but the killer's, and counts the players who hurt the boss in `damagers`. `killerId` and `killerName` are
absent when no player landed the killing blow.
| `kind` | Hook | `class` | Why |
|---|---|---|---|
| `npc.boss.spawned` | `OnRunicNpcBossSpawned` | public | The game says a boss's spawn to everyone on the server (D286). It names nobody |
| `npc.boss.died` | `OnRunicNpcBossDied` | **presence** | Said to everyone too, but it names the killer, which says that player was on |
| `npc.boss.phase` | `OnRunicNpcBossPhase` | **staff** | The game tells a phase only to the players near the boss (D286) |
**Hooks.** `OnRunicNpcBossSpawned`, `OnRunicNpcBossPhase` and `OnRunicNpcBossDied` join `rg.hooks`' list.
**The website** (Module-Rust) adds the public triggers `rust.boss.spawned`, `rust.boss.phase` and
`rust.boss.killed` (ceiling `everyone`, default `subscribers`) for app, in-app and email rules; Discord hears
a boss only through an event's announce step (D277). The feed shows a boss appearing, and its death where the
server's presence setting allows. The profile form gains the boss box and the passive role.