feat(rust): loot on the NPC profile form, and the Place NPCs step's "drop loot" switch (runicnpc stage 7)

The profile form's Loot section (D290-D301):

- what the corpse starts with (Rust's scientist loot, the kit, or
  nothing);
- rows that always roll, each with its chance;
- a pool capped at its picks, with a "nothing" weight;
- which crate the table goes into, and a locked crate's hack time;
- how long the corpse stays.

The site checks the block as RunicNPC does, in its words. Whether an
item exists on a server is RunicNPC's to say on the push.

The Place NPCs step's dropLoot switch (D296), on by default and sent
only when off.

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-06 00:32:24 -05:00
parent bb3e25b5d7
commit 33c5178ef9
5 changed files with 295 additions and 1 deletions

View File

@@ -542,7 +542,7 @@ function placeVerb({ id, kind, budget, max, label, description, source, example
const orders = kind === 'npc' ? npcOrders(params, found.server) : { ok: true, wire: {} }
if (!orders.ok) return { ok: false, retry: false, error: orders.error }
if (profile === null && Object.keys(orders.wire).length) {
return { ok: false, retry: false, error: "escort, ally and tether are for one of the site's NPC profiles (RunicNPC), not Rust's own scientists" }
return { ok: false, retry: false, error: "escort, ally, tether and drop loot are for one of the site's NPC profiles (RunicNPC), not Rust's own scientists" }
}
if (verify) return { ok: true }
@@ -608,6 +608,15 @@ const NPC_ORDER_PARAMS = [
description:
'Keep the NPCs inside the zone this event made around the point (D272): a Make a zone step must come first. RunicNPC profiles only.',
},
{
// Runicnpc stage 7 (D296): on by default; a step older than the switch drops loot as before.
name: 'dropLoot',
type: 'boolean',
required: false,
example: true,
description:
"Whether the NPCs drop their profile's loot table when killed (D296). On unless switched off; off, their corpse still holds what the profile starts it with. An event's own rewards are separate. RunicNPC profiles only.",
},
]
/** The orders, checked, as the bridge reads them: `{ ok, wire }` or `{ ok: false, error }`. */
@@ -632,6 +641,7 @@ function npcOrders(params, server) {
wire.ally = { kind: 'player', id: teamOf }
}
if (params.tether === true || params.tether === 'true') wire.tether = true
if (params.dropLoot === false || params.dropLoot === 'false') wire.dropLoot = false
return { ok: true, wire }
}