后室:逃出生天 (Backrooms Escape)
扮演 M.E.G.CN 工作人员,从 Level 0 出发,在后室中寻找出口不断切入下一个楼层,直至找到最终出口 Level 399。
游戏背景
你是一名 M.E.G.CN(探险者总署中文分部)的探员,在一次任务中不小心切入了后室。这是一个由无数诡异楼层组成的超自然空间。你从著名的 Level 0「前厅」开始,必须穿越一个个危险而诡异的楼层,找到传说中的 Level 399 最终出口,才能回到现实世界。
后室中潜伏着各种危险的实体,但也有前人留下的补给品和线索。能否活着逃出去,取决于你的智慧和运气。
快速上手
第一步:验证插件
在群里或私聊发送:
/br test如果收到回复「✅ 后室逃生插件已正常接收消息!」,说明插件工作正常,可以开始游戏。
第二步(可选):查看已解锁的工作故事
/br story完成 Alpha 基地工作后,使用 /br story 查看已解锁的故事列表,使用 /br story <ID> 通过合并转发消息阅读具体内容。
第三步:开始游戏
/br start你会从 Level 0「前厅」出发,系统会给你当前楼层的描述和可用的命令。
第四步:游戏主循环
每一层的标准流程:
/br explore → 探索楼层(搜集物品、了解环境)
/br exit → 寻找出口(切入下一层)
/br status → 随时查看探员状态和背包重复以上步骤,直到抵达 Level 399。
游戏内智能引导
游戏会在每一轮回复后自动给出下一步建议:
- 进入新楼层后 → 提示先探索再找出口
- 多次找不到出口 → 建议探索搜集物品来提升概率
- 生命值/理智值过低 → 提醒检查背包中的补给品
- 查看背包时 → 根据持有物品给出个性化策略建议
命令列表
| 命令 | 说明 | 使用时机 |
|---|---|---|
/br test | 测试插件连通性 | 首次使用前,验证插件是否正常 |
/br story | 故事档案 | 查看已解锁的工作故事列表,/br story <ID> 以转发消息查看具体故事 |
/br start | 开始新游戏 | 首次进入 / 死亡后重开 |
/br explore | 探索当前楼层 | 每层第一步,搜寻物品和线索 |
/br exit | 尝试寻找出口 | 探索之后,尝试切入下一层 |
/br read | 阅读捡到的纸条 | 探索中捡到纸条后,通过合并转发消息展示内容 |
/br use <编号> | 使用背包中的物品 | 需要恢复生命/理智时使用。例:/br use 1 |
/br status | 查看探员状态 | 随时查看生命/理智/进度/贡献点 |
/br inventory | 查看背包 | 检查物品,获取使用建议 |
/br quest | 任务系统 | 查看/接受/提交任务,获得贡献点 |
/br work | 基地工作 | 在 Level 1 Alpha 基地参与解谜工作,获得贡献点 |
/br help | 游戏帮助 | 忘记命令时查看 |
/br people_net | 人物关系图 | 查看已解锁角色的背景与关系 |
/br say | 随机名言 | 随机输出一句名人名言 |
/br off | 关闭插件(管理员) | 仅首次使用的用户可关闭,关闭后仅管理员可用 |
/br on | 启用插件(管理员) | 管理员重新开放插件 |
技术架构
本插件使用 MaiBot SDK 的 @Command 组件进行命令路由,当用户消息匹配命令的正则模式时,MaiBot 会自动调度执行对应的处理函数,匹配到的消息不会进入 Planner/LLM 处理链。
所有游戏命令以 /br 为前缀,兼容 NapCat(OneBot v11)消息格式。
消息输出模式
所有游戏输出统一通过 _send() 方法发送,根据 config.toml 中的 [plugin] → output_mode 配置自动切换:
"text"(默认):所有回复以普通文本形式发送"forward":所有回复以合并转发消息形式发送,支持多节点拆分展示
合并转发消息
/br story <ID> 和 /br read 命令在 output_mode = "forward" 时使用合并转发消息展示。
节点格式:
nodes = [
{
"user_id": "标识",
"user_nickname": "昵称",
"content": [{"type": "text", "data": "消息内容"}],
},
]adapter 内部流程:
- SDK 将 nodes 包装为
raw_message = [{"type": "forward", "data": nodes}] - adapter 的
_contains_forward_segment()检测到type=forward段 _build_forward_nodes()映射:user_id→uin,user_nickname→name,content经 segment encoder 转换- →
send_group_forward_msg/send_private_forward_msg→ NapCat
不用
send.custom("send_msg", ...)传 node 段 — adapter 将其识别为普通消息段输出[unsupported:node]。也不用send.custom("send_forward_msg", ...)— 绕过了 adapter 的消息段转换和 group_id/user_id 自动注入。
权限要求
需在 _manifest.json 的 capabilities 中声明:
"capabilities": [
"send.text",
"send.forward",
...
]项目结构
目录树
backrooms_escape/
│
├── plugin.py # 插件主入口
│ 游戏逻辑、命令注册、数据持久化
│
├── renderer.py # 消息渲染器 + 拓展模块加载入口
│ 格式化所有回复文本;从 renderer_load/ 导入并透出所有拓展类
│
├── config.py # 配置模型
│ PluginConfigBase 子类,定义 [plugin]/[game]/[whitelist]/[blacklist]
│
├── renderer_load/ # 拓展功能模块目录
│ ├── __init__.py # 统一导出(上层只需 import renderer_load 即可)
│ ├── state_machine.py # 有限状态机 — GameState / GameEvent / GameStateMachine
│ ├── shut.py # 群聊静默管理 — ShutManager
│ ├── story_manage.py # 数据加载层 — StoryManager / PeopleStoryMgmt /
│ │ # QuestManager / WorkManager / BaseWorkStoryManager
│ └── people_manage.py # 角色业务层 — CharacterEncounterService / CHARACTERS 注册表
│
├── br_story/ # 故事/剧情/数据目录
│ ├── level_story/ # 后室背景故事纸条文本
│ │ └── l1_story.txt ~ l11_story.txt
│ ├── people_story/ # NPC 角色剧情 + 任务数据 + 人物关系数据
│ │ ├── ankexin.txt
│ │ ├── anjinian.txt
│ │ ├── people_quests.json
│ │ └── people_relationship.json
│ └── base_story/ # 基地工作解谜数据 + 解锁故事
│ ├── base_work.json
│ └── work_W001_story.txt ~ work_W005_story.txt
│
├── config.toml # 插件配置文件(启动时自动读取)
├── _manifest.json # 插件元信息(ID、版本、兼容性声明)
├── backrooms_data.json # 物品/实体数据池
├── br_data/ # 玩家存档(运行时自动创建)
│ └── *.json
└── .gitignore分层设计
┌─────────────────────────────────────────────────────┐
│ plugin.py │
│ 命令路由 + 状态管理 + 存档读写 + 游戏流程编排 │
│ 依赖: renderer, config │
└─────────────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ renderer.py │
│ 消息格式化 + 拓展模块统一加载入口 │
│ 从 renderer_load/ 导入并透出所有类 │
└─────────────────────────┬───────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌──────────┐ ┌──────────────────┐
│ renderer_load/ │ │ config │ │ renderer_load/ │
│ state_machine │ │ │ │ shut │
│ (FSM) │ └──────────┘ │ (群聊静默) │
└─────────────────┘ └──────────────────┘
┌──────────────────┐
│ renderer_load/ │
│ story_manage │
│ (数据加载层) │
│ .StoryManager │
│ .PeopleStoryMgmt │
│ .QuestManager │
│ .WorkManager │
│ .BaseWorkStory │
└────────┬─────────┘
│ 调用获取数据
▼
┌──────────────────┐
│ renderer_load/ │
│ people_manage │
│ (角色业务层) │
│ .CHARACTERS │
│ .EncounterService│
└──────────────────┘数据流
用户命令 → plugin.py (命令处理)
│
├──→ renderer.xxx() ← 格式化回复消息
├──→ fsm.apply(event) ← 状态转移
├──→ story_manage.xxx() ← 读取故事/任务/工作数据
├──→ people_manage.xxx() ← 角色遭遇/礼品/任务发放
├──→ _save_player() ← 持久化存档
└──→ _send() ← 发送回复约定
所有新增的功能拓展模块应放置在
renderer_load/目录下,并在renderer.py中导入并透出。plugin.py无需直接引用renderer_load/下的任何模块。
状态机
插件使用有限状态机(FSM) 管理游戏核心流程,定义在 renderer_load/state_machine.py 中。
状态定义
| 状态 | 含义 | 可执行操作 |
|---|---|---|
NOT_STARTED | 未开始游戏 | /br start |
ALIVE | 存活探索中(Level 0~398) | 全部命令 |
AT_399 | 到达最终出口 | /br exit(触发通关) |
DEAD | 生命值归零 | /br start 重新开始 |
ESCAPED | 成功逃出后室 | /br start 重新开始 |
状态转移图
NOT_STARTED ──start──▶ ALIVE ──reach_399──▶ AT_399 ──exit_399──▶ ESCAPED
│ │
│ die │ restart
▼ │
DEAD ◀────────────────────────────────────────────┘
│
└── restart ──▶ ALIVEALIVE 状态下 explore、exit、use_item 等事件不会改变状态,但可能触发 die(生命归零)或 reach_399(到达 Level 399)进入新状态。
在 PlayerState 中使用
from dataclasses import dataclass, field
from .renderer import GameStateMachine
@dataclass
class PlayerState:
fsm: GameStateMachine = field(default_factory=GameStateMachine)
# ... 其他字段
# 守卫检查(替代旧的 game_started 判断)
if not player.fsm.is_playable():
# 拒绝操作状态机将游戏流程显式化为一张可读的转移表,非法操作自然被拦截,不再需要散落在各命令处理器中的
if game_started隐式状态判断。
游戏机制
核心属性
- 生命值(❤️):初始 100 点。归零则游戏结束,角色永远留在后室中。
- 理智值(🧠):初始 100 点。探索和寻找出口都会消耗理智值。理智值过低会遭受额外惩罚。可通过 o1(杏仁水) 恢复。
- 楼层进度:从 Level 0 出发,目标是 Level 399。共有 400 个楼层需要穿越。
探索(/br explore)
每次探索消耗 2 点理智值,会触发以下随机事件:
- 发现线索:找到 M.E.G. 遗留的信息、地图碎片或日记。
- 获得物品:有几率找到补给品,如 o1(杏仁水)、o2(急救包)、o3(手电筒) 等。
- 遭遇危险:可能受伤,或遭遇后室实体。
- 诡异事件:一些令人不安但不会直接伤害你的事件。
寻找出口(/br exit)
每次尝试寻找出口消耗 5 点理智值。基础成功率 20%,每次失败后会递增成功率,确保你不会无限卡关。
物品可为成功率提供加成:
- o4(层级钥匙):100% 找到出口
- o3(手电筒) / o5(M.E.G. 无线电):各 +5% 成功率
捷径系统
有 12% 的概率触发捷径,可一次跳过 2~20 个楼层,大幅加速进度。
知名楼层
游戏包含以下根据后室维基设定的知名楼层,每个都有独特描述和专属实体:
| 楼层 | 名称 | 危险等级 | 特色 |
|---|---|---|---|
| Level 0 | 前厅 | 低 | 无限黄色办公空间,一切的起点 |
| Level 1 | 宜居区 | 低 | M.E.G. Alpha 基地所在地 |
| Level 2 | 管道梦魇 | 中 | 巨型管道迷宫,猎犬出没 |
| Level 3 | 电气站 | 中 | 遍布电线和配电箱 |
| Level 4 | 废弃办公室 | 中 | 被遗弃的办公大楼 |
| Level 5 | 恐怖旅馆 | 高 | 扭曲奢华的旅馆,镜像实体徘徊 |
| Level 6 | 熄灯 | 高 | 完全黑暗,笑魇聚集地 |
| Level 7 | 深海恐惧 | 极高 | 无边海洋,深海巨兽潜伏 |
| Level 8 | 洞穴系统 | 中 | 巨大的天然洞穴网络 |
| Level 9 | 暗黑郊区 | 中 | 永夜的诡异郊区 |
| Level 10 | 丰收之景 | 中 | 无边麦田,稻草人守望 |
| Level 11 | 无尽城市 | 低 | 空无一人的现代化城市 |
| Level 399 | 真正的结局 | 无 | 最终出口——欢迎回家 |
其他楼层(Level 12~398)将程序化生成,包含不同主题和危险等级。
物品系统
探索中有概率获得以下物品:
| 代码 | 名称 | 类型 | 效果 |
|---|---|---|---|
| o1 | 杏仁水 | 消耗品 | 使用后恢复 30 点理智值,在探索和找出口中自动消耗前手动使用 |
| o2 | 急救包 | 消耗品 | 使用后恢复 30 点生命值;在受伤事件中自动消耗一次(减伤 5 点) |
| o3 | 手电筒 | 装备 | 被动生效:遭遇笑魇/猎犬时驱散(免伤);其他实体伤害减 10;+5% 出口发现率 |
| o4 | 层级钥匙 | 消耗品 | 持有后下次 /br exit 必能找到出口(100% 成功率),使用后消耗 |
| o5 | M.E.G. 无线电 | 装备 | 被动生效:+5% 出口发现率 |
| o6 | 能量棒 | 消耗品 | 使用后恢复 15 点生命值 |
| o7 | 镇定剂 | 消耗品 | 使用后恢复 15 点理智值 |
物资箱系统
探索和寻找出口时(Level 0 除外),有概率发现大、中、小三种物资箱。每种箱子的物资内容不同:
| 箱型 | 杏仁水 | 额外物品 |
|---|---|---|
| 🟦 大型物资箱 | ✅ 必出 | 随机物品 +1 |
| 🟩 中型物资箱 | ✅ 必出 | 随机物品 +1 |
| 🟨 小型物资箱 | ✅ 必出 | 随机物品 +1 |
额外随机物品根据各物品的权重分配概率(权重越高越常见),可在 config.toml 的 [game] 段中调整:
| 参数 | 默认值 | 对应物品 | 默认概率 |
|---|---|---|---|
item_weight_o1 | 3 | o1 杏仁水(恢复 30 理智) | 20.0% |
item_weight_o2 | 3 | o2 急救包(恢复 30 生命) | 20.0% |
item_weight_o3 | 2 | o3 手电筒(驱散笑魇/猎犬) | 13.3% |
item_weight_o4 | 1 | o4 层级钥匙(稀有,100% 出口) | 6.7% |
item_weight_o5 | 2 | o5 M.E.G. 无线电(+5% 出口率) | 13.3% |
item_weight_o6 | 2 | o6 能量棒(恢复 15 生命) | 13.3% |
item_weight_o7 | 2 | o7 镇定剂(恢复 15 理智) | 13.3% |
同时获得杏仁水和额外物品时,二者概率独立计算。
物资箱概率配置
可在 config.toml 的 [game] 段中可分别调整三种物资箱的出现概率:
| 参数 | 默认值 | 说明 |
|---|---|---|
crate_large_chance | 0.08 | 触发补给事件时出现大型物资箱的概率 |
crate_medium_chance | 0.15 | 触发补给事件时出现中型物资箱的概率 |
crate_small_chance | 0.25 | 触发补给事件时出现小型物资箱的概率 |
三种概率参数可独立调整。总判定区间为三参数之和(默认 0.08+0.15+0.25=0.48),剩下的 1−0.48=0.52 为空箱概率。若调整后三参数之和超过 1.0,则空箱概率为 0%。
实体
后室中潜伏着多种危险实体,遇到它们会损失生命值:
- 笑魇(伤害 15):黑暗中的无面人形实体,手电筒可驱散
- 猎犬(伤害 20):高速四足猛兽,手电筒可驱散
- 窃皮者(伤害 25):剥取皮肤的恐怖实体
- 死亡飞蛾(伤害 10):能让人产生幻觉的巨型飞蛾
- 旅馆管理者(伤害 30):Level 5 的主人
- 深海之物(伤害 35):Level 7 的不可名状巨兽
- 以及更多……
胜利条件
到达 Level 399 并推开最终之门,你就成功逃出了后室!
新手策略建议
- 保持节奏:每层先
/br explore搜集物品,再用/br exit找出口。别跳过探索直接找出口,那样会错过补给品。 - 关注状态:经常用
/br status和/br inventory了解自己的情况。生命值或理智值低时优先考虑使用补给。 - 善用物品:o4(层级钥匙) 是通关神器,o3(手电筒) 也能提高出口发现率。
- 不要死磕:如果同一层
/br exit多次失败,回头/br explore看看能不能找到 o4(层级钥匙)。 - 理智管理:o1(杏仁水) 是关键资源,理智值耗尽会导致额外扣血。保持在 30 以上比较安全。
配置说明
可在 config.toml 中调整游戏参数和访问控制。配置模型定义在 config.py 中,包含五个配置段:[plugin]、[game]、[whitelist]、[blacklist]。
插件输出模式 [plugin]
| 参数 | 默认值 | 说明 |
|---|---|---|
output_mode | "text" | 消息输出模式:"text"=普通消息,"forward"=合并转发消息 |
[plugin]
output_mode = "text" # 普通文本消息(默认)
# output_mode = "forward" # 合并转发消息(所有回复以合并转发形式发送)游戏参数 [game]
| 参数 | 默认值 | 说明 |
|---|---|---|
initial_health | 100 | 初始生命值 |
initial_sanity | 100 | 初始理智值 |
explore_sanity_cost | 2 | 每次探索所消耗的理智值 |
exit_search_sanity_cost | 5 | 每次寻找出口所消耗的理智值 |
base_exit_chance | 0.2 | 成功找到出口的基础概率(0.0~1.0) |
exit_chance_increment | 0.1 | 每次寻找失败后成功概率的提升值 |
entity_encounter_chance | 0.25 | 在楼层中遭遇实体的基础概率 |
crate_large_chance | 0.08 | 触发补给时出现大型物资箱的概率(必出杏仁水) |
crate_medium_chance | 0.15 | 触发补给时出现中型物资箱的概率(必出杏仁水) |
crate_small_chance | 0.25 | 触发补给时出现小型物资箱的概率(必出杏仁水) |
物品权重
每个物品有独立的获取权重(item_weight_o1 ~ item_weight_o7)。当触发物品获取事件时,系统根据权重加权随机选择。权重越高,该物品越常见。设为 0 则该物品不会出现。
概率计算方式:某物品概率 = 该物品权重 ÷ 所有物品权重之和
默认配置下总权重 = 3+3+2+1+2+2+2 = 15:
| 参数 | 默认值 | 对应物品 | 默认概率 |
|---|---|---|---|
item_weight_o1 | 3 | o1 杏仁水(恢复 30 理智) | 20.0% |
item_weight_o2 | 3 | o2 急救包(恢复 30 生命) | 20.0% |
item_weight_o3 | 2 | o3 手电筒(驱散笑魇/猎犬) | 13.3% |
item_weight_o4 | 1 | o4 层级钥匙(稀有,100% 出口) | 6.7% |
item_weight_o5 | 2 | o5 M.E.G. 无线电(+5% 出口率) | 13.3% |
item_weight_o6 | 2 | o6 能量棒(恢复 15 生命) | 13.3% |
item_weight_o7 | 2 | o7 镇定剂(恢复 15 理智) | 13.3% |
概率计算公式
出口概率
最终概率 = min(base_exit_chance + 尝试次数 × exit_chance_increment, 1.0)累计尝试次数下各次的实际出口概率(默认 base_exit_chance = 0.2,exit_chance_increment = 0.1):
| 尝试次数 | 计算公式 | 实际概率 |
|---|---|---|
| 第 1 次 | 0.2 + 0 × 0.1 | 20% |
| 第 2 次 | 0.2 + 1 × 0.1 | 30% |
| 第 3 次 | 0.2 + 2 × 0.1 | 40% |
| 第 4 次 | 0.2 + 3 × 0.1 | 50% |
| 第 5 次 | 0.2 + 4 × 0.1 | 60% |
| 第 6 次 | 0.2 + 5 × 0.1 | 70% |
| 第 7 次 | 0.2 + 6 × 0.1 | 80% |
| 第 8 次 | 0.2 + 7 × 0.1 | 90% |
| 第 9 次 | 0.2 + 8 × 0.1 | 100%(达上限) |
使用 o4(层级钥匙) 时概率直接锁定为 100%,不参与上述计算。携带 o3(手电筒) 或 o5(无线电) 时,各自额外 +5%(于公式计算后累加,上限仍为 100%)。
实体遭遇概率
实际遭遇概率 = entity_encounter_chance × 当前楼层危险系数各楼层危险等级对应的系数(默认 entity_encounter_chance = 0.25):
| 危险等级 | 系数 | 实际遭遇概率 |
|---|---|---|
| 🔵 低 | 0.5 | 0.25 × 0.5 = 12.5% |
| 🟡 中 | 1.0 | 0.25 × 1.0 = 25.0% |
| 🟠 高 | 1.5 | 0.25 × 1.5 = 37.5% |
| 🔴 极高 | 2.0 | 0.25 × 2.0 = 50.0% |
物资箱判定
每次触发补给事件时,按以下顺序判定物资箱类型(默认值):
判定流程:
┌─ random < 0.08 ──→ 🟦 大型物资箱(必出杏仁水)
├─ random < 0.23 ──→ 🟩 中型物资箱(必出杏仁水)
├─ random < 0.48 ──→ 🟨 小型物资箱(必出杏仁水)
└─ 以上均未通过 ──→ 空箱("里面已经空了")各参数值对应的箱型出现概率总表:
| 参数 | 默认值 | 箱型 | 判定区间 | 独立出现概率 |
|---|---|---|---|---|
crate_large_chance | 0.08 | 🟦 大型 | [0, 0.08) | 8% |
crate_medium_chance | 0.15 | 🟩 中型 | [0.08, 0.23) | 15% |
crate_small_chance | 0.25 | 🟨 小型 | [0.23, 0.48) | 25% |
| — | — | ❌ 空箱 | [0.48, 1.0) | 52% |
三种概率参数可独立调整。总判定区间为三参数之和(默认 0.08+0.15+0.25=0.48),剩下的 1−0.48=0.52 为空箱概率。若调整后三参数之和超过 1.0,则空箱概率为 0%。
物品权重概率
某物品概率 = 该物品权重 ÷ 所有物品权重之和各物品权重参数在不同总权重下的概率对照表:
| 参数 | 权重值 | 总权重=15 时概率 | 总权重=10 时概率 | 总权重=20 时概率 |
|---|---|---|---|---|
item_weight_o1 | 3 | 20.0% | 30.0% | 15.0% |
item_weight_o2 | 3 | 20.0% | 30.0% | 15.0% |
item_weight_o3 | 2 | 13.3% | 20.0% | 10.0% |
item_weight_o4 | 1 | 6.7% | 10.0% | 5.0% |
item_weight_o5 | 2 | 13.3% | 20.0% | 10.0% |
item_weight_o6 | 2 | 13.3% | 20.0% | 10.0% |
item_weight_o7 | 2 | 13.3% | 20.0% | 10.0% |
将某个物品权重设为 0 可使该物品不再出现,其余物品概率会按比例重新分配。
白名单 [whitelist]
白名单用于控制哪些群组或私聊用户可以使用本插件。默认关闭,所有用户均可使用。
enabled:是否启用白名单(true/false,默认false)group_ids:群组白名单,字符串数组,填入允许使用的群号user_ids:私聊白名单,字符串数组,填入允许使用的用户 QQ 号group_deny_message:群组不在白名单时的提示文本(可自定义)private_deny_message:用户不在私聊白名单时的提示文本(可自定义)empty_group_list_message:白名单启用但群组列表为空时的提示文本(可自定义)empty_private_list_message:白名单启用但私聊列表为空时的提示文本(可自定义)
群组和私聊权限完全独立:你可以只开放群聊而关闭私聊,反之亦然。
# 示例:仅允许群号 123456789 和 987654321 的群使用
[whitelist]
enabled = true
group_ids = ["123456789", "987654321"]
user_ids = []# 示例:仅允许 QQ 号 10001 私聊使用,不限群组
[whitelist]
enabled = true
group_ids = []
user_ids = ["10001"]黑名单 [blacklist]
黑名单用于禁止指定群组或用户使用插件,优先级高于白名单。
enabled:是否启用黑名单(true/false,默认false)group_ids:群组黑名单,字符串数组,填入禁止使用的群号user_ids:用户黑名单,字符串数组,填入禁止使用的用户 QQ 号group_deny_message:群组被黑名单拦截时的提示文本(可自定义)private_deny_message:用户被黑名单拦截时的提示文本(可自定义)
# 示例:禁止群号 111222333 和用户 444555666 使用
[blacklist]
enabled = true
group_ids = ["111222333"]
user_ids = ["444555666"]任务系统
任务系统通过安可欣发布任务,完成后可获得 M.E.G.CN 贡献点。在 Level 1(Alpha 基地)探索时有概率遇到安可欣,她可能给你一个随机任务。
任务类型
| 类型 | 说明 | 示例 |
|---|---|---|
reach_level | 到达指定楼层 | 到达 Level 5 / Level 11 / Level 399 |
collect_item | 收集特定物品 | 获取一台 M.E.G. 无线电 |
use_item | 提交指定物资 | 提交 2 个杏仁水和 1 个急救包 |
任务列表
| ID | 标题 | 目标 | 奖励 |
|---|---|---|---|
| M001 | 初来乍到 | 到达 Level 5 | 50 贡献点 |
| M002 | 信号搜寻 | 收集无线电(o5) | 80 贡献点 + 2 急救包 |
| M003 | 深层探索 | 到达 Level 11 | 150 贡献点 |
| M004 | 紧急补给 | 提交 2 个 o1 + 消耗 1 个 o2 | 60 贡献点 + 层级钥匙 |
| M005 | 归途之旅 | 到达 Level 399 | 500 贡献点 |
相关命令
| 命令 | 说明 |
|---|---|
/br quest | 查看任务面板(进行中/可接/已完成) |
/br quest accept <ID> | 接受任务 |
/br quest submit <ID> | 提交已完成的任务 |
到达目标楼层时,系统会自动提示任务可提交。
基地工作系统
在 Level 1(Alpha 基地)探索时,有概率触发工作事件,完成后可参与解谜工作赚取贡献点。工作内容基于高中自然地理知识,包括坐标计算、气候识别、时区换算、气压带分析和地形推算。
工作列表
| ID | 标题 | 部门 | 谜题类型 | 奖励 |
|---|---|---|---|---|
| W001 | 经纬度坐标校准 | 信息分析组 | 正午太阳高度角计算 | 30 贡献点 |
| W002 | 气候带识别与物资调配 | 仓储管理 | 世界气候类型判断 | 25 贡献点 |
| W003 | 时区与抵达时间推算 | 工程部 | 时区换算 | 35 贡献点 + 杏仁水 |
| W004 | 气压带与后室气流分析 | 信息分析组 | 全球大气环流 | 25 贡献点 |
| W005 | 等高线地形与路线规划 | 工程部 | 海拔与气温垂直递减率 | 40 贡献点 + 无线电 |
相关命令
| 命令 | 说明 |
|---|---|
/br work | 查看基地工作面板 |
/br work start <ID> | 开始工作(显示谜题详情) |
/br work answer <ID> <答案> | 提交答案 |
工作故事
每个工作完成后会解锁一段故事文本。故事文件位于 br_story/base_story/ 目录下,使用 ===STORY_XXX=== 分隔符,格式与 br_story/level_story/ 中的纸条文件相同。
backrooms_escape/
├── br_story/base_story/
│ ├── work_W001_story.txt ← 坐标校准工作故事(占位符)
│ ├── work_W002_story.txt ← 气候识别工作故事(占位符)
│ ├── work_W003_story.txt ← 时区推算工作故事(占位符)
│ ├── work_W004_story.txt ← 气流分析工作故事(占位符)
│ └── work_W005_story.txt ← 路线规划工作故事(占位符)人物关系图
/br people_net 命令查看已解锁角色的人物关系图。数据来源为 br_story/people_story/people_relationship.json。
- 仅已解锁的角色会显示完整信息
- 未解锁的角色显示为
❓ ??? - 首次在 Level 1 遇到角色时自动解锁,并赠送 2 瓶杏仁水
如何新增角色
- 在
br_story/people_story/下新建.txt文件,使用===CHARACTER_NNN===分隔剧情片段 - 在
br_story/people_story/people_relationship.json中添加该角色的数据条目 - 在
plugin.py的_do_explore中该角色出现的楼层区域添加触发逻辑 - 重载插件生效
自定义故事文本
文件位置
backrooms_escape/
├── br_story/
│ ├── level_story/
│ │ └── l1_story.txt ~ l11_story.txt ← 故事纸条
│ ├── base_story/
│ │ ├── base_work.json ← 基地工作解谜数据
│ │ └── work_W001_story.txt ~ W005 ← 基地工作故事
│ └── people_story/
│ ├── ankexin.txt ← 安可欣剧情
│ ├── anjinian.txt ← 安继年剧情
│ ├── people_quests.json ← 任务数据
│ └── people_relationship.json ← 人物关系数据
├── backrooms_data.json ← 物品/实体数据
├── plugin.py
├── config.py
├── config.toml格式说明
每个故事文件内使用 ===STORY_NNN=== 作为分隔符,格式相同:
===STORY_001===
第一条故事内容……
===STORY_002===
第二条故事内容……规则:
- 每个故事以
===STORY_开头,后跟编号(任意数字或字母),再以===结尾 - 编号只用于分隔,不影响游戏逻辑(不会显示给玩家)
- 两个分隔符之间的内容即该条故事的正文
- 故事正文支持多行文本,会原样展示给玩家
- 编码使用 UTF-8
如何新增故事
在任意 l*_story.txt 文件末尾追加一个新的故事段:
===STORY_009===
你的故事文本写在这里。
可以写多行。
不需要转义,直接写中文即可。也可以新建一个 l12_story.txt(或任意匹配 l*_story.txt 模式的文件)放入 br_story/level_story/ 目录,插件重载后会自动加载。
如何修改现有故事
直接编辑对应 ===STORY_NNN=== 下方的正文内容。分隔符和编号不要改,只改正文部分。
如何删除故事
删除对应的整个段落(从 ===STORY_NNN=== 到下一个分隔符之前的所有内容)。
注意事项
- 插件重载后生效:修改任意故事文件后,需要对插件执行卸载/加载(或重启 MaiBot)才能重新读取。
- 不要删除所有故事:如果文件中没有有效故事,玩家将不会再捡到纸条。
- 空行处理:分隔符之间的空行会被保留,可以利用空行控制段落间距。
- 编号去重:建议使用不重复的编号以便管理,但即使编号重复也不影响程序运行。
- 新文件自动识别:任何匹配
l*_story.txt模式的新文件都会被自动加载,无需修改代码。
人物剧情系统
游戏中,在 Level 1(Alpha 基地)探索时有 40% 概率遇到基地中的 NPC 角色(安可欣、安继年)。首次遇到时对方会赠送 2 瓶杏仁水。每段剧情通过合并转发消息展示。角色在首次遭遇后自动解锁。
自定义角色剧情文件
角色剧情文件位于 br_story/people_story/ 目录,每个 .txt 文件代表一个角色,文件名作为角色 ID。
backrooms_escape/
├── br_story/people_story/
│ ├── ankexin.txt ← 安可欣(信息分析组探员,7段剧情)
│ ├── anjinian.txt ← 安继年(工程部技师,7段剧情)
│ └── people_relationship.json ← 人物关系配置文件(JSON 格式)
└── ...文件格式
使用 ===CHARACTER_NNN=== 作为分隔符,格式与故事纸条相同:
===CHARACTER_001===
你走进了 Alpha 基地的休息区……
===CHARACTER_002===
…数据持久化(存档系统)
插件的玩家游戏进度会自动保存到磁盘,即使插件重载或 MaiBot 重启也不会丢失进度。
存档位置
存档文件存放在插件目录下的 br_data/ 文件夹中:
backrooms_escape/
├── br_data/ ← 存档目录(插件首次加载时自动创建)
│ ├── 123456789.json ← 用户 QQ 号对应的存档文件
│ └── 987654321.json
├── plugin.py
├── config.py
└── ...每个玩家对应一个 JSON 文件,文件名即用户 ID。
存档文件结构
{
"user_id": "123456789",
"current_level": 5,
"health": 85,
"sanity": 72,
"inventory": [
{
"name": "o1",
"type": "consumable",
"effect": "sanity_restore",
"value": 30,
"display_name": "杏仁水",
"description": "后室中最常见的补给品…"
}
],
"exit_attempts": 2,
"pending_note": null,
"state": "ALIVE",
"unlocked_chars": ["ankexin"],
"currency": 85,
"active_quests": ["M001"],
"completed_quests": [],
"pending_quest_offer": null,
"available_works": ["W001", "W002"],
"completed_works": [],
"work_stories": []
}| 字段 | 类型 | 说明 |
|---|---|---|
user_id | string | 玩家 QQ 号 |
current_level | int | 当前所在楼层 |
health | int | 当前生命值 |
sanity | int | 当前理智值 |
inventory | array | 背包物品列表 |
state | string | 游戏状态:"NOT_STARTED" / "ALIVE" / "AT_399" / "DEAD" / "ESCAPED" |
exit_attempts | int | 当前楼层寻找出口的累计次数 |
pending_note | string|null | 待阅读的纸条内容,无则为 null |
unlocked_chars | array | 已解锁的角色 ID 列表 |
currency | int | M.E.G.CN 贡献点余额 |
active_quests | array | 进行中的任务 ID 列表 |
completed_quests | array | 已完成的任务 ID 列表 |
pending_quest_offer | string|null | 待接受的任务 ID |
available_works | array | 基地可用工作 ID 列表 |
completed_works | array | 已完成的工作 ID 列表 |
work_stories | array | 已解锁的工作故事 ID 列表 |
自动保存时机
以下操作完成后会自动保存存档:
| 时机 | 触发操作 |
|---|---|
| 开始新游戏 | /br start |
| 探索完成 | /br explore(无论是否遇敌/获得物品) |
| 寻找出口完成 | /br exit(无论是否找到出口) |
| 使用物品后 | /br use <ID> |
| 查看状态后 | /br status |
| 接受/提交任务 | /br quest accept <ID> / /br quest submit <ID> |
| 完成基地工作 | /br work answer <ID> <答案> |
| 插件卸载 | 插件被重载或 MaiBot 关闭时,批量保存所有在线玩家 |
存档清除时机
以下情况会自动删除存档文件:
- 玩家生命值归零死亡 → 存档被删除,需
/br start重新开始 - 玩家到达 Level 399 通关 → 存档被删除,可
/br start重新挑战
存档恢复
插件每次加载时(包括首次安装和重启),会自动扫描 br_data/ 目录下的所有 .json 文件,将有效存档恢复到内存中。玩家无需手动操作,直接使用 /br status 即可继续之前的游戏。
注意事项
- 不要手动编辑存档:手动修改 JSON 文件可能导致数据格式错误,插件会丢弃损坏的存档并在日志中记录错误。
- 删除存档:如需强制清除某玩家的进度,直接删除
br_data/下对应的.json文件,然后重载插件即可。 - 跨设备迁移:将
br_data/文件夹整体复制到另一台机器的同插件目录下,即可迁移所有玩家存档。