变量管理1.0
旧版本。推荐大家使用2.0版本
功能概览
-
在消息中变更状态
<plot-log>- 在 AI 回复中嵌入
<plot-log>区块,记录/更新变量 - 支持设置、追加、数值增减、删除四种操作
- 支持编辑/删除/滑动消息时自动回滚正确变量状态
- 在 AI 回复中嵌入
-
变量保护指令
- 使用
xbsetvar进行初始变量指令设置 - 默认行为:只允许”改值”,不允许新增
- 使用
-
世界书条件事件
<varevent>- 在世界书中设置变量条件,满足时自动显示文本或执行动作
- 可视化编辑器:点点选选就能生成规则,不用写代码
-
数值映射(自然语言→数值)
- 将”开心”、“害羞”等词汇自动转换为数值变化
-
变量占位符与斜杠命令
- 用
{{xbgetvar::变量名}}显示 JSON 格式的值 - 用
{{xbgetvar_yaml::变量名}}显示 YAML 格式的值(推荐给 AI 看) - 用
/xbgetvar 变量名快速查看变量
- 用
一、理解数据结构
在开始之前,你需要理解变量里的两种容器。
数组 = 排队
像排队一样,一条条往下加,用 - 开头:
战斗日志:
- "第1回合:命中"
- "第2回合:闪避"
- "第3回合:暴击"
角色特性:
- "力量型"
- "怕痒"特点:只管顺序,没有名字。第1个、第2个、第3个…
初始化:"$list 战斗日志": []
AI 加东西:用 追加
对象 = 抽屉柜
像抽屉柜一样,每样东西有名字,按名字找:
背包:
苹果:
数量: 3
描述: "回血用"
刀:
数量: 1
描述: "攻击用"
状态效果:
中毒:
剩余: 2
描述: "每回合掉血"
狂暴:
剩余: 1
描述: "攻击+5"特点:每个东西都有标签(名字),用名字来找。
初始化:"$free 背包": {}
AI 加东西:用 录入
怎么选?
问自己一个问题:“这东西以后怎么加?“
| 回答 | 用哪个 | 初始化写法 | AI 怎么加 |
|---|---|---|---|
| 不用加,就改改数字/文字 | 普通值 | "体力": 0 | 录入 / 变更 |
| 一条条往下加(像聊天记录) | 数组 | "$list 日志": [] | 追加 |
| 每个有名字,要能单独找到 | 对象 | "$free 背包": {} | 录入 |
一句话总结
数组存流水账,对象存有名字的东西。
$list告诉系统这是数组,$free告诉系统这是对象。
二、在消息中变更状态
让 AI 在回复中包含一个特殊区块 <plot-log>,用来记录剧情变化。
四个操作关键词
| 操作 | 别名 | 用途 | 适用于 |
|---|---|---|---|
| 录入 | set / 记下 / 记录 / record | 设置/覆盖值 | 普通值、对象 |
| 变更 | bump / 调整 / 推移 / adjust | 数值加减(可负) | 数字 |
| 追加 | push / 添入 / 增录 / append | 往列表加一条 | 仅数组 |
| 删除 | del / 遗忘 / 抹去 / erase | 删除路径 | 都可以 |
基本用法
<plot-log>
录入:
好感度: 65
心情: "害羞"
变更:
约会次数: 1
追加:
重要事件:
- "第一次看电影"
删除:
- 临时标记
</plot-log>录入:设置/覆盖值
用于设置文字、数字、或整个对象:
录入:
# 设置普通值
日常.时间: "15:30"
日常.地点: "学院区"
# 设置嵌套值
战斗.对手.服装.上身: "背心(撕破)"
战斗.对手.生理.胸部: "右乳暴露"
# 往对象里加一个新东西(注意:不是追加!)
背包.治疗药:
数量: 3
描述: "恢复50HP"
# 往对象里加状态效果
战斗.对手.状态效果.羞耻:
剩余: 2
描述: "性技DC-2"变更:数值加减
只用于数字,可以是正数(加)或负数(减):
变更:
战斗.回合: 1 # +1
玩家.体力: -30 # -30
战斗.对手.体力: -20 # -20
战斗.对手.快感: 25 # +25
背包.治疗药.数量: -1 # 用掉一个追加:往数组加
⚠️ 重要:追加只能用于数组($list)!
追加:
# 往战斗日志加记录
战斗.日志:
- "R3: 对手锁技→玩家 -30HP"
- "R3: 玩家撕衣→对手 +25快感"
# 往事件记录加
事件:
- "14:52 - 战斗白热化"
# 往特性列表加
玩家.特性:
- "力量型"错误示范:
# ❌ 错误:背包是对象($free),不能用追加
追加:
背包:
苹果:
数量: 3
# ✅ 正确:往对象加东西用录入
录入:
背包.苹果:
数量: 3删除:移除路径
推荐用列表形式:
删除:
- 背包.苹果 # 删除对象里的一项
- 状态效果.中毒 # 删除状态效果
- 战斗.日志[0] # 删除数组第一条(索引从0开始)也可以用嵌套形式(末端用数组列出要删的):
删除:
背包:
- 苹果
- 过期药水
战斗.对手.状态效果:
- 格斗强化完整示例
<plot-log>
录入:
战斗.阶段: "激烈交战"
日常.时间: "14:52"
战斗.对手.服装.上身: "背心(撕破,右乳暴露)"
战斗.对手.生理.胸部: "右乳暴露,乳头挺立"
战斗.对手.状态效果.羞耻:
剩余: 2
描述: "性技DC-2"
玩家.状态效果.手臂疼痛:
剩余: 1
描述: "格斗DC-1"
变更:
战斗.回合: 1
玩家.体力: -30
玩家.快感: 5
战斗.对手.体力: -20
战斗.对手.快感: 25
背包.治疗药.数量: -1
追加:
战斗.日志:
- "R3: 对手【腕十字固】→玩家 -30HP"
- "R3: 玩家撕破对手上衣 +25快感"
事件:
- "14:52 - 观众开始起哄"
删除:
- 战斗.对手.状态效果.格斗强化
- 背包.过期药水
</plot-log>状态一致性与回滚
系统会自动处理消息编辑的问题:
- 编辑消息:先回滚到该消息生效前的状态,再按新内容重新计算
- 滑动替换:先回滚,再应用新的回复内容
- 删除消息:回滚到被删消息之前的变量状态
这确保了无论怎么修改对话,变量状态都能保持一致。
三、变量守护和规则集
基本控制
总体原则
- 默认行为:只允许”改值”,不允许新增/删除对象键,不允许新增/删除数组项
- 需要修改规则时:把
/setvar换成/xbsetvar - 想放开操作:在键名前加规则前缀(
$开头)
可用规则前缀
| 前缀 | 作用 |
|---|---|
$ro | 只读,任何人都不能改 |
$ext | 对象允许新增键(不可删) |
$prune | 对象允许删键(不可增) |
$free | 对象可增可删 |
$grow | 数组允许添加(不可删) |
$shrink | 数组允许删除(不可增) |
$list | 数组可增可删 |
$min=数 / $max=数 | 数值最小/最大限制 |
$range=[a,b] | 数值范围限制 |
$enum={A;B;C} | 字符串必须是这几个之一 |
$match=/regex/flags | 字符串必须匹配正则 |
初始化示例
/xbsetvar key="$free bf" {
"日常": {
"日期": null,
"时间": null,
"地点": null
},
"金钱": 0,
"$list 事件": [],
"战斗": {
"状态": "未开始",
"回合": 0,
"回合上限": 0,
"阶段": null,
"$list 日志": [],
"$free 对手": {
"名称": null,
"体力": 0,
"体力上限": 0,
"快感": 0,
"快感上限": 0,
"$free 状态效果": {},
"$free 服装": {
"上身": null,
"下身": null
},
"$list 特性": [],
"$list 弱点": []
}
},
"$free 玩家": {
"名称": null,
"$range=[0,999] 体力": 0,
"$range=[0,999] 体力上限": 0,
"$range=[0,999] 快感": 0,
"$free 状态效果": {},
"$free 服装": {},
"$list 特性": [],
"$list 弱点": []
},
"$free 背包": {},
"$free 图 的": {}
}规则就三条:
$list= 数组(一条条加的)→ 用 追加$free= 对象(按名字存的)→ 用 录入- 普通值 → 用 录入 或 变更
使用效果
设置规则后:
- AI 尝试把体力改成 1500?自动拉回 999(设了
$range=[0,999]) - AI 想删除角色真名?拒绝操作(设了
$ro) - AI 要往背包加新道具?允许(设了
$free) - AI 想往日志加记录?允许(设了
$list)
四、变量宏
在角色卡、世界书、消息中显示变量值。
两种格式
| 宏 | 输出格式 | 用途 |
|---|---|---|
{{xbgetvar::路径}} | JSON | 给代码用、精确取值 |
{{xbgetvar_yaml::路径}} | YAML | 给 AI 看(推荐) |
为什么要用 YAML 版本?
假设变量 bf.背包 的值是:
{"苹果":{"数量":3},"刀":{"数量":1}}两种宏的输出对比:
{{xbgetvar::bf.背包}} 输出:
{"苹果":{"数量":3},"刀":{"数量":1}}{{xbgetvar_yaml::bf.背包}} 输出:
苹果:
数量: 3
刀:
数量: 1AI 看 YAML 更清晰,输出也用 YAML,格式统一不混乱。
使用示例
<bf-state>
bf.日常.时间: "{{xbgetvar::bf.日常.时间}}"
bf.日常.地点: "{{xbgetvar::bf.日常.地点}}"
bf.战斗.回合: {{xbgetvar::bf.战斗.回合}}
bf.背包:
{{xbgetvar_yaml::bf.背包}}
bf.玩家.状态效果:
{{xbgetvar_yaml::bf.玩家.状态效果}}
bf.战斗.对手.状态效果:
{{xbgetvar_yaml::bf.战斗.对手.状态效果}}
</bf-state>注意事项
xbgetvar_yaml 输出多行,不要在外面套引号:
<!-- ❌ 错误:引号会破坏格式 -->
bf.背包: "{{xbgetvar_yaml::bf.背包}}"
<!-- ✅ 正确:换行后直接写 -->
bf.背包:
{{xbgetvar_yaml::bf.背包}}五、斜杠命令
| 命令 | 用途 | 示例 |
|---|---|---|
/xbgetvar 路径 | 读取变量 | /xbgetvar bf.玩家.体力 | /echo |
/xbsetvar 路径 值 | 设置变量 | /xbsetvar bf.玩家.体力 100 |
/xbaddvar 路径 增量 | 数值加减 | /xbaddvar bf.玩家.体力 -20 |
/xbpushvar 路径 值 | 数组追加 | /xbpushvar bf.日志 "新记录" |
/xbdelvar 路径 | 删除变量 | /xbdelvar bf.临时标记 |
带规则前缀的设置
/xbsetvar key="$list bf.新数组" ["item1", "item2"]
/xbsetvar key="$free bf.新对象" {"key": "value"}
/xbsetvar key="$range=[0,100] bf.玩家.体力" 50六、世界书条件事件
在世界书中设置 <varevent>,当变量满足条件时自动触发。
可视化编辑器
不用写代码!点击世界书条目上的”条件规则编辑器”按钮(尺子+笔图标),就能打开图形化界面。
在这个界面里:
- 设置条件:选择变量名、比较方式(大于、等于、包含等)、目标值
- 设置显示内容:条件满足时要插入的文字
- 设置动作(可选):回复生成后要执行的命令
- 点击确认:自动生成代码并写入世界书
手写示例
<varevent>
[event.低血量警告]
condition: var(`bf.玩家.体力`) < val(`30`)
display: "【系统】血量过低,请注意!"
[event.高好感触发]
condition: var(`bf.好感度`) >= val(`80`)
display: "【系统】好感度已达到高级阶段"
js_execute: "console.log('好感度达标')"
</varevent>事件优先级
- 同一个
<varevent>内:多条事件同时满足时,只触发最后一条 - 想要多个都生效:创建多个
<varevent>区块
七、数值映射
将自然语言自动转换为数值变化。
设置入口
在世界书的”条件规则编辑器”中,点击”bump 数值映射设置”按钮。
配置格式
每行一条规则:变量名(可空) | 词组或/正则/ | 数值
好感度 | /她(很)?害羞/i | 1
好感度 | 生气 | -2
心情值 | 很开心 | 2
| 略显疲惫 | -1最后一行变量名为空,表示对所有变量生效。
使用效果
配置后,AI 可以这样写:
<plot-log>
变更:
好感度: 她很害羞 # 自动转换为 +1
心情值: 很开心 # 自动转换为 +2
</plot-log>八、常见问题
Q:追加报错或没效果?
A:追加只能用于数组($list)。如果目标是对象($free),应该用录入。
# ❌ 错误:背包是对象
追加:
背包.苹果: ...
# ✅ 正确:对象用录入
录入:
背包.苹果:
数量: 3Q:删除没效果?
A:推荐用列表形式。如果用嵌套写法,末端必须有值。
# ✅ 推荐
删除:
- 背包.苹果
# ✅ 也可以
删除:
背包:
- 苹果
# ❌ 错误:末端没值
删除:
背包:
苹果:Q:xbgetvar 和 xbgetvar_yaml 有什么区别?
A:输出格式不同。xbgetvar 输出 JSON,xbgetvar_yaml 输出 YAML。给 AI 看推荐用 YAML 版本,格式更清晰。两者替换时机完全一致。
Q:编辑消息后变量会乱吗?
A:不会。系统会自动回滚到编辑前的状态,再按新内容重新计算。
Q:一个 varevent 能触发多个事件吗?
A:不能。同一个 <varevent> 内多条事件同时满足时,只触发最后一条。要多个都触发,需要写多个 <varevent> 区块。