Zum Hauptinhalt springen
S

dsh-dungeon-master

superchipper/dsh-dungeon-master

QQ Bot channel and D&D 5e Dungeon Master plugin for DeepSeek Harness (fork of @tencent-connect/dsh-qqbot; do not enable alongside upstream): /dnd runs turn-based campaigns with 19 `dnd_*` tools for dice, checks, grid positioning, fog and battle maps, story chronicles, snapshot rollbacks and an optional dedicated combat subagent, plus /persona per-chat switching with handoffs, shared Markdown notes, sticker collection, read-only Bilibili tools and per-chat tool-access gating. Direct and group chats default to open in cordis.patch.yml while non-allowlisted QQ chats are blocked from shell and subagents; requires QQBOT_APPID/QQBOT_SECRET or in-app QR binding, with optional sharp for rendered maps and ffmpeg for audio/video. Shared notes are visible to every session, so private-chat content may be recalled in groups.

Installation

dsh plugin --profile web add github:superchipper/dsh-dungeon-master

README

DSH Dungeon Master

English | 简体中文

在 QQ 群里跑 D&D 5e 的 AI 地下城主。 这是 tencent-connect/dsh-qqbot 的二次开发版本:群里发一句 /dnd start,bot 就成了这个群的 DM,骰子、检定、先攻、站位、血量全部由工具结算,模型只负责讲故事。

安装、扫码绑定、基础配置项、内置命令和整体架构都沿用上游,请看 上游 README。本文主要讲跑团,其余新增功能在文末简要列出。

三步开团

  1. 按本地运行装好插件,把 bot 拉进群。
  2. 群里发 /dnd start。这条消息带签到按钮,人齐自动开场;有人来不了就点「开始」。
  3. @bot 说清楚自己的角色做什么:「卡厄斯用巨剑砍地精 3」「恩佐潜行到门口听动静」。

不用换 preset,也不用开新会话:开团后每回合额外注入「DM 守则 + 精简团况」两段 system prompt,/dnd end 后恢复普通聊天。


🎲 跑团

设计原则

  • 所有裁定都走工具:骰点、检定、伤害、HP、状态、位置、资源只能通过 dnd_* 工具改动,模型不能自己编点数。
  • 机密不给到嘴边:DM 笔记、暗门只出现在工具结果里(dnd_* 的结果永远不在群里展示)。怪物的 AC、HP 和 DC 连例行的工具结果和团况里都不给,只给成败和伤势词(毫发无伤 / 受了点伤 / 伤得不轻 / 摇摇欲坠),要裁定时 DM 用 dnd_character show 专门查。
  • 行动只认本人:PC 绑定玩家 openid,只有本人宣告才能行动。工具还会核对这个人最近确实发过消息,模型照抄 openid 也冒充不了。
  • 严格回合制:战斗中只有当前回合的角色能主动行动,PC 的回合只有本人能结束。
  • 状态存在档里,不靠模型记:完整状态是一份 JSON,每回合只往 prompt 里放精简团况。站位、待结算的反应这类要跨压缩保留的东西都写在团况里,不依赖压缩摘要的转述。
  • 判错了能回滚:每次改动都留快照,可以按步数或按骰子编号撤销。

玩家命令

命令说明
/dnd start [模组id]开团(同一模组的旧团接着跑);消息带签到按钮,人齐自动开场
/dnd new [模组id] [blank]存档旧团,从头开新团(默认带上旧角色卡,加 blank 从零建卡)
/dnd status玩家视角的团况:血量、资源、先攻顺序,战斗中附你到各人的距离
/dnd combat最近一场战斗代理的模型与用量,新输入、缓存读取、缓存写入和输出分别统计
/dnd map [battle|explore]发地图:战斗中是站位图,平时是已探索部分的迷雾地图
/dnd checkin再发一次签到按钮
/dnd end [摘要]保存交接并暂停,战斗状态保留;也可以直接说「今天先到这」
/dnd dungeons列出可用模组
/dnd search <词条>查灰机 D&D wiki(法术、技能、职业、专长、怪物…)
/dnd spells [职业]职业法术列表
/dnd help玩法说明

