Compare commits

...

1 Commits

Author SHA1 Message Date
eb729f7dd4 docs(runicnpc): stage 5 build decisions D267-D272
The org lead's answers to the six questions the stage 5 build raised
(2026-10-01): a Harmony patch for the safe-zone sentries under the
condition that it never reaches Rust's own scientists (D267), faction pairs
both ways and shooting back (D268), escort as an order that walks home
when the target is gone (D269), the event step's escort and ally (D270),
the PVE opt-out as two checkboxes (D271), and the tether on placements and
event steps rather than profiles (D272).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-01 07:00:39 -05:00

View File

@@ -6,8 +6,9 @@ decided with it. **Stage 1 measured 2026-09-30** (§9): six answers on both rigs
**Stage 2's design answered 2026-09-30:** D232–D238 (§0), which reshape stage 2 (§9). **Stage 2 built and tested
2026-09-30** on both rigs (§9); its API is [API.md](API.md). **Stage 3's design answered 2026-09-30:** D239–D242
(§0). **Stage 3 built and tested 2026-09-30** on both rigs (§9); its in-game walk waits for a player. **Stage 4's
design answered 2026-09-30** (D243–D252, §0), **built and walked 2026-09-30** on both rigs (§9). **Stage 4's
design answered 2026-09-30:** D243–D252 (§0).
design answered 2026-09-30** (D243–D252, §0), **built and walked 2026-09-30** on both rigs (§9). **Stage 5's
design answered 2026-09-30 and 2026-10-01** (D253–D266, §0), **its spike measured 2026-10-01** on both rigs (§9),
and **its build's own questions answered 2026-10-01** (D267–D272).
RunicNPC is Runic Gateway's own NPC plugin for Rust servers, in its own repository,
[`RunicGateway/runicnpc-rust`](https://gitea.whitlocktech.com/RunicGateway/runicnpc-rust). It runs on Oxide and
@@ -83,6 +84,12 @@ architectural or design decision is implemented.
| **D264** | **`turrets: always` means the safe-zone sentries too**: Outpost's and Bandit Camp's turrets shoot that profile's NPCs as they shoot a hostile player. `default` is what Rust does (player turrets shoot it, safe-zone sentries do not), and `ignore` means no turret shoots it (stage 5 spike, refines D259). | Dropping `always`, since `default` already means player turrets. |
| **D265** | **The main weapon's ammunition is endless, as in Rust.** An NPC never runs dry, and its loot keeps the kit's ammunition. Only D260's extras (syringes, grenades, rockets and the like) are used up (stage 5 spike, refines D260). | Ammunition used up shot by shot; a per-profile setting. |
| **D266** | **Fire burns as it does in Rust.** A flamethrower NPC's flames burn every NPC in them, its own allies included, because Rust filters only bullets between NPCs. Admins place flamethrower NPCs with that in mind (stage 5 spike). | Our NPCs taking no fire damage from their allies. |
| **D267** | **`turrets: always` reaches the safe-zone sentries through a Harmony patch.** Rust's sentry (`NPCAutoTurret`) refuses every scientist in `Ignore` and `IsEntityHostile`, before any Oxide or Carbon hook runs. RunicNPC patches those two methods so they answer "hostile" for its own NPCs whose profile says `always`, and as Rust does for everything else, as the zone and dome helpers patch their plugins (D181). It unpatches on unload, and a failed patch is reported at boot. **The org lead's condition: if the walk shows a sentry targeting Rust's own scientists or bandit guards, the sentry half of `always` is dropped** (stage 5 build, refines D264). | RunicNPC handing nearby sentries the target again every 0.25 s; dropping the sentries from `always`. |
| **D268** | **A faction pair is one row, both ways.** "bandits ↔ guards: hostile" makes each hunt the other; the table is a grid with one cell per pair. **Any of our NPCs that is shot fights back at whoever shot it**, whatever the table says, as it does a turret (D259) (stage 5 build). | Each direction set separately. |
| **D269** | **Escort is an order, not a role.** Any roamer or guard profile can be told to escort, by an event step, the API or `/rnpc follow` (D258). Its NPCs keep within a few metres of the target and fight whoever attacks it. **When the target dies or leaves the server, they walk back to where they were placed** and carry on as their profile does there (stage 5 build). | Holding the spot where the target was lost; an `escort` role whose NPCs stand idle until given someone. |
| **D270** | **An event's Place NPCs step names the escort by a player's Steam id** (typed, or a `{placeholder}` filled from the run's start params), **and the ally by a clan from the site's clan list, or as "the team of player &lt;Steam id&gt;"**. Both are optional (stage 5 build). | One Steam id for both; the ally alone, with escort left to the API. |
| **D271** | **A profile's PVE opt-out is two checkboxes: "players can hurt it" and "it can hurt players"**, both on by default. Turning one off is enforced by RunicNPC itself on every server, with a PVE plugin or without one, and TruePVE and NextGenPVE are told the same. Turrets, fire and other NPCs are not affected (stage 5 build, refines D261). | One "follow the PVE rules" switch, with unkillable meaning `damageTaken` 0. |
| **D272** | **A zone tether is set on a placement (`tether=<zone>`) and on an event step ("inside the zone this event made"), not on a profile**, because a ZoneManager zone belongs to one server and a profile may be pushed to several (stage 5 build, refines §6). | A profile field; a profile default overridden per placement and step. |
**Borrowing, not copying.** NpcSpawn states no licence at all, so its source grants us nothing and is read only as a
description of *what* can be done in Rust. HumanNPC is MIT on uMod, which is GPL-compatible, but §1.2 rules out its
@@ -369,7 +376,9 @@ own (D257). Allies within a profile's alert radius join a fight one of them is i
**Zone tethering** keeps an NPC inside a ZoneManager zone. At the edge it turns back, and if it ends up outside (it
was pushed, or the zone moved) it is returned home. ZoneManager is already required by `module-rust`; to RunicNPC it
is optional, and a profile that asks for a tether on a server without it is refused at save.
is optional. **The tether is a placement's (`tether=<zone>`) or an event step's, not a profile's (D272)**, because a
zone belongs to one server; a placement that names a tether on a server without ZoneManager, or a zone it does not
have, is refused when it is set.
---
@@ -969,10 +978,25 @@ What this adds to the build (D263–D266):
- **Turrets (D264):** `default` needs no code. `ignore` answers `CanBeTargeted` with "no" for the auto turret, flame
turret and trap. `always` makes Outpost's and Bandit Camp's sentries (`NPCAutoTurret`) target it, which Rust's own
`Ignore` and `IsEntityHostile` refuse for every `ScientistNPC`. Stage 5's build finds the hook that reaches those
two, or answers for the sentry from RunicNPC's side, and says which in this plan.
two, or answers for the sentry from RunicNPC's side, and says which in this plan. **No hook reaches them: Rust's
`AutoTurret.TargetScan` calls `Ignore` before anything Oxide or Carbon injects, so it is a Harmony patch (D267).**
- **Ammunition (D265) and fire (D266):** nothing to build. The NPC's reload stays Rust's own, and fire damage is not
touched.
**The build's own questions, answered by the org lead on 2026-10-01 (D267–D272):**
1. **How a sentry is made to shoot an `always` NPC. → D267:** a Harmony patch on `NPCAutoTurret.Ignore` and
`IsEntityHostile`, for our `always` NPCs only. If the walk shows a sentry targeting Rust's own scientists or
bandit guards, the sentry half of `always` is dropped.
2. **Whether a faction pair runs both ways. → D268:** one row, both ways; and any of ours shot fights back.
3. **Escort as a role or an order, and what happens when the target is gone. → D269:** an order any roamer or guard
takes; they walk back to their spot when the target dies or leaves.
4. **How an event step names the escort and the ally. → D270:** a Steam id (or `{placeholder}`) for the escort; a clan
from the site's list, or the team of a player, for the ally.
5. **The PVE opt-out's shape. → D271:** two checkboxes, "players can hurt it" and "it can hurt players", enforced by
RunicNPC itself.
6. **Where a tether is set. → D272:** on a placement and on an event step, not on a profile.
### Stage 6 — Roles
Bosses (a health bar drawn with CUI, phases at thresholds that swap profile values, announcements through the bridge