ttrpg-tools/src/doc-entries/journal-stat.md

283 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
tag: journal-stat
icon: 📊
title: 属性系统
description: 在文档中定义属性,通过命令设置/删除/掷骰,在面板中查看属性表。
syntax: '```yaml role=stat'
props:
- name: 定义文件
type: —
desc: 在任意 .md 文档中使用 yaml role=stat 代码块定义属性
- name: 命令
type: —
desc: /stat set key=value | /stat del key | /stat roll key
- name: 属性类型
type: —
desc: number, string, enum, modifier, derived
- name: 权限
type: —
desc: GM 可修改所有属性,玩家只能修改自己的属性 (玩家名:xxx)
---
## 概述
属性系统允许你在文档中定义角色属性(如力量、生命值、技能等),
通过命令设置和掷骰,并在 Journal 面板的属性视图中查看当前值。
属性分为两层:
- **定义**Schema在 markdown 文档的 ` ```yaml role=stat ` 代码块中定义
- **值**State通过 `/stat set/del/roll` 命令在游戏过程中动态修改
## 属性类型
| 类型 | 说明 | 支持掷骰 |
|---|---|---|
| `number` | 数值,可声明 `roll` 公式 | ✅ |
| `string` | 自由文本 | ❌ |
| `enum` | 枚举选项,掷骰随机选择 | ✅ |
| `modifier` | 修饰值,自动加到 `target` 属性上 | ❌ |
| `derived` | 通过公式从其他属性计算 | ✅ |
| `template` | 查表属性,掷骰匹配范围并应用修饰符 | ✅ |
## 属性定义语法
支持两种格式:**YAML**(适合复杂属性)和 **CSV**(适合同质列表)。
### YAML 格式
`.md` 文档中插入 ` ```yaml role=stat ` 代码块:
```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 格式
对于同质属性列表(如多个 `number` 类型的属性CSV 更紧凑。
插入 ` ```csv role=stat ` 代码块:
```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 |
| `formula` | — | — | derived 的计算公式 |
| `options` | — | — | enum 选项,用 `\|` 分隔 |
示例 — enum 属性:
```csv role=stat
key,label,type,options
weather,天气,enum,晴天\|阴天\|雨天\|暴风雨
```
### 关键语法说明
- **`key`**:唯一标识符。使用纯名字(如 `strength`),不用加玩家前缀
- **`scope`**`player` 或 `global`。`player` 表示每个玩家各自独立的值,运行时 key 为 `玩家名:strength``global` 表示所有玩家共享
- **`label`**:在属性视图中显示的名称
- **`type`**:属性类型(见上表)
- **`default`**:默认值,在未通过命令设置时使用
- **`roll`**:掷骰公式(仅 `number` 类型),支持引用其他属性值(使用 bare key自动同 scope 解析)
- **`target`**`modifier` 类型的目标属性 keybare key同 scope 内解析)
- **`options`**`enum` 类型的选项列表,支持多行 `- value` 语法
- **`formula`**`derived` 类型的计算公式,支持 `+ - * / floor() ceil() round()`,属性引用使用 bare key
### 作用域说明
`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`。命令中使用 bare key
| 命令 | 示例 | 说明 |
|---|---|---|
| `/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`**:计算公式,结果写入属性值
例如 `/stat roll attack` 会:
1. 在当前玩家 scope 下查找 `attack` 的定义
2. 解析 `roll` 公式 `1d20 + attack`,将 `attack` 替换为当前值(含修饰符)→ 如 `1d20 + 3`
3. 掷骰 → 如结果 `15`
4.`15` 写入 `alice:attack`,同步到所有连接的客户端
## 属性视图
在 Journal 面板顶部点击 **属性** 标签切换视图:
- 属性按 scope 分组(全局属性 + 玩家属性)
- 显示属性名、当前值、默认值
- 修饰符自动合并显示(`strength = 16` 时,`str_mod` 自动加到 `strength` 上)
- 有掷骰属性的行显示 🎲 按钮,点击可快速掷骰
## 权限
- **GM**:可以修改所有属性
- **玩家**:只能修改自己 scope 下的属性(`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详解
模板属性用于查表掷骰,例如年龄表、职业表等。
模板在独立的 CSV 代码块中定义,使用 `role=stat-template``id=模板名`
**第一列是骰子表达式**(如 `1d10`),第二列是 `label`,其余列为修饰符:
```csv id=年龄 role=stat-template
1d10,label,heart,mind,strength,speed
1-3,青少年,+20,-10,,
4-7,成年,,-10,,+20
8-9,老年,,+20,-10,
10,换躯者,,,+30,-10
```
- **第一列header**:骰子表达式,如 `1d10`、`2d6`
- **第一列rows**:匹配范围,支持 `1-3`(区间)、`4`(精确)、`1-3,5`(多个)
- **`label` 列**:显示名称
- **其余列**:修饰符键名,值为变化量(正数加、负数减、空表示不修改)
然后在属性定义中引用模板:
```yaml role=stat
- key: age
scope: player
label: 年龄
type: template
template: 年龄
```
`/stat roll age` 时:
1.`1d10`(模板头部的骰子表达式)
2. 匹配第一列获取条目
3. 发布 `set age=青少年`
4. 同时发布 `set alice:heart=52`(原始值 +20、`set alice:mind=22`-10
修饰符值中的 `+`/`-` 前缀表示相对调整。如果 modifiers 值是 `+20`,会在当前值基础上加 20如果是 `-10`,会减 10。
## 掷骰公式中的属性引用
`roll` 字段中的标识符会自动替换为当前属性值:
```yaml role=stat
- key: attack
scope: player
type: number
default: 0
roll: "1d20 + attack + str_mod"
```
`/stat roll alice:attack` 时,`alice:attack` 和 `alice:str_mod` 会被替换为当前值后再掷骰。