koishi-plugin-mcdle 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 0.7.1 · 2026-10-02
2
+
3
+ 卡片小字号整体放大一档(最小 13px):列头、模式名、图例、战绩分项原来是 11 / 12px,缩到聊天里的大小只剩 5 个点。版式不变。
4
+
5
+ # 0.7.0 · 2026-09-26
6
+
7
+ 猜测恢复成一行一次猜测的列表,便于逐项对照;单句页脚居中。 主指令在 help 列表里补回描述;去掉「.显示」显示模式指令,有图只发图、出图失败才退回文字;多轮输入不再追加计时说明。
8
+
1
9
  # 0.6.0 · 2026-09-26
2
10
 
3
11
  猜测历史保留完整属性文字,棋盘改为两列属性卡;个人文字模式和裸猜冲突保护。
package/DESIGN_SYSTEM.md CHANGED
@@ -13,12 +13,12 @@
13
13
 
14
14
  ## 输出、交互与内容
15
15
 
16
- 1. 图文模式只发渲染图,不附文字;完整文字只在用户切到「文字」模式时出现。图片的等价文字随图片标记,切换到文字模式时展开,因此不会在群里重复刷屏。
17
- 2. `插件主指令.显示 文字` / `插件主指令.显示 图文` 切换个人显示偏好;同一机器人中的这些插件共享选择。设置保存在内存,重启恢复图文。文本回复不能把后续条目无提示地压掉;较长管理列表分页。
16
+ 1. 有渲染图时只发图片,不附同内容的文字,避免在群里重复刷屏;图片生成失败时才退回文字。插件不提供个人显示模式开关。
17
+ 2. 每个插件的主指令都带描述,`help` 列表右侧不留空;主指令先于任何子指令注册(Koishi 会忽略已存在指令的描述)。文本回复不能把后续条目无提示地压掉;较长管理列表分页。
18
18
  3. 裸输入必须符合词法、对局状态及参与条件。多个插件匹配时不执行,要求明确完整指令;完整指令继续可用。
19
19
  4. 回复说明当前结果、未完成原因和可执行的下一步,不用管理员日志替代用户可用的反馈。退款、赔付与渲染失败不能伪装成功。
20
20
  5. 破坏性清空需展示范围、不可撤销性和限时确认码。确认码限制到同一机器人、平台、用户与频道,使用后立即失效。
21
- 6. 多轮输入允许 5 分钟等待,发送「延长」重新计时,发送「取消」退出。斗牛、21 点提供延长等待入口。文字模式不主动撤回已发出的说明。
21
+ 6. 多轮输入等待 5 分钟,提问里写明可回复的内容与「取消」,不再追加计时说明。对局内的短窗口(如 21 点保险、投降)提供显式跳过,全员表态后立即进入下一阶段,而不是提供「延长」。
22
22
  7. 货币发放先写入核对记录,入账结果不明确时保留待核对状态,不自动重发。管理员核对实际流水并按需人工补发后标记确认;确认操作自身不转账。
23
23
 
24
24
  ## 内容边界
@@ -44,7 +44,7 @@ node markdown-to-image-service/scripts/sync-design-system.mjs --check
44
44
 
45
45
  官方色彩算法可在源仓库安装开发依赖后通过 `node scripts/build-material-colors.mjs` 重建,再同步消费者。
46
46
 
47
- 回归检查覆盖:24 个源色相的明暗角色对比度、奖牌前景、图表填充/轨道差异、浏览器/服务端 HCT 一致性、文字输出与身份隔离、输入冲突、可延长输入、入账异常、清空确认和 Wordle 并发/渲染失败。工作区截图脚本为 `scripts/verify-rendering.ts`,需 Puppeteer Core 和可用 Chromium。
47
+ 回归检查覆盖:24 个源色相的明暗角色对比度、奖牌前景、图表填充/轨道差异、浏览器/服务端 HCT 一致性、主指令描述、输入冲突、入账异常、清空确认和 Wordle 并发/渲染失败。工作区截图脚本为 `scripts/verify-rendering.ts`,需 Puppeteer Core 和可用 Chromium。
48
48
 
49
49
  ## 本轮改动对应关系
50
50
 
@@ -53,9 +53,9 @@ node markdown-to-image-service/scripts/sync-design-system.mjs --check
53
53
  | 共享设计规范 | 官方 HCT、2025 动态颜色角色、共享字阶与间距、同步与哈希校验 |
54
54
  | Markdown | M3 明暗主题;旧主题名按明暗迁移;代码高亮与 Mermaid 使用 M3 角色;长代码可换行 |
55
55
  | message-counter / monetary-rank | M3 角色与共享图表字阶、HCT 头像配色、完整文字榜单;保留昵称截断 |
56
- | Wordle | 替换复制的 NYT 外观;状态符号与图例;明暗角色;文字棋盘;异常释放并发锁;安全解析模式编号 |
57
- | MCDLE | 历史猜测完整文字属性;两列属性卡减少超宽表格 |
56
+ | Wordle | 替换复制的 NYT 外观;状态符号与图例;明暗角色;异常释放并发锁;安全解析模式编号;裸词只在确定是猜测时回应 |
57
+ | MCDLE | 猜测按行排成一张表,方便逐项对照;单句页脚居中 |
58
58
  | 2048 / ciyi | 数字与奖牌前景按实际对比度选色 |
59
- | 斗牛 / 21 点 | 付款核对记录、如实反馈退款失败、明确下注金额、延长操作窗口 |
59
+ | 斗牛 / 21 点 | 付款核对记录、如实反馈退款失败、明确下注金额、可显式跳过的短窗口 |
60
60
  | sentinel | 完整封印列表按每页 10 位展示 |