一场团怎么进行

  • 说行动:@bot 并说清楚角色做什么才算行动。闲聊、问规则、「查询状态」都不算,不掷骰也不消耗动作。只能控制自己的角色。
  • 回合按钮:轮到 PC 时,bot 在 DM 的回复后补一条带按钮的消息。
    • 「结束回合」只有本人点击有效,点击后先攻由工具推进,DM 接着结算怪物回合。
    • 「查看状态」由工具直接回复,不经过模型。
    • 「我的法术」列出点击者自己的法术和法术位,每条带 wiki 链接。
    • 「行动」往自己的输入框里预填角色名。
    • 需要 QQ 开放平台的消息按钮权限;发送失败会在本次运行中自动关闭按钮,退回纯文字推进。
  • 反应窗口:有人能反应时,攻击只掷骰、先挂成待结算,等本人答复(护盾术、尖刻言语、时间变幻重掷);一直没人应,由 DM 替他跳过。
  • 分头行动:只有说了要走的人才会移动,其他人留在原地,地图上每个有人的房间各标人数。
  • 回滚:大家同意的话说「卷回到 xx 之前」,DM 用快照撤销,不会靠改数字硬凑。
  • 收团与续团:停团时写一份交接(位置、刚刚发生、已定行动、同行与留守、未结事项、下次接续),先攻、站位和待结算反应原样保留,下次 start 接着跑。停团后聊团不剧透,DM 先查账本再答。

独立战斗代理(可选)

设置页「跑团 → 独立战斗代理」可将战斗交给另一个模型,默认关闭。主 DM 负责掷先攻和叙述开场,回复结束后自动唤醒子 DM 准备场地图、摆位和当前回合;后续玩家消息及按钮直接交给同一个战斗子会话,主模型不逐条转述。默认路由为 opencode-go/deepseek-v4.1-flash、推理 high,交接最近 8000 字对话及角色状态与已记录约定,不复制整个主会话。战斗工具仍实时读写原团档;结束后交回最新状态、消耗与新增账本,主 DM 只接续战后剧情。

dnd:
  combatAgent:
    enabled: true
    provider: opencode-go
    model: deepseek-v4.1-flash
    reasoningEffort: high
    contextChars: 8000

子级只开放战斗所需的 dnd_* 工具,没有终端、文件或任意子代理能力,因此无需给群增加终端白名单。插件重组可恢复活跃子会话;启动或运行失败交回主 DM,不重做已落账行动。/new 会释放子级。每场用量和交接记录保存在跑团目录的 combat-runs/,含 DM 私有资料,不要发给玩家。/dnd combat 只展示用量,包含战后主 DM 的一次交接回复,不包含开战前的主会话;金额按实际渠道账单计算。首次测试时同时观察规则错误与回滚次数,不能只比较单次请求价格。

启用独立代理时,主 DM 隐藏 dnd_position,只加载探索版 dnd_check / dnd_apply 和仅开战的 dnd_initiative;攻击、反应和回合循环参数及完整战斗守则由子 DM 加载。探索检定、陷阱群体豁免、治疗、改卡和资源工具仍保留。子级接管期间主级隐藏全部跑团工具;子级失败或关闭委派时自动恢复主 DM 的完整工具。旧宿主不支持同名工具覆盖时保留完整版本。

构建后还需保存一次设置触发 profile 重组,宿主才会加载新代码。

开战交接会附上角色的职业等级、属性、技能/专精、豁免、武器基础命中与伤害、法术、被动备注、反应和资源,并携带团档中所有 ruling 约定。备注里的能力不会自动成为程序规则:例如现世感知的智力先攻加值,核对后可用 dnd_character update name=奇塔露 init_bonus=7 保存固定总先攻;灵敏之赐的 1d8 仍在开战时通过 bonus 另加。修改固定先攻不重写当前先攻表;属性或能力变化时需同步更新。长期约定用 dnd_chronicle add kind=ruling 保存。

dnd_check type=save targets=[…] 一次掷公共伤害、逐人豁免并结算半伤、抗性和失败状态;每项可单独带 bonus_dice="1d4",只给受到祝福的人加骰。普通 dnd_apply targets=[{name,…}] 可原子批量伤害、治疗、临时生命和状态;damage_roll / heal_roll 由工具统一掷一次,每人可覆盖数值或抗性,一次撤销整批回滚。dnd_character update names=[…] 可批量改卡。

玩家预先授权「最终命中就用至圣斩」时,可传 dnd_check on_hit={name:"至圣斩",damage:"2d8",damage_type:"光耀",spend:"1环法术位"}:所有防守反应结束后才扣一次资源,最终未命中不扣;重击翻倍追加骰,武器与追加分别过抗性,再作为同一击扣血。critical_only=true 仅用于玩家明确授权「重击才用」。这不是替玩家在掷骰后选资源;同回合多次攻击、跨轮持续伤害和看到命中后再询问选择仍逐次处理。普通 spend 仍在掷骰前扣除。

地图与战斗站位

  • 战斗站位:一格 5 尺,按房间画场地图(墙、门、门外走廊、障碍、难行地形)。移动按意图走,Dijkstra 寻路绕墙和敌人格,难行地形双倍,同距离优先少触发借机。逐步检查整条路线,在离开触及之前或长柄大师入圈处暂停;问清并结算借机后才继续剩余移动。反应按内置 0/1 记账,到本人下回合开始恢复,不另建 dnd_resource;护盾术持续到本人下回合开始。战斗中换房间要先走到对应出口;真正的强制位移/传送才用 set 或 dnd_character forced_move=true。
  • 范围法术:球、立方、线形先查罩到哪些敌我,再决定放不放。
  • 图片地图(需要可选依赖 sharp):战斗中发当前房间的战斗图,标出站位和坐标,模组有底图就用底图;平时发已探索部分的迷雾地图,有书里的玩家版地图就用它。没装 sharp 时退回聊天框里的字符地图。

DM 工具

类别工具作用
掷骰dnd_roll任意骰子表达式(2d6+3、4d6kh3…)
dnd_check检定、豁免、攻击、死亡豁免;逐目标加骰、on_hit 预授权命中追加;反应攻击自动扣反应,每一骰带 #R 编号
dnd_apply单人/targets 批量伤害、治疗、临时 HP、状态,公共伤害/治疗可直接掷骰;处理待结算骰子、反应及暂停移动
角色dnd_character建卡/改卡(玩家绑定、武器、法术清单、物品金币);展示、核对和改卡先 show 查当前卡,修改成功才确认保存;停团可建、改、查 PC 卡,不删卡或改位置;names 一次改多人(发东西、换房间、max_hp_change 加减生命上限);srd=goblin count=3 从 SRD 取真实数值加怪
dnd_resource法术位、圣疗池、诗人激励、职业特性次数;停团也可用 set 配置 PC 资源
dnd_rest短休(工具掷生命骰回血)/ 长休
战斗dnd_initiative先攻 start / next / goto / end / status;surprised 的人第 1 轮由工具跳过
dnd_position战斗内站位:画场地图、摆位、回合内移动、距离查询、area 查范围法术
探索dnd_move房间移动(who 分头行动、暗门发现),返回玩家视角描述 + DM 机密;出口检定已经用 dnd_check 投过时传 check_done 不再重掷
dnd_map发战斗图或迷雾地图到群里
剧情dnd_story按 id 改模组里写好的剧情状态:触发器、信息、任务、NPC 生死与同行
dnd_lookup查模组细节(房间、NPC、线索),只给 DM 看;kind=character 看队伍的角色卡,停团时也能查
dnd_hook背景钩子:玩家讲的角色来历里没了结的事挂在 PC 卡上,碰到触发词提醒 DM,分 5 档推进
dnd_chronicle长期剧情账本:临场事实、承诺、俘虏和未结线头,按关键词查询;停团后仍可查
存档dnd_undo列出最近改动 / 撤销 N 步 / 按骰子编号撤回那一骰和它之后的后果
dnd_progress保存进度但不暂停,按段增量修改
dnd_prepareDM 私有备团:核对团况与交接,保存候选计划;不推进剧情、不向群里发送
dnd_end与 /dnd end 共用保存与暂停流程
查询dnd_srd查 5e SRD 怪物/法术(dnd5eapi.co)

工具层还自动处理一部分规则:PC 0 HP 倒地与死亡豁免、溢出伤害即死、重击骰子翻倍、「不死坚韧」;手动解除「死亡」会被拒绝。

模组

  • 内置「沉钟修道院」:原创的 7 房间小地城,适合 1–3 级、3–5 人一晚打完,怪物数值取自 SRD 5.1(CC BY 4.0)。
  • 自己写模组:把 JSON 放进 <dnd.root>/adventures/,小模组一个文件,大模组按场景拆文件;文件改了自动重读,不用重启。模组可以写章节、场景、房间、NPC(含 knows:他知道什么、不知道什么)、线索、任务、触发器和战斗场地图。完整写法见 模组编写指南。
  • 旧的单地城格式(dungeons/*.json)仍然可用。
  • 版权:商业模组(如《凡达林的失落矿坑》)转出来的文本只放在本机自用,不要提交进仓库。

数据与配置

  • 每个群一份团档 <dnd.root>/campaigns/<会话>.json,改动快照存在 campaigns/history/(最近 40 步)。团档只能经 dnd_* 工具修改,文件工具写不进去。
  • dnd_* 工具只对有团的 QQ 会话可见:没开团的群和私聊不带这些工具(省下约一万 token 的工具说明),停团时只留查账本、备团和补写交接用的几个,/dnd start 后全部可用。
  • 状态怎么跨压缩、跨停团保留,以及踩过的坑,见 跑团状态长期化的开发记录。
配置默认值说明
dnd.enabledtrue跑团开关(/dnd 命令 + dnd_* 工具)
dnd.rootcwd/dnd团档、模组的数据目录
dnd.turnButtonstrue轮到玩家时发回合按钮
dnd.interjectionstrue开团期间也按插话概率随机吐槽(只吐槽、不结算);关掉后只回 @

其他功能

除跑团外,本仓库在上游基础上还加了这些。配置项都在 DSH Web「插件」页的 QQ 机器人设置里,带说明。

方向内容
💬 群聊未 @ 时按概率或「回复欲望」打分接话;群消息落盘,重启后接得上;能看历史图片;合并消息保留各自发送者;上下文超限自动压缩;/new 时先压缩旧会话,把压缩摘要带进新会话(/new blank 完全从头)
🎭 人设群聊和私聊都支持 /persona(或 /人设)按钮切换,也可用 /persona 名字;主人和管理员可操作。每个聊天独立选择,各人设保留自己的历史;切换前生成跨人格共同交接,接手时只补未接收的版本;/persona 默认 恢复对应的 groupPrompt / directPrompt
🧠 记忆notes/ 下的 Markdown 笔记库,所有会话共用、按内容自动召回;chat 范围的笔记只在本群可见。主人私聊发 /bot-notes 查看注入情况
😺 表情按情绪自动收藏(qqbot_save_sticker)、按哈希匹配(qqbot_match_sticker)、梗图识别 skill
🖼 媒体图文同发(caption)、deepseek-native 原生读图、语音识别、整段视频理解与关键帧复查、音频转写、合并转发里的图片
🔧 工具以图搜图、B 站只读工具、同人图挑选、Playwright 浏览器(默认关闭,按群白名单授权)、Agent 临时目录与定期清理(/bot-cleanup)
⏰ 定时/new 和人设切换时自动迁移定时任务;群聊主动消息失败后补发
🔁 模型上游状态监测与主备模型自动切换(modelFailover,默认关闭)
🧩 DSH 集成在 DSH Web「插件」页安装、启停和改配置;桌宠余额兼容 deepseek-native

人格交接保存在 ~/.dsh-qqbot/persona-handoffs/<聊天键哈希>.json,按应用、群聊/私聊分别隔离。切换保留来源会话实际选用的模型,不随人格回落到默认模型;交接从已有压缩摘要、未覆盖的对话及工具证据生成,优先保留用户纠正和未完成事项。长记录逐段保存草稿,失败重试可继续处理未读部分。目标人格按「自身设定 → 自身历史 → 最新共同交接 → 新消息」接续,旧人格的身份与说话习惯不继承。版本、来源、时间、覆盖到的 session/事件位置及各人格接收记录均落盘,后台任务 ID 和定时任务迁移配置独立保留并要求先查状态;摘要失败时保留旧版、保存未覆盖原文并明确提示。切换需等待整理完成,期间新消息会等候;跑团期间仍禁止切换。更新宿主后可运行 node scripts/check-persona-handoff-host.mjs [宿主包目录],用实际安装的 v4 编解码器离线检查消息持久化格式。

权限

  • allowlist 为空时拒绝所有人(fail-closed);/model、/preset 和审批按钮只有 ownerOpenid / adminOpenids 能操作。
  • 按会话限制工具(toolAccess,默认开启):主人私聊和白名单会话不受限;其他 QQ 会话不给终端和子 agent,文件工具只能碰 media、表情库、临时目录和 toolAccess.readRoots。本机会话(Web/Desktop)不受影响。
  • 主人在私聊里说「给 XX 群开终端」即可加白名单;在群里只能发起申请,由主人本人点按钮同意。
  • fileAccess.sensitivePaths 里的路径对受限会话一律拦(即使在 readRoots 里);白名单会话有终端,不拦。关掉 toolAccess 后对所有 QQ 会话都拦。
  • B 站登录和字幕仅限私聊主人/管理员;以图搜图会把图片上传到第三方服务,只在用户明确问出处时才调用。

共享笔记对所有会话可见,私聊内容也可能在群里被召回。不要让 bot 记隐私,主人应定期翻看 notes/ 清理。

本地运行

勿与上游 @tencent-connect/dsh-qqbot 在同一 profile 中同时启用(两者共用 im-qqbot 插件 ID)。

# 从 npm 安装(发布后可用)
dsh plugin --profile web add dsh-dungeon-master

# 或从本地源码构建并挂载
pnpm install && pnpm build
npx @deepseek-ai/dsh plugin --profile qqbot add /path/to/dsh-dungeon-master
npx @deepseek-ai/dsh --profile qqbot

插件加载的是 dist/:改完代码要 pnpm build,并重启 dsh 才会生效。图片地图需要可选依赖 sharp,视频相关工具需要 ffmpeg/ffprobe。其他安装方式见上游 README。

安全与隐私

  • 凭据只放在 profile 的 cordis.patch.yml 或环境变量里,不要提交。
  • 运行期数据不进仓库:media/(群聊和私聊附件,可能涉及他人隐私)、stickers/、notes/、dnd/、tmp/。
  • 提交前用 git status --short 和 git diff --cached 复查。

致谢与许可

MIT

Ähnliche Plugins