--- tag: journal-stat icon: 📊 title: 属性系统 description: 在文档中定义属性,通过命令设置/删除/掷骰,在面板中查看属性表。 syntax: '```yaml role=stat' props: - name: 定义文件 type: — desc: 在任意 .md 文档中使用 ```yaml role=stat 或 ```csv role=stat 代码块定义属性 - name: 命令 type: — desc: /stat set key=value | /stat del key | /stat roll key - name: 属性类型 type: — desc: number, string, enum, modifier, derived, template - name: 权限 type: — desc: GM 可修改所有属性,玩家只能修改自己的属性 --- ## 概述 属性系统允许你在文档中定义角色属性,通过命令设置和掷骰, 并在 Journal 面板的属性视图中查看当前值。 属性分为两层: - **定义**(Schema):在 markdown 文档的 ` ```yaml role=stat ` 或 ` ```csv role=stat ` 代码块中定义 - **值**(State):通过 `/stat set/del/roll` 命令在游戏过程中动态修改 ## 代码块语法 所有属性相关代码块使用统一的属性语法: ```lang role=xxx [id=xxx] | 属性 | 说明 | 示例 | |---|---|---| | `lang` | 代码语言 | `yaml`, `csv` | | `role` | 块用途 | `stat`(属性定义), `stat-template`(模板表) | | `id` | 引用标识 | 模板名称,如 `id=年龄` | 代码块默认会被**剥离**(不渲染到页面),仅用于数据提取。 如需保留为可见代码块,添加 `as=codeblock`。 ## 属性定义 支持两种格式:**YAML**(适合复杂属性)和 **CSV**(适合同质列表)。 ### YAML 格式 ```yaml role=stat - key: strength scope: player label: "力量" type: number default: 10 - key: str_mod scope: player label: "力量调整" type: modifier target: strength - key: attack scope: player label: "近战攻击" type: number default: 0 roll: "1d20 + attack" - key: loot scope: player label: "战利品" type: enum options: - 金币 x10 - 魔法药水 - 破旧长剑 - key: hp_max scope: player label: "最大生命值" type: derived formula: "strength * 2 + 10" - key: notes scope: player label: "备注" type: string - key: weather scope: global label: "天气" type: enum options: - 晴天 - 阴天 - 雨天 - 暴风雨 ``` ### CSV 格式 ```csv role=stat key,label,type,roll mind,心智,number,2d10+20 heart,心灵,number,2d10+20 strength,力量,number,2d10+20 speed,速度,number,2d10+20 ``` CSV 列说明: | 列 | 必填 | 默认值 | 说明 | |---|---|---|---| | `key` | ✅ | — | 属性标识符 | | `label` | — | key 的值 | 显示名称 | | `type` | — | `number` | 属性类型 | | `scope` | — | `player` | `player` 或 `global` | | `default` | — | — | 默认值 | | `roll` | — | — | 掷骰公式 | | `target` | — | — | modifier 的目标 key | | `template` | — | — | template 类型引用的模板 id | | `formula` | — | — | derived 的计算公式 | | `options` | — | — | enum 选项,用 `\|` 分隔 | ### 属性类型 | 类型 | 说明 | 支持掷骰 | |---|---|---| | `number` | 数值,可声明 `roll` 公式 | ✅ | | `string` | 自由文本 | ❌ | | `enum` | 枚举选项,掷骰随机选择 | ✅ | | `modifier` | 修饰值,自动加到 `target` 属性上 | ❌ | | `derived` | 通过公式从其他属性计算 | ✅ | | `template` | 查表属性,掷骰匹配范围并应用修饰符 | ✅ | ### 关键字段说明 - **`key`**:唯一标识符。使用纯名字(如 `strength`),不用加玩家前缀 - **`scope`**:`player` 或 `global`。`player` 表示每个玩家各自独立的值,运行时 key 为 `玩家名:strength`;`global` 表示所有玩家共享 - **`label`**:在属性视图中显示的名称 - **`default`**:默认值,在未通过命令设置时使用 - **`roll`**:掷骰公式(`number` 类型),支持引用其他属性值(bare key,自动同 scope 解析) - **`target`**:`modifier` 类型的目标属性 key - **`options`**:`enum` 类型的选项列表,YAML 支持多行 `- value` 语法,CSV 用 `|` 分隔 - **`formula`**:`derived` 类型的计算公式,支持 `+ - * / floor() ceil() round()` - **`template`**:`template` 类型引用的模板 id(对应 `id=xxx` 的 stat-template 块) ### 作用域 `scope: player` 的属性在运行时自动加上玩家名前缀。Alice 连接时,`strength` 的实际 key 是 `alice:strength`。 在公式(`roll`、`formula`)和 `target` 中,使用 bare key 即可,系统自动在相同 scope 内查找: ```yaml role=stat - key: attack scope: player roll: "1d20 + attack" # attack 自动解析为 alice:attack - key: str_mod scope: player target: strength # 自动解析为 alice:strength ``` ## 命令 所有命令在 Journal 输入框中输入,前缀为 `/stat`: | 命令 | 示例 | 说明 | |---|---|---| | `/stat set key=value` | `/stat set strength=16` | 设置属性值 | | `/stat del key` | `/stat del strength` | 删除属性值,恢复默认 | | `/stat roll key` | `/stat roll attack` | 掷骰并发布结果 | ### 掷骰行为 - **`number` + `roll`**:解析公式中的属性引用,掷骰,结果写入属性值 - **`enum`**:从选项列表中随机选择一项 - **`derived` + `formula`**:计算公式,结果写入属性值 - **`template`**:掷模板头部骰子,匹配范围,应用修饰符 例如 `/stat roll attack`: 1. 在当前玩家 scope 下查找 `attack` 的定义 2. 解析 `roll` 公式 `1d20 + attack`,将 `attack` 替换为当前值(含修饰符)→ `1d20 + 3` 3. 掷骰 → `15` 4. 将 `15` 写入 `alice:attack`,同步到所有客户端 ## 属性视图 在 Journal 面板顶部点击 **属性** 标签切换视图: - 属性按 scope 分组(全局 + 玩家) - 显示属性名、当前值、默认值 - 修饰符自动合并显示 - 可掷骰的行显示 🎲 按钮 ## 权限 - **GM**:可修改所有属性 - **玩家**:只能修改 `scope: player` 的属性 - **观察者**:不能修改任何属性 ## 修饰符(modifier) 修饰符自动加到 `target` 属性上: ```yaml role=stat - key: strength scope: player type: number default: 10 - key: str_mod scope: player type: modifier target: strength ``` `/stat set str_mod=3` 后,`strength` 的计算值为 `10 + 3 = 13`。 多个修饰符指向同一目标时累加。 ## 派生属性(derived) 通过公式从其他属性计算: ```yaml role=stat - key: hp_max scope: player type: derived formula: "strength * 2 + 10" ``` 公式引用其他属性时自动使用计算值(含修饰符)。 支持的函数:`floor(x)`, `ceil(x)`, `round(x)`。 ## 模板属性(template) 模板属性用于查表掷骰(年龄表、职业表等)。 ### 方式一:stat-modifiers(推荐) 一个代码块同时生成模板 stat 和修饰符 stat defs: ```csv id=年龄 role=stat-modifiers 1d10,label,mind,heart,strength,speed 1-3,青少年,-10,+20,, 4-7,成年,,-10,,+20 8-9,老年,,+20,-10, 10,换躯者,,,+30,-10 ``` 这会自动生成: - `age`(type: template, template: 年龄) - `age_mind`(type: modifier, target: mind) - `age_heart`(type: modifier, target: heart) - `age_strength`(type: modifier, target: strength) - `age_speed`(type: modifier, target: speed) 修饰符键名规则:`{id}_{列名}`,目标为列名本身。 ### 方式二:手动定义 分别定义模板表和修饰符 stat: ```csv id=年龄 role=stat-template 1d10,label,age_mind,age_heart,age_strength,age_speed 1-3,青少年,-10,+20,, 4-7,成年,,-10,,+20 8-9,老年,,+20,-10, 10,换躯者,,,+30,-10 ``` ```yaml role=stat - key: age_mind type: modifier target: mind - key: age_heart type: modifier target: heart - key: age type: template template: 年龄 ``` ### 使用 ### 使用 - `/stat roll age` — 掷 `1d10`,匹配范围,应用修饰符 - `/stat set age=换躯者` — 直接设置,同样应用修饰符 `/stat roll age` 或 `/stat set age=青少年` 时: 1. 发布 `set age=青少年` 2. 同时发布 `set alice:age_mind=-10`、`set alice:age_heart=+20` 等 修饰符值中的 `+`/`-` 前缀表示相对调整,基于当前值计算。 ### 模板表语法 - **第一列(header)**:骰子表达式,如 `1d10` - **第一列(rows)**:匹配范围,`1-3`(区间)、`4`(精确)、`1-3,5`(多个) - **`label`**:显示名称 - **其余列**:修饰符键名,值为变化量(`+`加、`-`减、空不修改) ## 掷骰公式中的属性引用 `roll` 字段中的标识符自动替换为当前属性值: ```yaml role=stat - key: attack scope: player type: number default: 0 roll: "1d20 + attack + str_mod" ```