61
- | 其余插件 | 图文双通道、个人文字模式、可取消/延长输入与上下文反馈 |
61
+ | 其余插件 | 渲染失败退回文字、可取消输入与上下文反馈 |
package/README.md CHANGED
@@ -1,16 +1,21 @@
1
1
  # 我的世界猜谜
2
2
 
3
- Koishi 猜谜插件,题库包含《我的世界》的生物、物品和方块。
3
+ Koishi 插件:玩《我的世界》猜谜,凭属性提示从生物、物品、方块中锁定唯一答案
4
+
5
+ [![GitHub](https://img.shields.io/badge/GitHub-araea%2Fkoishi--plugin--mcdle-181717?logo=github&logoColor=white)](https://github.com/araea/koishi-plugin-mcdle)
6
+ [![npm](https://img.shields.io/npm/v/koishi-plugin-mcdle?logo=npm&logoColor=white&color=CB3837)](https://www.npmjs.com/package/koishi-plugin-mcdle)
4
7
 
5
8
  ## 安装
6
9
 
7
10
  ```sh
8
- yarn add koishi-plugin-mcdle
11
+ npm i koishi-plugin-mcdle
9
12
  ```
10
13
 
11
- 在 Koishi 中启用,并安装 `database` 服务。图片输出可选,需要 `puppeteer` 服务。
14
+ 启用插件,并安装 `database` 服务。图片输出可选,需要 `puppeteer` 服务。
15
+
16
+ ## 快速使用
12
17
 
13
- ## 指令
18
+ 发送 `mcdle` 查看玩法与全部指令。发送 `mcdle.猜 [名称]` 开局或提交猜测;首次猜测的词条决定题目类型(生物 / 物品 / 方块)。
14
19
 
15
20
  | 指令 | 说明 |
16
21
  | --- | --- |
@@ -20,14 +25,29 @@ yarn add koishi-plugin-mcdle
20
25
  | `mcdle.排行榜` | 查看本群战绩 |
21
26
  | `mcdle.词库` | 查看全部词条 |
22
27
 
23
- 首次猜测的词条决定题目类型。提示中,🟩 表示完全匹配,🟨 表示部分匹配,🟥 表示不匹配;🟥⬆️ 和 🟥⬇️ 表示答案更大或更小。裸猜设置仅对当前群有效,插件重载后恢复默认。
28
+ 提示颜色:🟩 完全匹配,🟨 部分匹配,🟥 不匹配;🟥⬆️ / 🟥⬇️ 表示答案更大或更小。裸猜设置仅对当前频道有效,插件重载后恢复默认。
29
+
30
+ ## 配置
31
+
32
+ | 配置项 | 类型 | 默认值 | 说明 |
33
+ | --- | --- | --- | --- |
34
+ | `atReply` | boolean | `false` | 回复时 @ 用户 |
35
+ | `quoteReply` | boolean | `false` | 回复时引用消息 |
36
+ | `enableDirectInput` | boolean | `false` | 对局中直接发送词条名称即可续猜 |
37
+ | `addStatusTextAfterEmoji` | boolean | `true` | 在状态方块后补一段文字说明 |
38
+ | `maxRank` | number | `10` | 排行榜最多显示的人数 |
39
+ | `dailyPlayLimit` | number | `1` | 每个频道每日可开始的局数,跨零点重置 |
40
+ | `retractDelay` | number | `0` | 自动撤回延迟(秒),0 表示不撤回 |
41
+ | `allowRepeatedGuesses` | boolean | `false` | 允许重复提交已猜过的词条 |
42
+ | `disableImages` | boolean | `false` | 全部改用文本,不发送图片 |
24
43
 
25
- ## 许可证
44
+ ## 限制 / 风险
26
45
 
27
- 可按 [Apache-2.0](LICENSE-APACHE) 或 [MIT](LICENSE-MIT) 使用。
46
+ 依赖 `database` 服务持久化对局与战绩。图片输出需 `puppeteer`,未安装或渲染失败时自动回退为等价文本,不中断对局。
28
47
 
29
- ## 显示与交互
48
+ 裸猜为各频道内存态,插件重载后回到配置默认。
30
49
 
31
- 发送 `mcdle.显示 文字` 或 `mcdle.显示 图文` 切换个人显示偏好。同一机器人中的配套插件共享选择,重启后恢复图文。图文模式中的信息图片附带文字说明;作品素材与感官测试的适用边界见 [设计系统](./DESIGN_SYSTEM.md)。
50
+ ## 链接
32
51
 
33
- 本次更新:猜测历史保留完整属性文字,棋盘改为两列属性卡;个人文字模式和裸猜冲突保护。
52
+ - [设计系统](DESIGN_SYSTEM.md)
53
+ - [MIT](LICENSE-MIT) / [Apache-2.0](LICENSE-APACHE)
package/lib/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Context, Schema, Session } from 'koishi';
2
2
  import { MobData, BlockData, ItemData } from './data';
3
3
  export declare const name = "mcdle";
4
- export declare const usage = "## \u4F7F\u7528\n\n\u53D1\u9001 `mcdle` \u67E5\u770B\u73A9\u6CD5\u4E0E\u5168\u90E8\u6307\u4EE4\u3002`mcdle.\u731C [\u540D\u79F0]` \u7528\u6709\u6548\u8BCD\u6761\u5F00\u5C40\u6216\u731C\u6D4B\u3002\u9996\u6B21\u731C\u6D4B\u7684\u8BCD\u6761\u51B3\u5B9A\u751F\u7269\u3001\u7269\u54C1\u6216\u65B9\u5757\u6A21\u5F0F\uFF0C\u7CFB\u7EDF\u518D\u4ECE\u540C\u7C7B\u8BCD\u5E93\u4E2D\u62BD\u53D6\u7B54\u6848\u3002\n\n## \u6307\u4EE4\n\n| \u6307\u4EE4 | \u8BF4\u660E |\n| --- | --- |\n| `mcdle` | \u73A9\u6CD5\u4E0E\u6307\u4EE4\u8BF4\u660E |\n| `mcdle.\u731C [\u540D\u79F0]` | \u7528\u6709\u6548\u8BCD\u6761\u5F00\u5C40\u6216\u731C\u6D4B |\n| `mcdle.\u88F8\u731C [\u5F00/\u5173]` | \u5F00\u5173\u672C\u9891\u9053\u7684\u65E0\u524D\u7F00\u7EED\u731C |\n| `mcdle.\u6392\u884C\u699C` | \u7D2F\u8BA1\u6218\u7EE9 |\n| `mcdle.\u8BCD\u5E93` | \u5168\u90E8\u8BCD\u6761 |\n\n## \u63D0\u793A\n\n| \u7B26\u53F7 | \u542B\u4E49 |\n| --- | --- |\n| \uD83D\uDFE9 | \u5B8C\u5168\u5339\u914D |\n| \uD83D\uDFE8 | \u90E8\u5206\u5339\u914D |\n| \uD83D\uDFE5 | \u4E0D\u5339\u914D |\n| \uD83D\uDFE5\u2B06\uFE0F / \uD83D\uDFE5\u2B07\uFE0F | \u7B54\u6848\u66F4\u5927 / \u66F4\u5C0F |";
4
+ export declare const usage = "## \u4F7F\u7528\n\n\u53D1\u9001 `mcdle` \u67E5\u770B\u73A9\u6CD5\u4E0E\u5168\u90E8\u6307\u4EE4\u3002`mcdle.\u731C [\u540D\u79F0]` \u5F00\u5C40\u6216\u63D0\u4EA4\u731C\u6D4B\u3002\u9996\u6B21\u731C\u6D4B\u7684\u8BCD\u6761\u51B3\u5B9A\u9898\u76EE\u7C7B\u578B\u3002\n\n## \u6307\u4EE4\n\n| \u6307\u4EE4 | \u8BF4\u660E |\n| --- | --- |\n| `mcdle` | \u67E5\u770B\u73A9\u6CD5\u4E0E\u6307\u4EE4 |\n| `mcdle.\u731C [\u540D\u79F0]` | \u5F00\u5C40\u6216\u63D0\u4EA4\u731C\u6D4B |\n| `mcdle.\u88F8\u731C [\u5F00/\u5173]` | \u5207\u6362\u672C\u9891\u9053\u65E0\u524D\u7F00\u7EED\u731C |\n| `mcdle.\u6392\u884C\u699C` | \u67E5\u770B\u672C\u7FA4\u6218\u7EE9 |\n| `mcdle.\u8BCD\u5E93` | \u67E5\u770B\u5168\u90E8\u8BCD\u6761 |\n\n## \u63D0\u793A\n\n| \u7B26\u53F7 | \u542B\u4E49 |\n| --- | --- |\n| \uD83D\uDFE9 | \u5B8C\u5168\u5339\u914D |\n| \uD83D\uDFE8 | \u90E8\u5206\u5339\u914D |\n| \uD83D\uDFE5 | \u4E0D\u5339\u914D |\n| \uD83D\uDFE5\u2B06\uFE0F / \uD83D\uDFE5\u2B07\uFE0F | \u7B54\u6848\u66F4\u5927 / \u66F4\u5C0F |";
5
5
  export declare const inject: {
6
6
  required: string[];
7
7
  optional: string[];
package/lib/index.js CHANGED
@@ -36,28 +36,13 @@ var import_koishi = require("koishi");
36
36
  var KEY = Symbol.for("araea.koishi.ux.v1");
37
37
  function state(ctx) {
38
38
  const root = ctx.root;
39
- return root[KEY] ??= { modes: /* @__PURE__ */ new Map(), owners: /* @__PURE__ */ new Set() };
39
+ return root[KEY] ??= { owners: /* @__PURE__ */ new Set() };
40
40
  }
41
41
  __name(state, "state");
42
- var userKey = /* @__PURE__ */ __name((session) => `${session.platform}:${session.selfId}:${session.userId}`, "userKey");
43
- function usePresentation(ctx, command) {
44
- const shared = state(ctx);
45
- ctx.command(`${command}.显示 [mode:string]`, "选择图文或文字输出").action(({ session }, mode) => {
46
- if (!mode) return `当前:${shared.modes.get(userKey(session)) ? "文字" : "图文"}。发送「${command}.显示 文字」或「${command}.显示 图文」。设置对本机器人各插件生效,重启后恢复图文。`;
47
- if (!["文字", "图文"].includes(mode)) return "请选择「文字」或「图文」。";
48
- shared.modes.set(userKey(session), mode === "文字");
49
- return `已切换为${mode}输出。`;
50
- });
51
- return {
52
- textOnly: /* @__PURE__ */ __name((session) => shared.modes.get(userKey(session)) === true, "textOnly"),
53
- /** 图文模式只给图片;图片缺失或用户选了文字模式时才退回文字。 */
54
- present(session, image, text) {
55
- if (!image || shared.modes.get(userKey(session))) return text;
56
- return import_koishi.h.normalize(image);
57
- }
58
- };
42
+ function present(image, text) {
43
+ return image ? import_koishi.h.normalize(image) : text;
59
44
  }
60
- __name(usePresentation, "usePresentation");
45
+ __name(present, "present");
61
46
  function registerDirectInput(ctx, name2, matches) {
62
47
  const owner = { name: name2, matches };
63
48
  state(ctx).owners.add(owner);
@@ -19923,6 +19908,7 @@ var CHART_TYPE = { count: TYPE.titleLarge.size, percent: TYPE.bodyMedium.size, r
19923
19908
  var LEGACY_CHART_SIZE = { 30: CHART_TYPE.count, 20: CHART_TYPE.percent, 22: CHART_TYPE.rank, 32: CHART_TYPE.title, 18: CHART_TYPE.meta, 9: SPACING.sm };
19924
19909
 
19925
19910
  // src/view.ts
19911
+ var TS = { labelSmall: 13, bodySmall: 14, labelMedium: 14, bodyMedium: 15, labelLarge: 15, titleSmall: 16 };
19926
19912
  var HUE = 138;
19927
19913
  var SCHEME = scheme(HUE, true);
19928
19914
  var accentOf = /* @__PURE__ */ __name((hue) => lch(80, 46, hue), "accentOf");
@@ -20453,10 +20439,10 @@ html,body{background:transparent}
20453
20439
  .brand .mark{color:var(--accent)}
20454
20440
  .brand .word{font-size:${TYPE.headlineMedium.size}px;font-weight:${EMPHASIZED_WEIGHT.headline};letter-spacing:.18em;line-height:1}
20455
20441
  .brand .word b{color:var(--accent);font-weight:${EMPHASIZED_WEIGHT.headline}}
20456
- .hd .sub{margin-top:8px;font-size:${TYPE.bodySmall.size}px;letter-spacing:.05em;color:var(--md-sys-color-on-surface-variant)}
20442
+ .hd .sub{margin-top:8px;font-size:${TS.bodySmall}px;letter-spacing:.05em;color:var(--md-sys-color-on-surface-variant)}
20457
20443
  .hd-meta{text-align:right;flex:none}
20458
20444
  .hd-meta .big{font-family:${NUM_FONT};font-size:${TYPE.headlineMedium.size}px;font-weight:${EMPHASIZED_WEIGHT.headline};color:var(--accent);line-height:1;font-variant-numeric:tabular-nums}
20459
- .hd-meta .cap{font-size:${TYPE.labelSmall.size}px;letter-spacing:.1em;color:var(--md-sys-color-on-surface-variant);margin-top:6px}
20445
+ .hd-meta .cap{font-size:${TS.labelSmall}px;letter-spacing:.1em;color:var(--md-sys-color-on-surface-variant);margin-top:6px}
20460
20446
 
20461
20447
  /* 模式徽记:药丸形。底色是每模式各自的 accent(同一套色调板上的色调 80),
20462
20448
  不是主题容器色,m3-chip 没有对应档位 */
@@ -20464,7 +20450,7 @@ html,body{background:transparent}
20464
20450
  display:inline-flex;align-items:center;gap:7px;padding:6px 14px;
20465
20451
  border-radius:var(--md-sys-shape-corner-full);
20466
20452
  background:var(--accent);color:var(--md-sys-color-surface);
20467
- font-size:${TYPE.labelMedium.size}px;letter-spacing:.06em;font-weight:${EMPHASIZED_WEIGHT.label};
20453
+ font-size:${TS.labelMedium}px;letter-spacing:.06em;font-weight:${EMPHASIZED_WEIGHT.label};
20468
20454
  }
20469
20455
 
20470
20456
  /* ── 猜测板 ───────────────────────────────────────── */
@@ -20472,7 +20458,7 @@ table{border-collapse:separate;border-spacing:6px;margin:0 -6px}
20472
20458
  th{padding:0 0 8px;vertical-align:bottom}
20473
20459
  .col{display:flex;flex-direction:column;align-items:center;gap:6px;
20474
20460
  min-width:80px;max-width:132px;color:var(--md-sys-color-on-surface-variant)}
20475
- .col .lb{font-size:${TYPE.labelSmall.size}px;letter-spacing:.04em;color:var(--md-sys-color-on-surface-variant);
20461
+ .col .lb{font-size:${TS.labelSmall}px;letter-spacing:.04em;color:var(--md-sys-color-on-surface-variant);
20476
20462
  text-align:center;line-height:1.25;font-weight:${EMPHASIZED_WEIGHT.label}}
20477
20463
  th.n .col{align-items:flex-start;min-width:150px}
20478
20464
 
@@ -20488,11 +20474,11 @@ td{padding:0}
20488
20474
  /* 多标签字段给更宽的上限,否则一列里会折成很高的一坨 */
20489
20475
  .tile.list{max-width:168px}
20490
20476
  th.list .col{max-width:168px}
20491
- .tile .v{font-size:${TYPE.titleSmall.size}px;font-weight:${EMPHASIZED_WEIGHT.title};line-height:1.35;text-align:center;
20477
+ .tile .v{font-size:${TS.titleSmall}px;font-weight:${EMPHASIZED_WEIGHT.title};line-height:1.35;text-align:center;
20492
20478
  color:${INK};word-break:break-word}
20493
20479
  .tile .chips{display:flex;flex-wrap:wrap;gap:4px;justify-content:center}
20494
20480
  .chip{
20495
- font-size:${TYPE.labelSmall.size}px;line-height:1.35;padding:2px 8px;
20481
+ font-size:${TS.labelSmall}px;line-height:1.35;padding:2px 8px;
20496
20482
  border-radius:var(--md-sys-shape-corner-full);
20497
20483
  color:${INK};background:color-mix(in srgb, var(--md-sys-color-scrim) 24%, transparent);
20498
20484
  }
@@ -20531,11 +20517,11 @@ th.list .col{max-width:168px}
20531
20517
  .thumb.failed .fb{display:block}
20532
20518
  .name .txt{min-width:0}
20533
20519
  .name .cn{font-size:${TYPE.titleMedium.size}px;font-weight:${EMPHASIZED_WEIGHT.title};line-height:1.25}
20534
- .name .en{font-size:${TYPE.labelSmall.size}px;letter-spacing:.04em;color:var(--md-sys-color-on-surface-variant);margin-top:3px;
20520
+ .name .en{font-size:${TS.labelSmall}px;letter-spacing:.04em;color:var(--md-sys-color-on-surface-variant);margin-top:3px;
20535
20521
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:150px}
20536
20522
  .name.correct .cn,.name.correct .en,.name.correct .no{color:${INK}}
20537
20523
  .name.correct .en,.name.correct .no{opacity:.78}
20538
- .name .no{font-family:${NUM_FONT};font-size:${TYPE.labelSmall.size}px;color:var(--md-sys-color-on-surface-variant);margin-top:3px}
20524
+ .name .no{font-family:${NUM_FONT};font-size:${TS.labelSmall}px;color:var(--md-sys-color-on-surface-variant);margin-top:3px}
20539
20525
 
20540
20526
  /* 最新一行的强调:外圈一圈 2px 描边 + 行首的圆头标记。
20541
20527
  这是高亮环不是层高,所以用 outline 而不是 box-shadow */
@@ -20554,7 +20540,7 @@ tr.fresh .name::before{content:"";position:absolute;left:0;top:14px;bottom:14px;
20554
20540
  background:var(--md-sys-color-surface-container-highest);
20555
20541
  }
20556
20542
  .prog .fill{height:100%;border-radius:var(--md-sys-shape-corner-full);background:var(--accent)}
20557
- .prog .num{font-family:${NUM_FONT};font-size:${TYPE.labelMedium.size}px;color:var(--md-sys-color-on-surface-variant);letter-spacing:.04em;flex:none;
20543
+ .prog .num{font-family:${NUM_FONT};font-size:${TS.labelMedium}px;color:var(--md-sys-color-on-surface-variant);letter-spacing:.04em;flex:none;
20558
20544
  font-variant-numeric:tabular-nums}
20559
20545
 
20560
20546
  /* ── 图例 / 页脚 ──────────────────────────────────── */
@@ -20566,15 +20552,15 @@ tr.fresh .name::before{content:"";position:absolute;left:0;top:14px;bottom:14px;
20566
20552
  .lg{
20567
20553
  display:flex;align-items:center;gap:6px;padding:5px 12px;
20568
20554
  border-radius:var(--md-sys-shape-corner-full);
20569
- font-size:${TYPE.labelSmall.size}px;color:${INK};background:var(--tile);
20555
+ font-size:${TS.labelSmall}px;color:${INK};background:var(--tile);
20570
20556
  }
20571
20557
  .lg.s-none{color:var(--md-sys-color-on-surface-variant)}
20572
- .tip{margin-left:auto;font-size:${TYPE.labelSmall.size}px;color:var(--md-sys-color-on-surface-variant);letter-spacing:.02em}
20558
+ .tip{margin-left:auto;font-size:${TS.labelSmall}px;color:var(--md-sys-color-on-surface-variant);letter-spacing:.02em}
20573
20559
 
20574
20560
  /* ── 通用区块 ─────────────────────────────────────── */
20575
20561
  .sec{margin-top:22px}
20576
20562
  .sec:first-child{margin-top:0}
20577
- .sec-t{display:flex;align-items:center;gap:10px;font-size:${TYPE.labelMedium.size}px;letter-spacing:.1em;
20563
+ .sec-t{display:flex;align-items:center;gap:10px;font-size:${TS.labelMedium}px;letter-spacing:.1em;
20578
20564
  font-weight:${EMPHASIZED_WEIGHT.label};color:var(--md-sys-color-on-surface-variant);margin-bottom:12px}
20579
20565
  .sec-t::after{content:"";flex:1;height:1px;background:var(--md-sys-color-outline-variant)}
20580
20566
  .panel{
@@ -20583,10 +20569,10 @@ tr.fresh .name::before{content:"";position:absolute;left:0;top:14px;bottom:14px;
20583
20569
  background:var(--md-sys-color-surface-container);
20584
20570
  }
20585
20571
  .rows{display:flex;flex-direction:column;gap:9px}
20586
- .row{display:flex;align-items:center;gap:10px;font-size:${TYPE.bodyMedium.size}px;
20572
+ .row{display:flex;align-items:center;gap:10px;font-size:${TS.bodyMedium}px;
20587
20573
  color:var(--md-sys-color-on-surface);line-height:1.5}
20588
20574
  .row .k{color:var(--accent);flex:none;font-weight:${EMPHASIZED_WEIGHT.label}}
20589
- .row .m{color:var(--md-sys-color-on-surface-variant);font-size:${TYPE.bodySmall.size}px}
20575
+ .row .m{color:var(--md-sys-color-on-surface-variant);font-size:${TS.bodySmall}px}
20590
20576
  .cmd{
20591
20577
  font-weight:${EMPHASIZED_WEIGHT.label};color:var(--md-sys-color-on-surface);
20592
20578
  background:var(--md-sys-color-surface-container-highest);
@@ -20600,8 +20586,8 @@ tr.fresh .name::before{content:"";position:absolute;left:0;top:14px;bottom:14px;
20600
20586
  background:var(--md-sys-color-surface-container);
20601
20587
  }
20602
20588
  .mode-card .top{display:flex;align-items:center;gap:9px;font-size:${TYPE.titleMedium.size}px;font-weight:${EMPHASIZED_WEIGHT.title}}
20603
- .mode-card .cnt{font-size:${TYPE.labelSmall.size}px;color:var(--md-sys-color-on-surface-variant);margin-top:8px;letter-spacing:.04em}
20604
- .mode-card .tl{font-size:${TYPE.labelSmall.size}px;color:var(--md-sys-color-on-surface-variant);margin-top:6px;line-height:1.5}
20589
+ .mode-card .cnt{font-size:${TS.labelSmall}px;color:var(--md-sys-color-on-surface-variant);margin-top:8px;letter-spacing:.04em}
20590
+ .mode-card .tl{font-size:${TS.labelSmall}px;color:var(--md-sys-color-on-surface-variant);margin-top:6px;line-height:1.5}
20605
20591
 
20606
20592
  .attrs{display:flex;flex-wrap:wrap;gap:8px}
20607
20593
  /* 配色与 m3-chip 的默认档(secondary-container)一致,但尺寸更小:
@@ -20609,7 +20595,7 @@ tr.fresh .name::before{content:"";position:absolute;left:0;top:14px;bottom:14px;
20609
20595
  .attr{
20610
20596
  display:flex;align-items:center;gap:7px;padding:7px 14px;
20611
20597
  border-radius:var(--md-sys-shape-corner-full);
20612
- font-size:${TYPE.labelMedium.size}px;color:var(--md-sys-color-on-secondary-container);
20598
+ font-size:${TS.labelMedium}px;color:var(--md-sys-color-on-secondary-container);
20613
20599
  background:var(--md-sys-color-secondary-container);
20614
20600
  }
20615
20601
  .attr .px{color:var(--accent)}
@@ -20630,7 +20616,7 @@ tr.fresh .name::before{content:"";position:absolute;left:0;top:14px;bottom:14px;
20630
20616
  .reveal .big-thumb .fb{display:none;color:var(--md-sys-color-on-surface-variant)}
20631
20617
  .reveal .big-thumb.failed .fb{display:block}
20632
20618
  .reveal .cn{font-size:${TYPE.displaySmall.size}px;font-weight:${EMPHASIZED_WEIGHT.display};line-height:1.1}
20633
- .reveal .en{font-size:${TYPE.bodySmall.size}px;letter-spacing:.1em;color:var(--md-sys-color-on-surface-variant);margin-top:10px}
20619
+ .reveal .en{font-size:${TS.bodySmall}px;letter-spacing:.1em;color:var(--md-sys-color-on-surface-variant);margin-top:10px}
20634
20620
  .stats{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
20635
20621
  .stat{
20636
20622
  padding:13px 16px;
@@ -20638,7 +20624,7 @@ tr.fresh .name::before{content:"";position:absolute;left:0;top:14px;bottom:14px;
20638
20624
  background:var(--md-sys-color-surface-container);
20639
20625
  }
20640
20626
  .stat .n{font-family:${NUM_FONT};font-size:${TYPE.titleLarge.size}px;font-weight:${EMPHASIZED_WEIGHT.title};color:var(--accent);line-height:1;font-variant-numeric:tabular-nums}
20641
- .stat .c{font-size:${TYPE.labelSmall.size}px;color:var(--md-sys-color-on-surface-variant);margin-top:7px;letter-spacing:.06em}
20627
+ .stat .c{font-size:${TS.labelSmall}px;color:var(--md-sys-color-on-surface-variant);margin-top:7px;letter-spacing:.06em}
20642
20628
 
20643
20629
  /* ── 排行榜 ───────────────────────────────────────── */
20644
20630
  /* 列用 m3-list、行用 m3-list-item:圆角(首尾项放大到 extraLarge)、容器色与
@@ -20651,16 +20637,16 @@ tr.fresh .name::before{content:"";position:absolute;left:0;top:14px;bottom:14px;
20651
20637
  }
20652
20638
  .rk.p1{outline:2px solid ${MEDAL.gold}}
20653
20639
  .rk .who{flex:1;min-width:0}
20654
- .rk .nm{font-size:${TYPE.titleSmall.size}px;font-weight:${EMPHASIZED_WEIGHT.title};white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
20640
+ .rk .nm{font-size:${TS.titleSmall}px;font-weight:${EMPHASIZED_WEIGHT.title};white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
20655
20641
  max-width:260px}
20656
20642
  .rk .split{display:flex;gap:10px;margin-top:6px}
20657
- .rk .sp{display:flex;align-items:center;gap:4px;font-size:${TYPE.labelSmall.size}px;font-family:${NUM_FONT};color:var(--md-sys-color-on-surface-variant)}
20643
+ .rk .sp{display:flex;align-items:center;gap:4px;font-size:${TS.labelSmall}px;font-family:${NUM_FONT};color:var(--md-sys-color-on-surface-variant)}
20658
20644
  .rk .tot{flex:none;text-align:right}
20659
20645
  .rk .tot .n{font-family:${NUM_FONT};font-size:${TYPE.titleLarge.size}px;font-weight:${EMPHASIZED_WEIGHT.title};color:var(--accent);line-height:1;font-variant-numeric:tabular-nums}
20660
- .rk .tot .c{font-size:${TYPE.labelSmall.size}px;color:var(--md-sys-color-on-surface-variant);margin-top:5px;letter-spacing:.06em}
20646
+ .rk .tot .c{font-size:${TS.labelSmall}px;color:var(--md-sys-color-on-surface-variant);margin-top:5px;letter-spacing:.06em}
20661
20647
 
20662
20648
  .empty{padding:36px 20px;min-width:400px;text-align:center;
20663
- color:var(--md-sys-color-on-surface-variant);font-size:${TYPE.bodyMedium.size}px;line-height:2}
20649
+ color:var(--md-sys-color-on-surface-variant);font-size:${TS.bodyMedium}px;line-height:2}
20664
20650
  .empty .px{margin:0 auto 14px;color:var(--md-sys-color-on-surface-variant)}
20665
20651
  `;
20666
20652
  function shell(body, opts) {
@@ -20704,7 +20690,7 @@ function legendRow(tip) {
20704
20690
  }
20705
20691
  __name(legendRow, "legendRow");
20706
20692
  function noteRow(note) {
20707
- return `<footer class="legend"><div class="tip" style="margin:0">${esc(note)}</div></footer>`;
20693
+ return `<footer class="legend" style="justify-content:center"><div class="tip" style="margin:0;text-align:center">${esc(note)}</div></footer>`;
20708
20694
  }
20709
20695
  __name(noteRow, "noteRow");
20710
20696
  function tileCell(guess, key) {
@@ -20719,15 +20705,24 @@ function tileCell(guess, key) {
20719
20705
  return `<td><div class="tile ${m.cls}${isList ? " list" : ""}"><span class="flag">${px(m.icon, 11)}</span>${body}</div></td>`;
20720
20706
  }
20721
20707
  __name(tileCell, "tileCell");
20708
+ function isListField(key, sample) {
20709
+ return Array.isArray(sample?.[key]);
20710
+ }
20711
+ __name(isListField, "isListField");
20722
20712
  function boardCard(opts) {
20723
20713
  const { mode, guesses } = opts;
20724
20714
  const meta = MODES[mode];
20725
20715
  const fields = FIELDS[mode];
20726
20716
  const last = guesses[guesses.length - 1];
20727
- const cards = guesses.map((g, i) => `<article class="guess-card">
20728
- <h2 class="m3-title-large">${i + 1}. ${esc(g.chinese_title)} <span class="m3-body-medium">${esc(g.title || "")}</span></h2>
20729
- <div class="guess-fields">${fields.map((key) => `<table><thead><tr><th>${esc(fieldLabel(key))}</th></tr></thead><tbody><tr>${tileCell(g, key)}</tr></tbody></table>`).join("")}</div>
20730
- </article>`).join("");
20717
+ const head = `<tr><th class="n"><div class="col"><span class="lb">${guesses.length} 次猜测</span></div></th>` + fields.map(
20718
+ (k) => `<th${isListField(k, last) ? ' class="list"' : ""}><div class="col">${px(fieldIcon(k), 15)}<span class="lb">${esc(fieldLabel(k))}</span></div></th>`
20719
+ ).join("") + "</tr>";
20720
+ const rows = guesses.map((g, i) => {
20721
+ const fresh = i === guesses.length - 1 ? ' class="fresh"' : "";
20722
+ const solved = fields.every((k) => statusOf(g, k) === "true") && g.chinese_title_gui === "true";
20723
+ const name2 = `<td><div class="name${solved ? " correct" : ""}">${thumb(g.wiki_image_url, mode)}<div class="txt"><div class="cn">${esc(g.chinese_title)}${solved ? " " + px("crown", 13) : ""}</div><div class="en">${esc(g.title || "")}</div><div class="no">#${String(i + 1).padStart(2, "0")}</div></div></div></td>`;
20724
+ return `<tr${fresh}>${name2}${fields.map((k) => tileCell(g, k)).join("")}</tr>`;
20725
+ }).join("");
20731
20726
  const locked = fields.filter((k) => statusOf(last, k) === "true").length;
20732
20727
  const pct = Math.round(locked / fields.length * 100);
20733
20728
  const prog = `<div class="prog"><div class="num">已锁定 ${locked}/${fields.length}</div>
@@ -20736,7 +20731,7 @@ function boardCard(opts) {
20736
20731
  const body = header(mode, `${meta.name}模式 · ${meta.tagline}`, {
20737
20732
  big: `#${guesses.length}`,
20738
20733
  cap: "猜测次数"
20739
- }) + `<style>.board-compact{width:640px;max-width:100%}.guess-card{padding:16px;border-radius:24px;background:var(--md-sys-color-surface-container-low);margin-bottom:16px}.guess-card h2{overflow-wrap:anywhere}.guess-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.guess-fields table{width:100%;table-layout:fixed}.guess-fields .tile{width:100%;max-width:none;min-width:0}.guess-fields td,.guess-fields th{white-space:normal;overflow-wrap:anywhere}</style><div class="pad board-compact">${cards}${prog}</div>` + legendRow(opts.tip || "箭头指向答案所在的方向");
20734
+ }) + `<div class="pad"><table>${head}${rows}</table>${prog}</div>` + legendRow(opts.tip || "箭头指向答案所在的方向");
20740
20735
  return shell(body, { accent: meta.accent });
20741
20736
  }
20742
20737
  __name(boardCard, "boardCard");
@@ -20881,7 +20876,7 @@ var RANK_BADGE = ["m3-badge--gold", "m3-badge--silver", "m3-badge--bronze"];
20881
20876
  function rankCard(entries, shown) {
20882
20877
  if (!entries.length) {
20883
20878
  const body2 = header(null, "排行榜", { big: "0", cap: "上榜人数" }) + `<div class="pad"><div class="empty">${px("trophy", 44)}
20884
- 排行榜还空着<br>第一个猜中的人,名字会写在这里。<br><span style="font-size:${TYPE.bodySmall.size}px">用 <span class="cmd">mcdle.猜 苦力怕</span> 开出第一局,成为榜首</span></div></div>`;
20879
+ 排行榜还空着<br>第一个猜中的人,名字会写在这里。<br><span style="font-size:${TS.bodySmall}px">用 <span class="cmd">mcdle.猜 苦力怕</span> 开出第一局,成为榜首</span></div></div>`;
20885
20880
  return shell(body2, { accent: accentOf(90), width: 560 });
20886
20881
  }
20887
20882
  const max = Math.max(...entries.map((e) => e.total), 1);
@@ -20909,17 +20904,17 @@ __name(rankCard, "rankCard");
20909
20904
  var name = "mcdle";
20910
20905
  var usage = `## 使用
20911
20906
 
20912
- 发送 \`mcdle\` 查看玩法与全部指令。\`mcdle.猜 [名称]\` 用有效词条开局或猜测。首次猜测的词条决定生物、物品或方块模式,系统再从同类词库中抽取答案。
20907
+ 发送 \`mcdle\` 查看玩法与全部指令。\`mcdle.猜 [名称]\` 开局或提交猜测。首次猜测的词条决定题目类型。
20913
20908
 
20914
20909
  ## 指令
20915
20910
 
20916
20911
  | 指令 | 说明 |
20917
20912
  | --- | --- |
20918
- | \`mcdle\` | 玩法与指令说明 |
20919
- | \`mcdle.猜 [名称]\` | 用有效词条开局或猜测 |
20920
- | \`mcdle.裸猜 [开/关]\` | 开关本频道的无前缀续猜 |
20921
- | \`mcdle.排行榜\` | 累计战绩 |
20922
- | \`mcdle.词库\` | 全部词条 |
20913
+ | \`mcdle\` | 查看玩法与指令 |
20914
+ | \`mcdle.猜 [名称]\` | 开局或提交猜测 |
20915
+ | \`mcdle.裸猜 [开/关]\` | 切换本频道无前缀续猜 |
20916
+ | \`mcdle.排行榜\` | 查看本群战绩 |
20917
+ | \`mcdle.词库\` | 查看全部词条 |
20923
20918
 
20924
20919
  ## 提示
20925
20920
 
@@ -21012,7 +21007,6 @@ function resolveMiddlewareSwitch(config, override, action) {
21012
21007
  }
21013
21008
  __name(resolveMiddlewareSwitch, "resolveMiddlewareSwitch");
21014
21009
  function apply(ctx, cfg) {
21015
- const presentation = usePresentation(ctx, "mcdle");
21016
21010
  ctx.model.extend(
21017
21011
  "mcdle",
21018
21012
  {
@@ -21228,8 +21222,8 @@ function apply(ctx, cfg) {
21228
21222
  }
21229
21223
  __name(renderCard, "renderCard");
21230
21224
  async function sendCard(session, html, fallback) {
21231
- const image = presentation.textOnly(session) ? null : await renderCard(html);
21232
- await sendMsg(session, import_koishi2.h.normalize(presentation.present(session, image, fallback)).join(""));
21225
+ const image = await renderCard(html);
21226
+ await sendMsg(session, import_koishi2.h.normalize(present(image, fallback)).join(""));
21233
21227
  }
21234
21228
  __name(sendCard, "sendCard");
21235
21229
  async function mcdle(session) {
@@ -21827,7 +21821,7 @@ ${words.join(" ")}`).join("\n\n")
21827
21821
  msg = `${import_koishi2.h.quote(session.messageId)}${msg}`;
21828
21822
  }
21829
21823
  const [messageId] = await session.send(msg);
21830
- if (!presentation.textOnly(session) && cfg.retractDelay > 0 && messageId) {
21824
+ if (cfg.retractDelay > 0 && messageId) {
21831
21825
  const prevMessage = lastMessageInfo.get(session.channelId);
21832
21826
  if (prevMessage) {
21833
21827
  const timePassed = Date.now() - prevMessage.timestamp;
package/lib/ux.d.ts CHANGED
@@ -3,29 +3,11 @@ type Owner = {
3
3
  name: string;
4
4
  matches: (session: Session) => boolean | Promise<boolean>;
5
5
  };
6
- /** 图文模式默认只发渲染图;完整文字只在用户切到「文字」模式时出现。偏好只影响本人。 */
7
- export declare function usePresentation(ctx: Context, command: string): {
8
- textOnly: (session: Session) => boolean;
9
- /** 图文模式只给图片;图片缺失或用户选了文字模式时才退回文字。 */
10
- present(session: Session, image: h.Fragment | null | undefined, text: h.Fragment): h.Fragment;
11
- };
6
+ /** 渲染图优先,只发图片;图片缺失时才退回等价文字。 */
7
+ export declare function present(image: h.Fragment | null | undefined, text: h.Fragment): h.Fragment;
12
8
  /** Plugins register their active input grammar; overlapping messages are never executed. */
13
9
  export declare function registerDirectInput(ctx: Context, name: string, matches: Owner['matches']): void;
14
10
  export declare function directInputConflict(ctx: Context, session: Session): Promise<boolean>;
15
- /** No hidden time limit: users can extend the non-game input step without losing context. */
16
- export declare function promptInput(session: Session, instruction: string): Promise<string | undefined>;
17
- export declare const IMAGE_FAILURE = "\u56FE\u7247\u6682\u65F6\u65E0\u6CD5\u751F\u6210\uFF0C\u5DF2\u4FDD\u7559\u6587\u5B57\u5185\u5BB9\u3002\u53EF\u4EE5\u7A0D\u540E\u91CD\u8BD5\uFF1B\u82E5\u6301\u7EED\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u3002";
18
- /**
19
- * 渲染图的等价文字。图文模式随图片一起丢掉、文字模式展开成正文,
20
- * 因此它永远不会原样发到聊天平台。
21
- */
22
- export declare const IMAGE_TEXT_TYPE = "ux-image-text";
23
- export declare function imageText(text: h.Fragment): h;
24
- /** 图文模式:保留图片与普通文字,去掉图片的等价文字。 */
25
- export declare function imagesOnly(content: h.Fragment): h[];
26
- /** 文字模式:去掉图片,把等价文字展开成普通文本。 */
27
- export declare function withoutImages(content: h.Fragment): h[];
28
- /** 发送前的统一选择:文字模式去掉图片,图文模式去掉等价文字。 */
29
- export declare function choosePresentation(content: h.Fragment, textOnly: boolean): h[];
30
- export declare function isTextOnly(ctx: Context, session: Session): boolean;
11
+ /** 等待下一句回复。提问本身已经写明了可回复的内容与「取消」,这里不再追加说明。 */
12
+ export declare function promptInput(session: Session): Promise<string | undefined>;
31
13
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-mcdle",
3
- "description": "Koishi《我的世界》猜谜:覆盖生物、物品和方块,支持群内记录与排行。",
4
- "version": "0.6.1",
3
+ "description": "Koishi 插件:玩《我的世界》猜谜,凭属性提示从生物、物品、方块中锁定唯一答案。",
4
+ "version": "0.7.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [