koishi-plugin-mcdle 0.1.4 → 0.1.5
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/lib/index.d.ts +23 -3
- package/lib/index.js +209 -83
- package/lib/view.d.ts +3 -3
- package/package.json +6 -2
- package/readme.md +3 -2
package/lib/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Context, Schema } from 'koishi';
|
|
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`mcdle.\u731C [\u540D\u79F0]` \u5F00\u5C40\u6216\u731C\u6D4B\u3002\
|
|
4
|
+
export declare const usage = "## \u4F7F\u7528\n\n`mcdle.\u731C [\u540D\u79F0]` \u4F7F\u7528\u8BCD\u5E93\u4E2D\u7684\u6709\u6548\u540D\u79F0\u5F00\u5C40\u6216\u731C\u6D4B\u3002\u9996\u4E2A\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## \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 |\n\n## \u6307\u4EE4\n\n| \u6307\u4EE4 | \u8BF4\u660E |\n| --- | --- |\n| `mcdle` | \u67E5\u770B\u5E2E\u52A9 |\n| `mcdle.\u731C [\u540D\u79F0]` | \u7528\u6709\u6548\u8BCD\u6761\u5F00\u5C40\u6216\u731C\u6D4B |\n| `mcdle.\u88F8\u731C [\u5F00/\u5173]` | \u4E34\u65F6\u5207\u6362\u672C\u7FA4\u65E0\u524D\u7F00\u7EED\u731C |\n| `mcdle.\u5E2E\u52A9` | \u5B8C\u6574\u8BF4\u660E |\n| `mcdle.\u6392\u884C\u699C` | \u7FA4\u5185\u6218\u7EE9 |\n| `mcdle.\u8BCD\u5E93` | \u5168\u90E8\u8BCD\u6761 |";
|
|
5
5
|
export declare const inject: {
|
|
6
6
|
required: string[];
|
|
7
7
|
optional: string[];
|
|
@@ -24,7 +24,7 @@ declare module "koishi" {
|
|
|
24
24
|
mcdle_rank: McdleRank;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
interface Mcdle {
|
|
27
|
+
export interface Mcdle {
|
|
28
28
|
id: number;
|
|
29
29
|
channelId: string;
|
|
30
30
|
answer: MobData | ItemData | BlockData | null;
|
|
@@ -46,5 +46,25 @@ interface McdleRank {
|
|
|
46
46
|
blockSuccessCount: number;
|
|
47
47
|
totalSuccessCount: number;
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* 裸猜只接受一条完整、无修饰、且与 MCDLE 词库精确匹配的纯文本消息。
|
|
51
|
+
* 引用、@、图片、富文本及机器人消息都可能只是普通聊天的一部分,不能据此猜测。
|
|
52
|
+
*/
|
|
53
|
+
export declare function getMiddlewareGuess(session: Session): string | null;
|
|
54
|
+
/** 裸猜只能加入当前模式下已开始的有效局面,绝不能代替完整指令开新局。 */
|
|
55
|
+
export declare function canHandleMiddlewareGuess(game: Mcdle | null | undefined, guess: string, allowRepeatedGuesses?: boolean): boolean;
|
|
56
|
+
export type MiddlewareSwitch = {
|
|
57
|
+
error: string;
|
|
58
|
+
} | {
|
|
59
|
+
/** 写回本群覆盖表的新值;undefined 表示清除覆盖,重新跟随插件配置。 */
|
|
60
|
+
override: boolean | undefined;
|
|
61
|
+
on: boolean;
|
|
62
|
+
reverted: boolean;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* 无参调用在「配置默认」与「本群临时相反」间往返;显式开/关若与配置相同,
|
|
66
|
+
* 就清除冗余覆盖。临时状态只保存在内存中,插件重载后自然回到配置默认。
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveMiddlewareSwitch(config: boolean, override: boolean | undefined, action: string | null | undefined): MiddlewareSwitch;
|
|
49
69
|
export declare function apply(ctx: Context, cfg: Config): void;
|
|
50
70
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -22,8 +22,11 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
Config: () => Config,
|
|
24
24
|
apply: () => apply,
|
|
25
|
+
canHandleMiddlewareGuess: () => canHandleMiddlewareGuess,
|
|
26
|
+
getMiddlewareGuess: () => getMiddlewareGuess,
|
|
25
27
|
inject: () => inject,
|
|
26
28
|
name: () => name,
|
|
29
|
+
resolveMiddlewareSwitch: () => resolveMiddlewareSwitch,
|
|
27
30
|
usage: () => usage
|
|
28
31
|
});
|
|
29
32
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -15395,7 +15398,7 @@ function boardCard(opts) {
|
|
|
15395
15398
|
return shell(body, { accent: meta.accent });
|
|
15396
15399
|
}
|
|
15397
15400
|
__name(boardCard, "boardCard");
|
|
15398
|
-
function startCard(mode, played, limit) {
|
|
15401
|
+
function startCard(mode, played, limit, middleware) {
|
|
15399
15402
|
const meta = MODES[mode];
|
|
15400
15403
|
const fields = FIELDS[mode];
|
|
15401
15404
|
const attrs = fields.map((k) => `<div class="attr">${px(fieldIcon(k), 13)}<span>${esc(keyMap[k] || k)}</span></div>`).join("");
|
|
@@ -15415,7 +15418,7 @@ function startCard(mode, played, limit) {
|
|
|
15415
15418
|
<div class="sec">
|
|
15416
15419
|
<div class="sec-t"><span>下 一 步</span></div>
|
|
15417
15420
|
<div class="panel"><div class="rows">
|
|
15418
|
-
<div class="row"><span class="cmd"
|
|
15421
|
+
<div class="row"><span class="cmd">${middleware ? `直接发送${esc(meta.name)}名称` : "mcdle.猜 [名称]"}</span><span class="m">提交后续猜测</span></div>
|
|
15419
15422
|
<div class="row"><span class="cmd">mcdle.词库</span><span class="m">忘了有哪些词条时翻一翻</span></div>
|
|
15420
15423
|
</div></div>
|
|
15421
15424
|
</div>
|
|
@@ -15466,7 +15469,7 @@ function winCard(o) {
|
|
|
15466
15469
|
return shell(body, { accent: meta.accent, width: 720 });
|
|
15467
15470
|
}
|
|
15468
15471
|
__name(winCard, "winCard");
|
|
15469
|
-
function helpCard(dailyLimit, allowRepeat) {
|
|
15472
|
+
function helpCard(dailyLimit, allowRepeat, middleware) {
|
|
15470
15473
|
const modeCards = ["mob", "item", "block"].map((m) => {
|
|
15471
15474
|
const meta = MODES[m];
|
|
15472
15475
|
return `<div class="mode-card" style="--accent:${meta.accent}">
|
|
@@ -15496,6 +15499,7 @@ function helpCard(dailyLimit, allowRepeat) {
|
|
|
15496
15499
|
<div class="panel"><div class="rows">
|
|
15497
15500
|
<div class="row"><span class="cmd">mcdle.猜 [名称]</span><span class="m">开始一局,或提交猜测</span></div>
|
|
15498
15501
|
<div class="row"><span class="cmd">mcdle.猜</span><span class="m">局中直接使用可回看当前棋盘</span></div>
|
|
15502
|
+
<div class="row"><span class="cmd">mcdle.裸猜 [开/关]</span><span class="m">临时切换本群无前缀续猜</span></div>
|
|
15499
15503
|
<div class="row"><span class="cmd">mcdle.排行榜</span><span class="m">查看群内战绩</span></div>
|
|
15500
15504
|
<div class="row"><span class="cmd">mcdle.词库</span><span class="m">查阅全部候选词条</span></div>
|
|
15501
15505
|
</div></div>
|
|
@@ -15505,6 +15509,8 @@ function helpCard(dailyLimit, allowRepeat) {
|
|
|
15505
15509
|
<div class="panel"><div class="rows">
|
|
15506
15510
|
<div class="row"><span class="k">·</span><span>每个群每日可开始 <b>${dailyLimit}</b> 局,跨零点重置。</span></div>
|
|
15507
15511
|
<div class="row"><span class="k">·</span><span>${allowRepeat ? "允许重复提交已经猜过的词条。" : "同一局内不能重复提交已猜过的词条。"}</span></div>
|
|
15512
|
+
<div class="row"><span class="k">·</span><span>${middleware ? "本群裸猜已开启:只接受当前模式词库中的完整纯文本词条。" : "本群裸猜已停用:续猜请使用完整指令。"}</span></div>
|
|
15513
|
+
<div class="row"><span class="k">·</span><span>空指令与词库外名称不会开启新局或消耗额度。</span></div>
|
|
15508
15514
|
<div class="row"><span class="k">·</span><span>词条与数据来自 Minecraft Wiki,版本号按发布先后比较。</span></div>
|
|
15509
15515
|
</div></div>
|
|
15510
15516
|
</div>
|
|
@@ -15512,7 +15518,7 @@ function helpCard(dailyLimit, allowRepeat) {
|
|
|
15512
15518
|
return shell(body, { accent: "#8ec96a", width: 760 });
|
|
15513
15519
|
}
|
|
15514
15520
|
__name(helpCard, "helpCard");
|
|
15515
|
-
function introCard(dailyLimit) {
|
|
15521
|
+
function introCard(dailyLimit, middleware) {
|
|
15516
15522
|
const modeCards = ["mob", "item", "block"].map((m) => {
|
|
15517
15523
|
const meta = MODES[m];
|
|
15518
15524
|
return `<div class="mode-card" style="--accent:${meta.accent}">
|
|
@@ -15528,8 +15534,8 @@ function introCard(dailyLimit) {
|
|
|
15528
15534
|
<div class="sec">
|
|
15529
15535
|
<div class="sec-t"><span>三 步 上 手</span></div>
|
|
15530
15536
|
<div class="panel"><div class="rows">
|
|
15531
|
-
<div class="row"><span class="k">壹</span><span class="cmd">mcdle.猜 苦力怕</span><span class="m"
|
|
15532
|
-
<div class="row"><span class="k">贰</span><span
|
|
15537
|
+
<div class="row"><span class="k">壹</span><span class="cmd">mcdle.猜 苦力怕</span><span class="m">用一个有效词条开局</span></div>
|
|
15538
|
+
<div class="row"><span class="k">贰</span><span>${middleware ? "开局后可直接发送当前模式的完整词条名称继续猜测。" : "对照颜色与箭头缩小范围,每一次猜测都会留在棋盘上。"}</span></div>
|
|
15533
15539
|
<div class="row"><span class="k">叁</span><span>锁定答案,战绩自动记入 <span class="cmd">mcdle.排行榜</span>。</span></div>
|
|
15534
15540
|
</div></div>
|
|
15535
15541
|
</div>
|
|
@@ -15537,6 +15543,7 @@ function introCard(dailyLimit) {
|
|
|
15537
15543
|
<div class="sec-t"><span>今 日 额 度</span></div>
|
|
15538
15544
|
<div class="panel"><div class="rows">
|
|
15539
15545
|
<div class="row"><span class="k">·</span><span>每个群每日 <b>${dailyLimit}</b> 局,跨零点重置;详细规则见 <span class="cmd">mcdle.帮助</span>。</span></div>
|
|
15546
|
+
<div class="row"><span class="k">·</span><span><span class="cmd">mcdle.裸猜 开/关</span> 可临时调整本群续猜方式。</span></div>
|
|
15540
15547
|
</div></div>
|
|
15541
15548
|
</div>
|
|
15542
15549
|
</div>` + noteRow("灵感来自 Wordle 与 mcdle.net");
|
|
@@ -15546,7 +15553,7 @@ __name(introCard, "introCard");
|
|
|
15546
15553
|
function rankCard(entries, shown) {
|
|
15547
15554
|
if (!entries.length) {
|
|
15548
15555
|
const body2 = header(null, "排行榜", { big: "0", cap: "上榜人数" }) + `<div class="pad"><div class="empty">${px("trophy", 44)}
|
|
15549
|
-
榜单还空着<br><span style="font-size:12px">用 <span class="cmd">mcdle
|
|
15556
|
+
榜单还空着<br><span style="font-size:12px">用 <span class="cmd">mcdle.猜 苦力怕</span> 开出第一局,成为榜首</span></div></div>`;
|
|
15550
15557
|
return shell(body2, { accent: "#e8b53c", width: 560 });
|
|
15551
15558
|
}
|
|
15552
15559
|
const max = Math.max(...entries.map((e) => e.total), 1);
|
|
@@ -15574,7 +15581,7 @@ __name(rankCard, "rankCard");
|
|
|
15574
15581
|
var name = "mcdle";
|
|
15575
15582
|
var usage = `## 使用
|
|
15576
15583
|
|
|
15577
|
-
\`mcdle.猜 [名称]\`
|
|
15584
|
+
\`mcdle.猜 [名称]\` 使用词库中的有效名称开局或猜测。首个词条决定生物、物品或方块模式,系统再从同类词库中抽取答案。
|
|
15578
15585
|
|
|
15579
15586
|
## 提示
|
|
15580
15587
|
|
|
@@ -15590,15 +15597,16 @@ var usage = `## 使用
|
|
|
15590
15597
|
| 指令 | 说明 |
|
|
15591
15598
|
| --- | --- |
|
|
15592
15599
|
| \`mcdle\` | 查看帮助 |
|
|
15593
|
-
| \`mcdle.猜 [名称]\` |
|
|
15600
|
+
| \`mcdle.猜 [名称]\` | 用有效词条开局或猜测 |
|
|
15601
|
+
| \`mcdle.裸猜 [开/关]\` | 临时切换本群无前缀续猜 |
|
|
15594
15602
|
| \`mcdle.帮助\` | 完整说明 |
|
|
15595
15603
|
| \`mcdle.排行榜\` | 群内战绩 |
|
|
15596
15604
|
| \`mcdle.词库\` | 全部词条 |`;
|
|
15597
15605
|
var inject = { required: ["database"], optional: ["puppeteer"] };
|
|
15598
15606
|
var Config = import_koishi.Schema.object({
|
|
15599
15607
|
atReply: import_koishi.Schema.boolean().default(false).description("响应时@用户"),
|
|
15600
|
-
quoteReply: import_koishi.Schema.boolean().default(
|
|
15601
|
-
isEnableMiddleware: import_koishi.Schema.boolean().default(false).description("
|
|
15608
|
+
quoteReply: import_koishi.Schema.boolean().default(false).description("响应时引用消息"),
|
|
15609
|
+
isEnableMiddleware: import_koishi.Schema.boolean().default(false).description("是否默认启用无前缀续猜(仅在游戏进行中生效;mcdle.裸猜 可在单个群内临时切换)"),
|
|
15602
15610
|
addStatusTextAfterEmoji: import_koishi.Schema.boolean().default(true).description("在状态表情后添加文字说明"),
|
|
15603
15611
|
maxRank: import_koishi.Schema.number().default(10).min(0).description("排行榜最大显示人数"),
|
|
15604
15612
|
dailyPlayLimit: import_koishi.Schema.number().default(1).min(1).description("每日游玩次数上限"),
|
|
@@ -15626,6 +15634,56 @@ var guessesField = {
|
|
|
15626
15634
|
}
|
|
15627
15635
|
}
|
|
15628
15636
|
};
|
|
15637
|
+
var DATA_BY_MODE = {
|
|
15638
|
+
mob: mobData,
|
|
15639
|
+
item: itemData,
|
|
15640
|
+
block: blockData
|
|
15641
|
+
};
|
|
15642
|
+
var allChineseTitles = new Set(
|
|
15643
|
+
Object.values(DATA_BY_MODE).flatMap(
|
|
15644
|
+
(entries) => entries.map((entry) => entry.chinese_title)
|
|
15645
|
+
)
|
|
15646
|
+
);
|
|
15647
|
+
function getMiddlewareGuess(session) {
|
|
15648
|
+
const message = session.event.message;
|
|
15649
|
+
if (!message || message.quote || session.event.user?.isBot || message.user?.isBot) {
|
|
15650
|
+
return null;
|
|
15651
|
+
}
|
|
15652
|
+
const elements = message.elements ?? [];
|
|
15653
|
+
if (elements.length !== 1 || elements[0].type !== "text") return null;
|
|
15654
|
+
const text = elements[0].attrs.content;
|
|
15655
|
+
if (typeof text !== "string" || text !== text.trim() || !text || !allChineseTitles.has(text)) {
|
|
15656
|
+
return null;
|
|
15657
|
+
}
|
|
15658
|
+
return text;
|
|
15659
|
+
}
|
|
15660
|
+
__name(getMiddlewareGuess, "getMiddlewareGuess");
|
|
15661
|
+
function canHandleMiddlewareGuess(game, guess, allowRepeatedGuesses = false) {
|
|
15662
|
+
if (!game || game.gameEnded || !game.answer) return false;
|
|
15663
|
+
const mode = game.gameMode;
|
|
15664
|
+
if (!mode || !DATA_BY_MODE[mode]) return false;
|
|
15665
|
+
if (!allowRepeatedGuesses && game.guessedChineseTitles?.includes(guess)) return false;
|
|
15666
|
+
return DATA_BY_MODE[mode].some((entry) => entry.chinese_title === guess);
|
|
15667
|
+
}
|
|
15668
|
+
__name(canHandleMiddlewareGuess, "canHandleMiddlewareGuess");
|
|
15669
|
+
function resolveMiddlewareSwitch(config, override, action) {
|
|
15670
|
+
const arg = action?.trim();
|
|
15671
|
+
if (!arg) {
|
|
15672
|
+
return override === void 0 ? { override: !config, on: !config, reverted: false } : { override: void 0, on: config, reverted: true };
|
|
15673
|
+
}
|
|
15674
|
+
if (arg === "状态") {
|
|
15675
|
+
return { override, on: override ?? config, reverted: false };
|
|
15676
|
+
}
|
|
15677
|
+
const on = arg === "开" || arg === "开启";
|
|
15678
|
+
if (!on && arg !== "关" && arg !== "关闭") {
|
|
15679
|
+
return { error: "裸猜开关只认 开 / 关 / 状态" };
|
|
15680
|
+
}
|
|
15681
|
+
if (on === config) {
|
|
15682
|
+
return { override: void 0, on: config, reverted: override !== void 0 };
|
|
15683
|
+
}
|
|
15684
|
+
return { override: on, on, reverted: false };
|
|
15685
|
+
}
|
|
15686
|
+
__name(resolveMiddlewareSwitch, "resolveMiddlewareSwitch");
|
|
15629
15687
|
function apply(ctx, cfg) {
|
|
15630
15688
|
ctx.model.extend(
|
|
15631
15689
|
"mcdle",
|
|
@@ -15661,41 +15719,49 @@ function apply(ctx, cfg) {
|
|
|
15661
15719
|
}
|
|
15662
15720
|
);
|
|
15663
15721
|
const logger = ctx.logger("mcdle");
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
|
|
15673
|
-
|
|
15674
|
-
|
|
15675
|
-
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
let dataSource = [];
|
|
15680
|
-
if (game.gameMode === "mob") dataSource = mobData;
|
|
15681
|
-
else if (game.gameMode === "item") dataSource = itemData;
|
|
15682
|
-
else if (game.gameMode === "block") dataSource = blockData;
|
|
15683
|
-
else return next();
|
|
15684
|
-
const matched = dataSource.find(
|
|
15685
|
-
(d) => d.chinese_title === content
|
|
15722
|
+
const middlewareOverrides = /* @__PURE__ */ new Map();
|
|
15723
|
+
const middlewareOn = /* @__PURE__ */ __name((channelId) => channelId === void 0 ? cfg.isEnableMiddleware : middlewareOverrides.get(channelId) ?? cfg.isEnableMiddleware, "middlewareOn");
|
|
15724
|
+
ctx.middleware(async (session, next) => {
|
|
15725
|
+
if (!session.channelId || !middlewareOn(session.channelId)) return await next();
|
|
15726
|
+
const guess = getMiddlewareGuess(session);
|
|
15727
|
+
if (!guess) return await next();
|
|
15728
|
+
try {
|
|
15729
|
+
const [game] = await ctx.database.get("mcdle", { channelId: session.channelId });
|
|
15730
|
+
if (!canHandleMiddlewareGuess(game, guess, cfg.allowRepeatedGuesses)) return await next();
|
|
15731
|
+
const handled = await c(session, guess, false);
|
|
15732
|
+
return handled ? void 0 : await next();
|
|
15733
|
+
} catch (error) {
|
|
15734
|
+
logger.warn(
|
|
15735
|
+
"中间件读取或处理游戏状态失败,本次消息不作猜测:%s",
|
|
15736
|
+
error instanceof Error ? error.message : String(error)
|
|
15686
15737
|
);
|
|
15687
|
-
|
|
15688
|
-
|
|
15689
|
-
|
|
15690
|
-
await session.execute(`mcdle.猜 ${content}`);
|
|
15691
|
-
return;
|
|
15692
|
-
});
|
|
15693
|
-
}
|
|
15738
|
+
return await next();
|
|
15739
|
+
}
|
|
15740
|
+
});
|
|
15694
15741
|
ctx.command("mcdle", "我的世界猜谜游戏").action(async ({ session }) => mcdle(session));
|
|
15695
|
-
ctx.command("mcdle.猜 [guess:string]").action(async ({ session }, guess) =>
|
|
15742
|
+
ctx.command("mcdle.猜 [guess:string]").action(async ({ session }, guess) => {
|
|
15743
|
+
await c(session, guess?.trim());
|
|
15744
|
+
});
|
|
15696
15745
|
ctx.command("mcdle.帮助").action(async ({ session }) => bz(session));
|
|
15697
15746
|
ctx.command("mcdle.排行榜").action(async ({ session }) => phb(session));
|
|
15698
15747
|
ctx.command("mcdle.词库").action(async ({ session }) => ck(session));
|
|
15748
|
+
ctx.command("mcdle.裸猜 [state:string]", "临时开关本群的无前缀续猜").usage("例:mcdle.裸猜(切换)· mcdle.裸猜 开 · mcdle.裸猜 关 · mcdle.裸猜 状态").action(async ({ session }, state) => {
|
|
15749
|
+
const result = resolveMiddlewareSwitch(
|
|
15750
|
+
cfg.isEnableMiddleware,
|
|
15751
|
+
session.channelId === void 0 ? void 0 : middlewareOverrides.get(session.channelId),
|
|
15752
|
+
state
|
|
15753
|
+
);
|
|
15754
|
+
if ("error" in result) {
|
|
15755
|
+
await sendMsg(session, `⚠️ ${result.error}。例:mcdle.裸猜 开`);
|
|
15756
|
+
return;
|
|
15757
|
+
}
|
|
15758
|
+
if (result.override === void 0) middlewareOverrides.delete(session.channelId);
|
|
15759
|
+
else middlewareOverrides.set(session.channelId, result.override);
|
|
15760
|
+
await sendMsg(
|
|
15761
|
+
session,
|
|
15762
|
+
middlewareSwitchText(result.on, result.override !== void 0, result.reverted)
|
|
15763
|
+
);
|
|
15764
|
+
});
|
|
15699
15765
|
const RULE = "────────────";
|
|
15700
15766
|
function textCard(title, ...sections) {
|
|
15701
15767
|
const body = sections.map((s) => Array.isArray(s) ? s.filter(Boolean).join("\n") : s).filter((s) => !!s && !!s.trim()).join("\n\n");
|
|
@@ -15755,13 +15821,16 @@ function apply(ctx, cfg) {
|
|
|
15755
15821
|
);
|
|
15756
15822
|
}
|
|
15757
15823
|
__name(boardText, "boardText");
|
|
15758
|
-
function startText(mode, played) {
|
|
15824
|
+
function startText(mode, played, channelOn) {
|
|
15759
15825
|
const meta = MODES[mode];
|
|
15760
15826
|
return textCard(
|
|
15761
15827
|
`新的一局 · ${meta.name}模式`,
|
|
15762
15828
|
`${meta.tagline},从 ${meta.total} 个候选中锁定唯一答案。`,
|
|
15763
15829
|
`可推理属性:${FIELDS[mode].map((k) => keyMap[k] || k).join(" / ")}`,
|
|
15764
|
-
[
|
|
15830
|
+
[
|
|
15831
|
+
channelOn ? `直接发送词库中的${meta.name}名称,或使用 mcdle.猜 [名称]` : `mcdle.猜 [名称] 提交一次猜测`,
|
|
15832
|
+
`今日进度 ${played}/${cfg.dailyPlayLimit}`
|
|
15833
|
+
]
|
|
15765
15834
|
);
|
|
15766
15835
|
}
|
|
15767
15836
|
__name(startText, "startText");
|
|
@@ -15818,27 +15887,47 @@ function apply(ctx, cfg) {
|
|
|
15818
15887
|
}
|
|
15819
15888
|
__name(sendCard, "sendCard");
|
|
15820
15889
|
async function mcdle(session) {
|
|
15821
|
-
|
|
15890
|
+
const channelOn = middlewareOn(session.channelId);
|
|
15891
|
+
await sendCard(
|
|
15892
|
+
session,
|
|
15893
|
+
introCard(cfg.dailyPlayLimit, channelOn),
|
|
15894
|
+
introText(channelOn)
|
|
15895
|
+
);
|
|
15822
15896
|
}
|
|
15823
15897
|
__name(mcdle, "mcdle");
|
|
15824
|
-
function introText() {
|
|
15898
|
+
function introText(channelOn) {
|
|
15825
15899
|
const total = mobData.length + itemData.length + blockData.length;
|
|
15826
15900
|
return textCard(
|
|
15827
15901
|
"MCDLE · 我的世界猜谜",
|
|
15828
15902
|
`从 ${total} 个词条里,只凭属性提示锁定唯一答案。`,
|
|
15829
15903
|
[
|
|
15830
|
-
`壹 mcdle.猜 苦力怕
|
|
15831
|
-
`贰 对照颜色与箭头缩小范围,每次猜测都会留在棋盘上`,
|
|
15904
|
+
`壹 mcdle.猜 苦力怕 用一个有效词条开局`,
|
|
15905
|
+
channelOn ? `贰 开局后可直接发送当前模式的词条名称继续猜测` : `贰 对照颜色与箭头缩小范围,每次猜测都会留在棋盘上`,
|
|
15832
15906
|
`叁 猜中后自动记入 mcdle.排行榜`
|
|
15833
15907
|
],
|
|
15834
15908
|
[
|
|
15835
15909
|
`生物 ${mobData.length} · 物品 ${itemData.length} · 方块 ${blockData.length}`,
|
|
15836
15910
|
`每日 ${cfg.dailyPlayLimit} 局,跨零点重置`,
|
|
15911
|
+
`裸猜 mcdle.裸猜 开/关 临时调整本群续猜方式`,
|
|
15837
15912
|
`完整规则:mcdle.帮助`
|
|
15838
15913
|
]
|
|
15839
15914
|
);
|
|
15840
15915
|
}
|
|
15841
15916
|
__name(introText, "introText");
|
|
15917
|
+
function middlewareSwitchText(on, temporary, reverted) {
|
|
15918
|
+
const mark = on ? "✅" : "⛔";
|
|
15919
|
+
const state = on ? "开启" : "停用";
|
|
15920
|
+
const config = cfg.isEnableMiddleware ? "开启" : "停用";
|
|
15921
|
+
if (!temporary) {
|
|
15922
|
+
return `${mark} 裸猜续局 · ${reverted ? "已复原," : ""}跟随插件配置(${state})`;
|
|
15923
|
+
}
|
|
15924
|
+
const hint = on ? "仅在已有对局中,直接发送当前模式的完整词条名称才会响应" : "续猜请使用 mcdle.猜 [名称]";
|
|
15925
|
+
return [
|
|
15926
|
+
`${mark} 裸猜续局 · 本群临时${state}(插件配置:${config})`,
|
|
15927
|
+
`${hint};再次发送 mcdle.裸猜 可复原`
|
|
15928
|
+
].join("\n");
|
|
15929
|
+
}
|
|
15930
|
+
__name(middlewareSwitchText, "middlewareSwitchText");
|
|
15842
15931
|
async function ck(session) {
|
|
15843
15932
|
const sections = [
|
|
15844
15933
|
[`生物词库 · ${mobChineseTitle.length} 条`, mobChineseTitle],
|
|
@@ -15866,11 +15955,7 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
15866
15955
|
);
|
|
15867
15956
|
}
|
|
15868
15957
|
__name(ck, "ck");
|
|
15869
|
-
const POOLS =
|
|
15870
|
-
mob: mobData,
|
|
15871
|
-
item: itemData,
|
|
15872
|
-
block: blockData
|
|
15873
|
-
};
|
|
15958
|
+
const POOLS = DATA_BY_MODE;
|
|
15874
15959
|
function modeOf(entry) {
|
|
15875
15960
|
if (mobData.includes(entry)) return "mob";
|
|
15876
15961
|
if (itemData.includes(entry)) return "item";
|
|
@@ -15927,7 +16012,7 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
15927
16012
|
return candidates[Math.floor(Math.random() * candidates.length)];
|
|
15928
16013
|
}
|
|
15929
16014
|
__name(pickAnswer, "pickAnswer");
|
|
15930
|
-
async function c(session, guess) {
|
|
16015
|
+
async function c(session, guess, allowStart = true) {
|
|
15931
16016
|
const record = await ensureRecord(session);
|
|
15932
16017
|
const now = /* @__PURE__ */ new Date();
|
|
15933
16018
|
await resetDailyIfNeeded(session, record, now);
|
|
@@ -15943,12 +16028,12 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
15943
16028
|
record.guesses = restored;
|
|
15944
16029
|
record.formatVersion = FORMAT_VERSION;
|
|
15945
16030
|
} else {
|
|
15946
|
-
await rollbackLegacyGame(session, record, guess, now);
|
|
15947
|
-
return;
|
|
16031
|
+
await rollbackLegacyGame(session, record, guess, now, allowStart);
|
|
16032
|
+
return true;
|
|
15948
16033
|
}
|
|
15949
16034
|
} else if (record.guesses.length) {
|
|
15950
|
-
await rollbackLegacyGame(session, record, guess, now);
|
|
15951
|
-
return;
|
|
16035
|
+
await rollbackLegacyGame(session, record, guess, now, allowStart);
|
|
16036
|
+
return true;
|
|
15952
16037
|
} else {
|
|
15953
16038
|
await ctx.database.set(
|
|
15954
16039
|
"mcdle",
|
|
@@ -15959,10 +16044,12 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
15959
16044
|
}
|
|
15960
16045
|
}
|
|
15961
16046
|
if (record.gameEnded) {
|
|
16047
|
+
if (!allowStart) return false;
|
|
15962
16048
|
await startNewGame(session, record, guess, now);
|
|
15963
16049
|
} else {
|
|
15964
16050
|
await continueGame(session, record, guess);
|
|
15965
16051
|
}
|
|
16052
|
+
return true;
|
|
15966
16053
|
}
|
|
15967
16054
|
__name(c, "c");
|
|
15968
16055
|
function restoreGuessHistory(record) {
|
|
@@ -15975,7 +16062,7 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
15975
16062
|
return entries.map((entry) => compareData(entry, record.answer));
|
|
15976
16063
|
}
|
|
15977
16064
|
__name(restoreGuessHistory, "restoreGuessHistory");
|
|
15978
|
-
async function rollbackLegacyGame(session, record, guess, now) {
|
|
16065
|
+
async function rollbackLegacyGame(session, record, guess, now, allowStart) {
|
|
15979
16066
|
const answerTitle = record.answer?.chinese_title;
|
|
15980
16067
|
const history = answerTitle ? record.historyChineseTitles.filter((title) => title !== answerTitle) : record.historyChineseTitles;
|
|
15981
16068
|
const refunded = Math.max(0, record.dailyPlayedToday - 1);
|
|
@@ -15999,24 +16086,50 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
15999
16086
|
"检测到旧版本遗留的一局",
|
|
16000
16087
|
"这局是在旧版本下开始的,已有的猜测记录没法用新版图片牌面渲染。",
|
|
16001
16088
|
answerTitle ? `「${answerTitle}」已退回词库,之后仍有机会被抽到。` : null,
|
|
16002
|
-
"
|
|
16089
|
+
allowStart ? "这一局已作废并退还今日额度,马上按这次的完整指令重新开局。" : "这一局已作废并退还今日额度,请用 mcdle.猜 [名称] 重新开局。"
|
|
16003
16090
|
)
|
|
16004
16091
|
);
|
|
16005
|
-
|
|
16006
|
-
|
|
16007
|
-
|
|
16008
|
-
|
|
16009
|
-
|
|
16010
|
-
|
|
16011
|
-
|
|
16012
|
-
|
|
16013
|
-
|
|
16014
|
-
|
|
16015
|
-
|
|
16016
|
-
|
|
16092
|
+
if (allowStart) {
|
|
16093
|
+
await startNewGame(
|
|
16094
|
+
session,
|
|
16095
|
+
{
|
|
16096
|
+
...record,
|
|
16097
|
+
historyChineseTitles: history,
|
|
16098
|
+
dailyPlayedToday: refunded,
|
|
16099
|
+
gameEnded: true,
|
|
16100
|
+
formatVersion: FORMAT_VERSION
|
|
16101
|
+
},
|
|
16102
|
+
guess,
|
|
16103
|
+
now
|
|
16104
|
+
);
|
|
16105
|
+
}
|
|
16017
16106
|
}
|
|
16018
16107
|
__name(rollbackLegacyGame, "rollbackLegacyGame");
|
|
16019
16108
|
async function startNewGame(session, record, guess, now) {
|
|
16109
|
+
if (!guess) {
|
|
16110
|
+
await sendMsg(
|
|
16111
|
+
session,
|
|
16112
|
+
textCard(
|
|
16113
|
+
"还没有进行中的游戏",
|
|
16114
|
+
"请发送完整指令 mcdle.猜 [名称] 开局,例如 mcdle.猜 苦力怕。",
|
|
16115
|
+
"名称必须来自 mcdle.词库。"
|
|
16116
|
+
)
|
|
16117
|
+
);
|
|
16118
|
+
return;
|
|
16119
|
+
}
|
|
16120
|
+
const opener = findAnywhere(guess);
|
|
16121
|
+
if (!opener) {
|
|
16122
|
+
const near = [...allChineseTitles].filter((title) => title.includes(guess) || guess.includes(title)).slice(0, 3);
|
|
16123
|
+
await sendMsg(
|
|
16124
|
+
session,
|
|
16125
|
+
textCard(
|
|
16126
|
+
`⚠️ 「${guess}」不在 MCDLE 词库里`,
|
|
16127
|
+
near.length ? `是不是想猜:${near.join("、")}?` : null,
|
|
16128
|
+
"没有开启新局,也没有消耗今日额度。请用 mcdle.猜 [词库名称] 开局。"
|
|
16129
|
+
)
|
|
16130
|
+
);
|
|
16131
|
+
return;
|
|
16132
|
+
}
|
|
16020
16133
|
if (record.dailyPlayedToday >= cfg.dailyPlayLimit) {
|
|
16021
16134
|
await sendMsg(
|
|
16022
16135
|
session,
|
|
@@ -16028,8 +16141,7 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
16028
16141
|
);
|
|
16029
16142
|
return;
|
|
16030
16143
|
}
|
|
16031
|
-
const
|
|
16032
|
-
const mode = opener ? modeOf(opener) : ["mob", "item", "block"][Math.floor(Math.random() * 3)];
|
|
16144
|
+
const mode = modeOf(opener);
|
|
16033
16145
|
const answer = await pickAnswer(session, record, mode);
|
|
16034
16146
|
const played = record.dailyPlayedToday + 1;
|
|
16035
16147
|
await ctx.database.set(
|
|
@@ -16047,14 +16159,17 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
16047
16159
|
formatVersion: FORMAT_VERSION
|
|
16048
16160
|
}
|
|
16049
16161
|
);
|
|
16050
|
-
|
|
16051
|
-
|
|
16052
|
-
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16162
|
+
const channelOn = middlewareOn(session.channelId);
|
|
16163
|
+
await sendCard(
|
|
16164
|
+
session,
|
|
16165
|
+
startCard(mode, played, cfg.dailyPlayLimit, channelOn),
|
|
16166
|
+
startText(mode, played, channelOn)
|
|
16167
|
+
);
|
|
16168
|
+
await applyGuess(
|
|
16169
|
+
session,
|
|
16170
|
+
{ mode, answer, guesses: [], titles: [], startedAt: now, played },
|
|
16171
|
+
opener
|
|
16172
|
+
);
|
|
16058
16173
|
}
|
|
16059
16174
|
__name(startNewGame, "startNewGame");
|
|
16060
16175
|
async function continueGame(session, record, guess) {
|
|
@@ -16172,10 +16287,15 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
16172
16287
|
}
|
|
16173
16288
|
__name(applyGuess, "applyGuess");
|
|
16174
16289
|
function bz(session) {
|
|
16175
|
-
|
|
16290
|
+
const channelOn = middlewareOn(session.channelId);
|
|
16291
|
+
return sendCard(
|
|
16292
|
+
session,
|
|
16293
|
+
helpCard(cfg.dailyPlayLimit, cfg.allowRepeatedGuesses, channelOn),
|
|
16294
|
+
helpText(channelOn)
|
|
16295
|
+
);
|
|
16176
16296
|
}
|
|
16177
16297
|
__name(bz, "bz");
|
|
16178
|
-
function helpText() {
|
|
16298
|
+
function helpText(channelOn) {
|
|
16179
16299
|
const legend = ["true", "mixed", "false", "false_up", "false_down"].map(
|
|
16180
16300
|
(s) => `${STATUS_META[s].emoji} ${STATUS_META[s].label}`
|
|
16181
16301
|
);
|
|
@@ -16195,12 +16315,15 @@ ${words.join(" ")}`).join("\n\n")
|
|
|
16195
16315
|
[
|
|
16196
16316
|
"mcdle.猜 [名称] 开始一局,或提交猜测",
|
|
16197
16317
|
"mcdle.猜 局中直接使用可回看当前棋盘",
|
|
16318
|
+
"mcdle.裸猜 [开/关] 临时切换本群无前缀续猜",
|
|
16198
16319
|
"mcdle.排行榜 查看群内战绩",
|
|
16199
16320
|
"mcdle.词库 查阅全部候选词条"
|
|
16200
16321
|
],
|
|
16201
16322
|
[
|
|
16202
16323
|
`每个群每日 ${cfg.dailyPlayLimit} 局,跨零点重置。`,
|
|
16203
16324
|
cfg.allowRepeatedGuesses ? "允许重复提交已经猜过的词条。" : "同一局内不能重复提交已猜过的词条。",
|
|
16325
|
+
channelOn ? "本群裸猜已开启:仅已有对局、纯文本完整词条、且符合当前模式时响应。" : "本群裸猜已停用:请使用完整猜测指令。",
|
|
16326
|
+
"空指令和词库外名称不会开启新局或消耗额度。",
|
|
16204
16327
|
"词条与数据来自 zh.minecraft.wiki,版本号按发布先后比较。"
|
|
16205
16328
|
]
|
|
16206
16329
|
);
|
|
@@ -16381,7 +16504,10 @@ __name(apply, "apply");
|
|
|
16381
16504
|
0 && (module.exports = {
|
|
16382
16505
|
Config,
|
|
16383
16506
|
apply,
|
|
16507
|
+
canHandleMiddlewareGuess,
|
|
16508
|
+
getMiddlewareGuess,
|
|
16384
16509
|
inject,
|
|
16385
16510
|
name,
|
|
16511
|
+
resolveMiddlewareSwitch,
|
|
16386
16512
|
usage
|
|
16387
16513
|
});
|
package/lib/view.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface BoardOptions {
|
|
|
42
42
|
tip?: string;
|
|
43
43
|
}
|
|
44
44
|
export declare function boardCard(opts: BoardOptions): string;
|
|
45
|
-
export declare function startCard(mode: Mode, played: number, limit: number): string;
|
|
45
|
+
export declare function startCard(mode: Mode, played: number, limit: number, middleware: boolean): string;
|
|
46
46
|
export interface WinOptions {
|
|
47
47
|
mode: Mode;
|
|
48
48
|
answer: any;
|
|
@@ -56,8 +56,8 @@ export interface WinOptions {
|
|
|
56
56
|
/** 把秒数说成人话;秒级以内也要有话说,异常才落到破折号。 */
|
|
57
57
|
export declare function formatDuration(seconds: number): string;
|
|
58
58
|
export declare function winCard(o: WinOptions): string;
|
|
59
|
-
export declare function helpCard(dailyLimit: number, allowRepeat: boolean): string;
|
|
60
|
-
export declare function introCard(dailyLimit: number): string;
|
|
59
|
+
export declare function helpCard(dailyLimit: number, allowRepeat: boolean, middleware: boolean): string;
|
|
60
|
+
export declare function introCard(dailyLimit: number, middleware: boolean): string;
|
|
61
61
|
export interface RankEntry {
|
|
62
62
|
username: string;
|
|
63
63
|
userId: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-mcdle",
|
|
3
3
|
"description": "Koishi 的 Minecraft 猜词游戏插件。",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -59,6 +59,10 @@
|
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"koishi-plugin-puppeteer": "^3.9.0"
|
|
62
|
+
"koishi-plugin-puppeteer": "^3.9.0",
|
|
63
|
+
"tsx": "^4.23.13"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"test": "tsx --test test/*.test.ts"
|
|
63
67
|
}
|
|
64
68
|
}
|
package/readme.md
CHANGED
|
@@ -8,7 +8,7 @@ Koishi 的 Minecraft 猜词游戏插件。
|
|
|
8
8
|
|
|
9
9
|
## 使用
|
|
10
10
|
|
|
11
|
-
`mcdle.猜 [名称]`
|
|
11
|
+
`mcdle.猜 [名称]` 使用词库中的有效名称开局或猜测。首个词条决定生物、物品或方块模式,系统再从同类词库中抽取答案。开局后可用 `mcdle.裸猜` 临时切换本群的无前缀续猜;这一状态不改插件配置,插件重载后自动复原。
|
|
12
12
|
|
|
13
13
|
## 提示
|
|
14
14
|
|
|
@@ -24,7 +24,8 @@ Koishi 的 Minecraft 猜词游戏插件。
|
|
|
24
24
|
| 指令 | 说明 |
|
|
25
25
|
| --- | --- |
|
|
26
26
|
| `mcdle` | 查看帮助 |
|
|
27
|
-
| `mcdle.猜 [名称]` |
|
|
27
|
+
| `mcdle.猜 [名称]` | 用有效词条开局或猜测 |
|
|
28
|
+
| `mcdle.裸猜 [开/关]` | 临时切换本群无前缀续猜 |
|
|
28
29
|
| `mcdle.帮助` | 完整说明 |
|
|
29
30
|
| `mcdle.排行榜` | 群内战绩 |
|
|
30
31
|
| `mcdle.词库` | 全部词条 |
|