feat(rust): bosses and passive NPCs on the profile form, and public boss triggers (runicnpc stage 6)
The profile form's boss box (D273-D277): the bar's distance, where its lines are said, the spawn and death lines, and phases at health percentages, each with optional damage, aim, speed, ranges, a kit swap, adds of another profile and a line. The passive role (D278, D279, D288): press E answers with a chat line or a window, it moves as its profile says (now including `stand`), and it starts unhurtable. The site checks both as RunicNPC does, in its words; a phase's kit is checked on each server like the profile's own, and its adds must name a site profile that is not a boss. Public triggers rust.boss.spawned, rust.boss.phase and rust.boss.killed (D277) from the bridge's new frames. In the feed, a boss appearing is public; its death names the killer, so it sits behind the presence setting; its phases are staff's, as the game tells them only to players near it (D286). engagement-triggers.json regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -163,6 +163,8 @@ async function describe() {
|
||||
roles: shape.ROLES,
|
||||
turrets: shape.TURRETS,
|
||||
kitUses: shape.KIT_USES,
|
||||
announces: shape.ANNOUNCES,
|
||||
useModes: shape.USE_MODES,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,8 +214,20 @@ async function validate(input, id = null) {
|
||||
if (shared) throw new NpcError(`a profile called "${name}" is already on ${shared.name || shared.id}`, 409)
|
||||
}
|
||||
|
||||
// Stage 6 (D275): a phase's adds are another of the site's profiles, and never a boss, as RunicNPC refuses.
|
||||
const all = active(await db.listProfiles())
|
||||
for (const [i, phase] of ((checked.value.boss && checked.value.boss.phases) || []).entries()) {
|
||||
if (!phase.adds) continue
|
||||
const named = all.filter((p) => p.name === phase.adds.profile && p.id !== id)
|
||||
if (phase.adds.profile === name) throw new NpcError(`boss.phases[${i}].adds.profile: a boss does not summon itself`)
|
||||
if (named.length === 0) throw new NpcError(`boss.phases[${i}].adds.profile: there is no profile '${phase.adds.profile}'`)
|
||||
if (named.some((p) => p.body && p.body.boss)) {
|
||||
throw new NpcError(`boss.phases[${i}].adds.profile: '${phase.adds.profile}' is a boss, and a boss does not summon bosses`)
|
||||
}
|
||||
}
|
||||
|
||||
const covered = allServers ? list : requested.map((s) => byId.get(s))
|
||||
await checkKits(checked.value.kits, covered)
|
||||
await checkKits(shape.kitsOf(checked.value), covered)
|
||||
|
||||
return { name, body: checked.value, allServers, servers: allServers ? [] : requested, killsScope }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user