跳到主要内容

Lattice 语法参考 · 第 2 章,共 4 章

Block、内容与线性流转

Block 是流转能直接指向的最小段落。它把创作元数据、可见内容、可选连续性批注和恰好一个流转终结语句组合在一起。

Block 声明

text
block opening (
  title: "警告",
  purpose: setup,
  summary: { 玛拉找到了信号源。 },
  setup: [signal_arc],
  tags: [opening]
) {
  text: { 一束光从花园地下苏醒。 };
  next -> answer;
}

每个 Block 必须同时满足以下规则:

  • ID 在所有导入文件中保持唯一;
  • 必须有 titlepurpose
  • 至少包含一条可见的 textdialogue
  • 内容条目写在终结语句之前;
  • 恰好有一个终结语句,并且所选故事类型与当前位置允许它;
  • 所有目标都存在,并留在主故事或当前 Module 内。

Block 元数据

字段必填接受的值含义
title文本面向读者/作者的段落标题
purpose目的标识符Block 的叙事功能
summary文本简短的作者侧摘要
prose_target正整数可重新分配的局部创作预算
setup标记 ID 列表引入叙事承诺
requires标记 ID 列表期待此前已有铺垫
resolves标记 ID 列表回收此前的铺垫
tags文本或列表创作分类

prose_target 要求 Story 已经声明完整的正文目标。它用于引导渐进创作,但不会独立决定 Block 是否有效。

purpose 接受以下值:

常见用途
setup建立角色、处境、问题或承诺
exposition提供读者需要的背景
development推进已经建立的线索
transition在地点、时间或阶段之间移动
turn改变事件方向或意义
climax通过决定性行动解决核心压力
resolution展示核心冲突之后的结果
payoff兑现此前承诺的揭示、后果或情感回报

这些值服务于校验和创作工具,但不会创建流转。

叙述

叙述由 text、冒号、正文值和分号组成:

text
text: {
  车站时钟始终分秒不差。
  玛拉看着秒针越过午夜。
};

一个 Block 可以按阅读顺序包含多条叙述与 Dialogue。

text
text: { 铁轨开始低鸣。 };
dialogue ch_mara: { 那列车早到了一天。 };
text: { 站台上没有人回头回答。 };

text 是可见内容。发布校验会拒绝只有批注或流转、没有正文和对白的 Block。大纲校验会暂时允许这种结构,以便在创作正文前检查最终 Block 图、摘要、预算和连续性关系。预览和导出绝不会用作者侧摘要代替缺失的读者正文。

Dialogue 对白

声明形态是 dialogue <character-id> (<metadata>): <prose>;

text
dialogue ch_mara (
  mode: whisper,
  emotion: cautious,
  expression: focused,
  pose: listening,
  position: left,
  stage_direction: { 她俯身贴近土壤。 }
): { 别再来了。 };

说话者必须引用已声明的 character。所有 Dialogue 元数据都是可选项。

字段接受的值含义
modespeechthoughtwhispershout说话方式
positionleftcenterright阅读器中的展示位置
emotion标识符面向素材的情绪状态
expression标识符面向素材的面部表情
pose标识符面向素材的身体姿势
stage_direction文本独立动作或舞台提示

展示字段会保留到预览/导出,但不会改变 Block 流转、Guard 或运行时 State。缺少素材也不会创建故事分支。

轻量连续性标记

Block 元数据可以描述铺垫和回收,而不增加运行时逻辑:

text
block warning (
  title: "警告",
  purpose: setup,
  setup: [signal_arc]
) {
  text: { 每当玛拉朝向北方,钥匙就会搏动。 };
  next -> crossing;
}

block crossing (
  title: "穿越",
  purpose: development,
  requires: [signal_arc]
) {
  text: { 她相信那阵搏动,踏进雾里。 };
  next -> answer;
}

block answer (
  title: "答案",
  purpose: payoff,
  resolves: [signal_arc]
) {
  text: { 搏动拼出了她自己的名字。 };
  end;
}
  • setup 引入一个标记。
  • requires 表示这个 Block 期待标记此前已经出现。
  • resolves 表示这个 Block 回收该标记。

标记 ID 是创作事实,不是声明的 State。它不能让 Module 变得可用、满足 Pool 退出条件,也不能记住普通玩家选择。

结构化连续性事件

结构化批注写在叙述和 Dialogue 之间:

text
foreshadowing fs_signal: event {
  subject: ch_mara,
  object: it_key,
  predicate: notices,
  time: "黎明之前"
};

reveals rv_signal resolves fs_signal: event {
  subject: ch_mara,
  object: it_key,
  predicate: understands,
  time: "午夜"
};

foreshadowing 有自己的 ID。reveals 也有自己的 ID,并指出它回收哪条 foreshadowing。

事件必须包含 subjectpredicateobjectplacetime 为可选字段。事件值可以是标识符、字符串、数字或布尔值。这些批注只描述叙事证据。即使它的元组形态与 CYOA State 相似,也绝不会激活或移除 State。

流转终结语句

每个 Block 恰好以以下一种形态结束:

终结语句形态可以使用的位置
自动继续next -> target;线性与 CYOA;同故事或 Module
结局end;线性与 CYOA;结束整个故事
玩家选择choice { option ... }CYOA;同故事或 Module
进入 Poolenter pool_id -> resume;仅 CYOA 主故事
完成 Modulecomplete (...);仅 CYOA Module

不存在隐式顺序执行。文件或 Scene 里的下一个 Block 不会自动运行,除非终结语句明确指向它。

线性故事规则

线性故事只允许 nextend

text
next -> answer;
text
end;

它会拒绝 choiceentercompletepredicatestatestate grouppoolmodulestory.initial_state,即使这些声明本身能通过语法解析。

Story 入口必须开始一条有限链:

text
entry -> block -> block -> ... -> 唯一结局

完整校验会拒绝:

  • 指向入口的边;
  • 没有恰好一条入边的非入口 Block;
  • 分叉或合流;
  • 不可达/孤立 Block;
  • 循环;
  • 没有结局或存在多个结局。

完整线性示例

text
story main (
  title: "信号花园",
  language: "zh-CN",
  format: novel,
  entry: opening,
  beat_order: [opening, resolution]
);

entity character ch_mara (name: "玛拉", role: protagonist);
entity location loc_garden (name: "信号花园");

scene garden (
  title: "花园",
  beat: opening,
  pov: ch_mara,
  location: loc_garden
) {
  block opening (
    title: "警告",
    purpose: setup,
    setup: [signal_arc]
  ) {
    text: { 一束光从花园地下苏醒。 };
    dialogue ch_mara (
      mode: whisper,
      emotion: cautious
    ): { 别再来了。 };
    next -> answer;
  }

  block answer (
    title: "答案",
    purpose: resolution,
    resolves: [signal_arc]
  ) {
    text: { 她循着光回到家。 };
    end;
  }
}

声明顺序让源码便于浏览,但只有 entrynextend 定义阅读顺序。新增 Block 却没有把它连接进链,会产生不可达 Block。

Beat 顺序不是 Block 流转

story.beat_order 为 Scene beat 元数据提供预期顺序。在受支持的校验路径中,它能诊断缺失、未知或乱序的 beat,但绝不会连接 Block。把线性故事拆到多个文件时,既要保留预期节拍顺序,也要保留显式 Block 目标。

下一章:CYOA 选择、State、Pool 与 Module