pub struct QuestsContent {Show 18 fields
pub quests: Vec<Quest>,
pub guidance: Guidance,
pub waves: Vec<Wave>,
pub triggers: Vec<EnvTrigger>,
pub actors: Vec<Actor>,
pub traps: Vec<Trap>,
pub shortcuts: Vec<Shortcut>,
pub timed_gates: Vec<TimedGate>,
pub loot: Vec<Loot>,
pub state: Vec<StateDecl>,
pub on_death: Vec<QuestEffect>,
pub lethal_volumes: Vec<LethalVolume>,
pub shops: Vec<Shop>,
pub stakes: Vec<Stake>,
pub assemblies: Vec<Assembly>,
pub loops: Vec<Loop>,
pub ambushes: Vec<Ambush>,
pub ambushes_expanded: bool,
}Expand description
Stage 5 payload: quest expansions.
Fields§
§quests: Vec<Quest>The expanded quests (1:1 with stage 4).
guidance: GuidanceHow loudly the campaign guides (spec-0093): the default for every
objective’s marker and announcement. Absent = both shown, which is
what every campaign written before the block existed gets, byte for byte.
waves: Vec<Wave>Combat waves (DSL v0.3). Each wave is spawned by a spawn-wave effect and
slain to complete a kill objective. Empty/absent in v0.2 campaigns.
triggers: Vec<EnvTrigger>Environment triggers (DSL v0.4, spec-0008 §7): “the world answers”. Each
watches an anchor for a strike / use / approach event and fires a bundle
of QuestEffects. Empty/absent in v0.2/v0.3 campaigns.
actors: Vec<Actor>Scripted actors (DSL v0.6, spec-0014): NoAI/Silent/no-loot puppets moved by compiler-emitted per-tick teleport. Distinct from stage-2 NPCs (no dialogue, any mob type). Summoned/removed/moved/unleashed by the actor staging effects. Empty/absent before v0.6.
traps: Vec<Trap>Traps (DSL v0.6, spec-0011; command payloads spec-0022): environmental
hazards, each at one point anchor an area’s prefab provides. Each says
what springs the trap, what it then does (a command payload, a legacy
dispenser effect, or both), how dangerous it is, how it is disarmed and
whether it re-arms. Empty/absent in pre-0.6 campaigns, so a v0.5-or-earlier campaign that declares none stays
byte-identical.
shortcuts: Vec<Shortcut>Shortcut doors (spec-0016 §2): a gate that is sealed from world-load and is opened — permanently — from the FAR side. Empty/absent in pre-0.6 campaigns, so a campaign that declares none stays byte-identical.
timed_gates: Vec<TimedGate>Ambushes (spec-0016 §3): sugar over “deferred actors + a trigger that springs them”. Empty/absent in pre-0.6 campaigns.
Never serialized. parse_campaign expands
each ambush into triggers, so the canonical form of a campaign is its
desugared form. That is what keeps the canonical round-trip idempotent
(re-parsing canonical output finds no ambushes and so cannot expand a
second time and duplicate the trigger ids), and it means the sugar exists
at exactly one layer boundary — the authored .json — with nothing
downstream needing to know it was ever there. The list itself is kept in
memory so diagnostics can name the ambush the author wrote.
Timed gates (spec-0016 §4): gates on a deterministic open/close clock.
Empty/absent in pre-0.6 campaigns.
loot: Vec<Loot>Container fills (spec-0021): pre-placed chests/barrels in the prefabs given contents at world init. Empty/absent in pre-0.6 campaigns .
state: Vec<StateDecl>Runtime state data (DSL v0.10, spec-0031): named, scoped, integer-valued counters the campaign sets, adds to and clears at runtime, and compares against in any gate. A campaign that declares none emits none of it.
on_death: Vec<QuestEffect>The campaign’s death beat (DSL v0.10, spec-0031): effects run at the
moment a player dies, for that player. Effect root R7
(crate::EffectRootKind::OnDeath); a campaign that declares none emits
none of it.
Why this is campaign-wide and not a field on a checkpoint. The engine
already has on_respawn, and it hangs off a set-checkpoint because
where you come back is a property of the checkpoint. That you died is
not: it is true at every point of the delve, under every checkpoint, and a
bundle repeated on each checkpoint would be the same content written N
times with N chances to forget one. So death is a moment in the campaign,
and this is the one place it is named. Anything that should only happen in
some phase of the delve is expressed by the ordinary per-effect
requires_flags / forbids_flags gate every other root already carries —
no second gating surface.
Audience is the dying player (Audience::Solo, the audience
on_respawn and on_caught already use): a death is one player’s, and
re-broadcasting it to the party would duplicate their narration and their
kit. A beat the whole party should see is a narrate addressed by the
author to the party through the effect’s own vocabulary, not a different
default here.
Timing. It fires on the death edge while the player is still a corpse
(Health: 0.0f, on the death screen) — see
emit::emit_checkpoint_functions. That is the difference between this and
on_respawn, which deliberately waits for the player to come back.
lethal_volumes: Vec<LethalVolume>Lethal volumes (DSL v0.10, spec-0031): declared boxes that kill whatever enters them. Empty/absent in pre-0.10 campaigns, so a campaign that declares none stays byte-identical.
shops: Vec<Shop>Shops (DSL v0.10, spec-0032): interaction points that open a list of gated offers. Empty/absent in pre-0.10 campaigns, so a campaign that declares none stays byte-identical.
stakes: Vec<Stake>Recovery stakes (DSL v0.10, spec-0032): what a death forfeits, where the marker lands, and how it comes back. Empty/absent in pre-0.10 campaigns , so a campaign that declares none stays byte-identical.
assemblies: Vec<Assembly>Assemblies (spec-0082): fixed things built of display entities that
play clips from a library rig, can be struck in melee, and strike back
at a player who stands where they reach. Appear on spawn-assembly,
leave on despawn-assembly. Empty/absent = nothing emitted.
loops: Vec<Loop>Loops (spec-0086): slabs whose crossing returns a body by a whole-block offset to an identical earlier section, held while a party gate is open. Empty/absent for every campaign that declares none, so such a campaign stays byte-identical.
ambushes: Vec<Ambush>§ambushes_expanded: boolWhether Self::expand_ambushes has already run (never serialized). The
authored ambushes are deliberately KEPT after expansion so validation
and the counterplay proof can attribute diagnostics to the ambush the
author actually wrote; this flag is what makes a second expansion a no-op.
Implementations§
Source§impl QuestsContent
impl QuestsContent
Sourcepub fn all_triggers(&self) -> Vec<EnvTrigger>
pub fn all_triggers(&self) -> Vec<EnvTrigger>
Every environment trigger this stage produces: the authored triggers
followed by the ones each ambush desugars to (spec-0016 §3), in
declared order.
This is the single trigger authority. Validation, the l10n inventory, the flag/wave producer scans, the nav proofs and emission all read triggers through it, so an ambush behaves exactly like the trigger an author would otherwise hand-write — there is no second code path for the sugar to drift down. Deterministic (declaration order, no hashing).
Sourcepub fn answers_press_at(&self, anchor: &str) -> bool
pub fn answers_press_at(&self, anchor: &str) -> bool
Does the campaign itself answer a right-click at anchor?
One predicate, read by both consumers of the press-answer rule, so they can
never disagree about what “the campaign answered it” means: the compiler’s
synthesis (plan::collect_press_answers, which stands down where this is
true) and the obligation on a shortcut door (DW0429, which fires where it
is false). Split across the two crates they would drift, and the drift
would read as “the compiler refused a door I answered”.
Deliberately the widest reading — any use trigger anchored there.
Pressing it already does something the author chose, and the engine does
not adjudicate whether what they chose counts as an answer.
Sourcepub fn expand_ambushes(&mut self)
pub fn expand_ambushes(&mut self)
Desugar every ambush into a real environment trigger and clear the
ambush list (spec-0016 §3). Called once, by
parse_campaign; idempotent by construction
(a second call sees no ambushes left to expand).
Sourcepub fn state_decl(&self, id: &str) -> Option<&StateDecl>
pub fn state_decl(&self, id: &str) -> Option<&StateDecl>
The declared datum with this id, if any (DSL v0.10).
Sourcepub fn stake_decl(&self, id: &str) -> Option<&Stake>
pub fn stake_decl(&self, id: &str) -> Option<&Stake>
The declared stake with this id, if any (DSL v0.10, spec-0032).
Sourcepub fn assembly_decl(&self, id: &str) -> Option<&Assembly>
pub fn assembly_decl(&self, id: &str) -> Option<&Assembly>
The declared assembly with this id, if any (spec-0082).
Trait Implementations§
Source§impl Clone for QuestsContent
impl Clone for QuestsContent
Source§impl Debug for QuestsContent
impl Debug for QuestsContent
Source§impl<'de> Deserialize<'de> for QuestsContent
impl<'de> Deserialize<'de> for QuestsContent
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for QuestsContent
impl JsonSchema for QuestsContent
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read more