@zhin.js/plugin-idiom-chain 1.1.17 → 1.1.19
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/commands/chain/[[action]]/index.js +5 -4
- package/commands/chain/[[action]]/index.ts +5 -4
- package/lib/chain-command.d.ts +3 -3
- package/lib/chain-command.js +33 -31
- package/lib/chain-command.js.map +1 -1
- package/lib/game-flow.d.ts +6 -6
- package/lib/game-flow.js +158 -147
- package/lib/game-flow.js.map +1 -1
- package/lib/session-service.d.ts +2 -2
- package/lib/session-service.js +4 -9
- package/lib/session-service.js.map +1 -1
- package/middlewares/chain-alias/index.js +12 -8
- package/middlewares/chain-alias/index.ts +11 -7
- package/middlewares/chain-text/index.js +13 -12
- package/middlewares/chain-text/index.ts +13 -11
- package/package.json +7 -7
- package/src/chain-command.ts +31 -29
- package/src/game-flow.ts +158 -148
- package/src/session-service.ts +6 -12
package/lib/session-service.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseSessionService,
|
|
1
|
+
import { BaseSessionService, generateSessionId, } from '@zhin.js/game-kit';
|
|
2
2
|
export function parseUsed(value) {
|
|
3
3
|
if (Array.isArray(value))
|
|
4
4
|
return new Set(value.filter((x) => typeof x === 'string'));
|
|
@@ -28,13 +28,8 @@ export class SessionService extends BaseSessionService {
|
|
|
28
28
|
const row = {
|
|
29
29
|
id: generateSessionId(),
|
|
30
30
|
locale: message.locale ?? 'zh-CN',
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
channel_type: message.$channel.type,
|
|
34
|
-
channel_id: message.$channel.id,
|
|
35
|
-
channel_key: channelKey(message),
|
|
36
|
-
player_id: message.$sender.id,
|
|
37
|
-
player_name: message.$sender.name?.trim() || message.$sender.id,
|
|
31
|
+
player_id: message.sender.id,
|
|
32
|
+
player_name: message.sender.name?.trim() || message.sender.id,
|
|
38
33
|
last_idiom: starter.text,
|
|
39
34
|
next_char: starter.nextChar,
|
|
40
35
|
match_mode: starter.matchMode,
|
|
@@ -50,7 +45,7 @@ export class SessionService extends BaseSessionService {
|
|
|
50
45
|
updated_at: now,
|
|
51
46
|
created_at: now,
|
|
52
47
|
};
|
|
53
|
-
return this.createRow(row);
|
|
48
|
+
return this.createRow({ target: message.target, fields: row });
|
|
54
49
|
}
|
|
55
50
|
}
|
|
56
51
|
export function createServices(db) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,
|
|
1
|
+
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,GAGlB,MAAM,mBAAmB,CAAC;AAM3B,MAAM,UAAU,SAAS,CAAC,KAAkC;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;IAClG,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;IACrG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,GAAG,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAgB;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,kBAAmC;IACrE,YAAY,EAAiB;QAC3B,KAAK,CAAC,EAAqD,EAAE;YAC3D,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,sBAAsB;YAC7B,UAAU,EAAE,CAAC,WAAW,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,OAAmB,EACnB,OAAiF;QAEjF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAkG;YACzG,EAAE,EAAE,iBAAiB,EAAE;YACvB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO;YACjC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE;YAC5B,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE;YAC7D,UAAU,EAAE,OAAO,CAAC,IAAI;YACxB,SAAS,EAAE,OAAO,CAAC,QAAQ;YAC3B,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,WAAW,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACjD,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC;YACT,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,CAAC;YACb,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;SAChB,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACjE,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAAiB;IAC9C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
-
import { defineGameCommandAliasMiddleware, isChainAction,
|
|
2
|
+
import { replyGameOperation, defineGameCommandAliasMiddleware, isChainAction, gamePlayerFromInput, normalizeChainAction, } from '@zhin.js/game-kit';
|
|
3
3
|
import { getChainHelp, runChainCommand } from "../../lib/chain-command.js";
|
|
4
4
|
import { resolveGameServices } from "../../lib/runtime-store.js";
|
|
5
5
|
export default defineGameCommandAliasMiddleware({
|
|
6
6
|
aliases: ['接龙', 'chain'],
|
|
7
7
|
async run(action, input, context) {
|
|
8
|
-
const
|
|
9
|
-
formatCommand: (path) => context.input.formatCommand?.(path, context.owner.id)
|
|
10
|
-
});
|
|
8
|
+
const presentation = { locale: context.input.locale,
|
|
9
|
+
formatCommand: (path) => context.input.formatCommand?.(path, context.owner.id) };
|
|
11
10
|
const normalized = normalizeChainAction(String(action ?? ''));
|
|
12
|
-
if (normalized === 'help')
|
|
13
|
-
|
|
11
|
+
if (normalized === 'help') {
|
|
12
|
+
await context.input.$reply(getChainHelp(presentation));
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
14
15
|
// action 无法识别:放行给后续中间件,避免劫持普通聊天
|
|
15
16
|
if (!isChainAction(normalized))
|
|
16
|
-
return
|
|
17
|
+
return false;
|
|
18
|
+
const message = gamePlayerFromInput(input, presentation);
|
|
17
19
|
const services = resolveGameServices(context);
|
|
18
|
-
|
|
20
|
+
await replyGameOperation({ session: services, player: message, reply: content => context.input.$reply(content),
|
|
21
|
+
run: () => runChainCommand(services, message, normalized) });
|
|
22
|
+
return true;
|
|
19
23
|
},
|
|
20
24
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
+
replyGameOperation,
|
|
2
3
|
defineGameCommandAliasMiddleware,
|
|
3
4
|
isChainAction,
|
|
4
|
-
|
|
5
|
+
gamePlayerFromInput,
|
|
5
6
|
normalizeChainAction,
|
|
6
7
|
} from '@zhin.js/game-kit';
|
|
7
8
|
import { getChainHelp, runChainCommand } from '../../src/chain-command.js';
|
|
@@ -10,14 +11,17 @@ import { resolveGameServices } from '../../src/runtime-store.js';
|
|
|
10
11
|
export default defineGameCommandAliasMiddleware({
|
|
11
12
|
aliases: ['接龙', 'chain'],
|
|
12
13
|
async run(action, input, context) {
|
|
13
|
-
const
|
|
14
|
-
formatCommand: (path) => context.input.formatCommand?.(path, context.owner.id)
|
|
15
|
-
|
|
14
|
+
const presentation = { locale: context.input.locale,
|
|
15
|
+
formatCommand: (path: string) => context.input.formatCommand?.(path, context.owner.id) };
|
|
16
|
+
|
|
16
17
|
const normalized = normalizeChainAction(String(action ?? ''));
|
|
17
|
-
if (normalized === 'help')
|
|
18
|
+
if (normalized === 'help') { await context.input.$reply(getChainHelp(presentation)); return true; }
|
|
18
19
|
// action 无法识别:放行给后续中间件,避免劫持普通聊天
|
|
19
|
-
if (!isChainAction(normalized)) return
|
|
20
|
+
if (!isChainAction(normalized)) return false;
|
|
21
|
+
const message = gamePlayerFromInput(input, presentation);
|
|
20
22
|
const services = resolveGameServices(context);
|
|
21
|
-
|
|
23
|
+
await replyGameOperation({ session: services, player: message, reply: content => context.input.$reply(content),
|
|
24
|
+
run: () => runChainCommand(services, message, normalized) });
|
|
25
|
+
return true;
|
|
22
26
|
},
|
|
23
27
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { replyGameOperation, buildChoiceFallbackMap, channelKey, gamePlayerFromInput, parseChoicePayload, resolveGameTextPayload, } from '@zhin.js/game-kit';
|
|
2
3
|
import { defineMiddleware } from 'zhin.js/middleware';
|
|
3
|
-
import { buildChoiceFallbackMap, channelKey, messageFromCommandInput, parseChoicePayload, resolveGameTextPayload, } from '@zhin.js/game-kit';
|
|
4
4
|
import { resolveGameServices } from "../../lib/runtime-store.js";
|
|
5
5
|
import { CHAIN_PREFIX, handleChoice, processIdiomText } from "../../lib/game-flow.js";
|
|
6
6
|
/**
|
|
@@ -10,13 +10,17 @@ import { CHAIN_PREFIX, handleChoice, processIdiomText } from "../../lib/game-flo
|
|
|
10
10
|
export default defineMiddleware({
|
|
11
11
|
target: 'inbound',
|
|
12
12
|
async handle(context, next) {
|
|
13
|
+
if (!context.input.sender?.id) {
|
|
14
|
+
await next();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
13
17
|
const raw = context.input.content?.trim() ?? '';
|
|
14
18
|
if (!raw) {
|
|
15
19
|
await next();
|
|
16
20
|
return;
|
|
17
21
|
}
|
|
18
22
|
const services = resolveGameServices(context);
|
|
19
|
-
const message =
|
|
23
|
+
const message = gamePlayerFromInput(context.input);
|
|
20
24
|
const ch = channelKey(message);
|
|
21
25
|
// 直接 payload(QQ 指令预填 / Sandbox action→text)
|
|
22
26
|
const payloadFromText = resolveGameTextPayload(raw);
|
|
@@ -25,16 +29,15 @@ export default defineMiddleware({
|
|
|
25
29
|
if (parsed) {
|
|
26
30
|
const session = await services.getById(parsed.sessionId);
|
|
27
31
|
if (session?.channel_key === ch) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
await context.input.$reply(reply);
|
|
32
|
+
await replyGameOperation({ session: services, player: message, reply: content => context.input.$reply(content),
|
|
33
|
+
run: () => handleChoice(services, message, parsed.sessionId, parsed.choiceId) });
|
|
31
34
|
return;
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
await next();
|
|
35
38
|
return;
|
|
36
39
|
}
|
|
37
|
-
const session = await services.getActiveForUser(ch, message
|
|
40
|
+
const session = await services.getActiveForUser(ch, message.sender.id);
|
|
38
41
|
if (!session) {
|
|
39
42
|
await next();
|
|
40
43
|
return;
|
|
@@ -48,17 +51,15 @@ export default defineMiddleware({
|
|
|
48
51
|
const payload = resolveGameTextPayload(raw, map);
|
|
49
52
|
const parsed = payload ? parseChoicePayload(payload, CHAIN_PREFIX) : null;
|
|
50
53
|
if (parsed?.sessionId === session.id) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
await context.input.$reply(reply);
|
|
54
|
+
await replyGameOperation({ session: services, player: message, reply: content => context.input.$reply(content),
|
|
55
|
+
run: () => handleChoice(services, message, session.id, parsed.choiceId) });
|
|
54
56
|
return;
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
// 仅把 2-8 个汉字的纯文本当成语作答,其余放行
|
|
58
60
|
if (/^[\u4e00-\u9fff]{2,8}$/.test(raw)) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
await context.input.$reply(reply);
|
|
61
|
+
await replyGameOperation({ session: services, player: message, reply: content => context.input.$reply(content),
|
|
62
|
+
run: () => processIdiomText(services, message, raw) });
|
|
62
63
|
return;
|
|
63
64
|
}
|
|
64
65
|
await next();
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { defineMiddleware } from 'zhin.js/middleware';
|
|
2
|
-
import type { Message } from '@zhin.js/core/runtime';
|
|
3
1
|
import {
|
|
2
|
+
replyGameOperation,
|
|
4
3
|
buildChoiceFallbackMap,
|
|
5
4
|
channelKey,
|
|
6
|
-
|
|
5
|
+
gamePlayerFromInput,
|
|
7
6
|
parseChoicePayload,
|
|
8
7
|
resolveGameTextPayload,
|
|
9
8
|
} from '@zhin.js/game-kit';
|
|
9
|
+
import { defineMiddleware } from 'zhin.js/middleware';
|
|
10
|
+
import type { Message } from '@zhin.js/core/runtime';
|
|
10
11
|
import { resolveGameServices } from '../../src/runtime-store.js';
|
|
11
12
|
import { CHAIN_PREFIX, handleChoice, processIdiomText } from '../../src/game-flow.js';
|
|
12
13
|
|
|
@@ -17,13 +18,14 @@ import { CHAIN_PREFIX, handleChoice, processIdiomText } from '../../src/game-flo
|
|
|
17
18
|
export default defineMiddleware<Message>({
|
|
18
19
|
target: 'inbound',
|
|
19
20
|
async handle(context, next) {
|
|
21
|
+
if (!context.input.sender?.id) { await next(); return; }
|
|
20
22
|
const raw = context.input.content?.trim() ?? '';
|
|
21
23
|
if (!raw) {
|
|
22
24
|
await next();
|
|
23
25
|
return;
|
|
24
26
|
}
|
|
25
27
|
const services = resolveGameServices(context);
|
|
26
|
-
const message =
|
|
28
|
+
const message = gamePlayerFromInput(context.input);
|
|
27
29
|
const ch = channelKey(message);
|
|
28
30
|
|
|
29
31
|
// 直接 payload(QQ 指令预填 / Sandbox action→text)
|
|
@@ -33,8 +35,8 @@ export default defineMiddleware<Message>({
|
|
|
33
35
|
if (parsed) {
|
|
34
36
|
const session = await services.getById(parsed.sessionId);
|
|
35
37
|
if (session?.channel_key === ch) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
await replyGameOperation({ session: services, player: message, reply: content => context.input.$reply(content),
|
|
39
|
+
run: () => handleChoice(services, message, parsed.sessionId, parsed.choiceId) });
|
|
38
40
|
return;
|
|
39
41
|
}
|
|
40
42
|
}
|
|
@@ -42,7 +44,7 @@ export default defineMiddleware<Message>({
|
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
const session = await services.getActiveForUser(ch, message
|
|
47
|
+
const session = await services.getActiveForUser(ch, message.sender.id);
|
|
46
48
|
if (!session) {
|
|
47
49
|
await next();
|
|
48
50
|
return;
|
|
@@ -57,16 +59,16 @@ export default defineMiddleware<Message>({
|
|
|
57
59
|
const payload = resolveGameTextPayload(raw, map);
|
|
58
60
|
const parsed = payload ? parseChoicePayload(payload, CHAIN_PREFIX) : null;
|
|
59
61
|
if (parsed?.sessionId === session.id) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
await replyGameOperation({ session: services, player: message, reply: content => context.input.$reply(content),
|
|
63
|
+
run: () => handleChoice(services, message, session.id, parsed.choiceId) });
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
// 仅把 2-8 个汉字的纯文本当成语作答,其余放行
|
|
67
69
|
if (/^[\u4e00-\u9fff]{2,8}$/.test(raw)) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
await replyGameOperation({ session: services, player: message, reply: content => context.input.$reply(content),
|
|
71
|
+
run: () => processIdiomText(services, message, raw) });
|
|
70
72
|
return;
|
|
71
73
|
}
|
|
72
74
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-idiom-chain",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.19",
|
|
4
4
|
"description": "Zhin.js 成语接龙 — 四字成语文字接龙 (Plugin Runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"chinese-idiom-chengyu": "^1.1.0",
|
|
27
|
-
"@zhin.js/core": "1.1.
|
|
28
|
-
"@zhin.js/game-kit": "1.1.
|
|
27
|
+
"@zhin.js/core": "1.1.54",
|
|
28
|
+
"@zhin.js/game-kit": "1.1.19"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"typescript": "^6.0.3",
|
|
32
32
|
"vitest": "^4.1.10",
|
|
33
|
-
"zhin.js": "1.1.
|
|
33
|
+
"zhin.js": "1.1.19"
|
|
34
34
|
},
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|
|
@@ -67,9 +67,9 @@
|
|
|
67
67
|
"plugins": []
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"@zhin.js/command": "^1.1.
|
|
71
|
-
"@zhin.js/middleware": "^1.1.
|
|
72
|
-
"zhin.js": "^1.1.
|
|
70
|
+
"@zhin.js/command": "^1.1.12",
|
|
71
|
+
"@zhin.js/middleware": "^1.1.11",
|
|
72
|
+
"zhin.js": "^1.1.19"
|
|
73
73
|
},
|
|
74
74
|
"peerDependenciesMeta": {
|
|
75
75
|
"@zhin.js/command": {
|
package/src/chain-command.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatGameHelp, gameCommandFeedback, gameCommandHint, channelKey, type
|
|
1
|
+
import { formatGameHelp, gameCommandFeedback, gameCommandHint, channelKey, type GamePlayer, type GameReply } from '@zhin.js/game-kit';
|
|
2
2
|
import { createMessages } from 'zhin.js/i18n';
|
|
3
3
|
import { continueGame, startGame } from './game-flow.js';
|
|
4
4
|
import { idiomCount, modeLabel, promptLine, type MatchMode } from './engine.js';
|
|
@@ -15,10 +15,10 @@ const messages = createMessages({
|
|
|
15
15
|
quit: { 'zh-CN': '已放弃成语接龙。', en: 'You quit the idiom chain.' },
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
export function getChainHelp(message: Pick<
|
|
18
|
+
export function getChainHelp(message: Pick<GamePlayer, 'locale' | 'formatCommand'> = {}): string {
|
|
19
19
|
const locale = message.locale ?? 'zh-CN';
|
|
20
20
|
const command = message.formatCommand?.('chain');
|
|
21
|
-
return [formatGameHelp(message, { 'zh-CN': '📜 成语接龙(文字接龙 · 四字成语)', en: '📜 Chinese Idiom Chain' }, 'chain', ['continue', 'quit']),
|
|
21
|
+
return [formatGameHelp({ presentation: message, title: { 'zh-CN': '📜 成语接龙(文字接龙 · 四字成语)', en: '📜 Chinese Idiom Chain' }, commandPath: 'chain', actions: ['continue', 'quit'] }),
|
|
22
22
|
messages(locale, 'dictionary', { count: idiomCount() }),
|
|
23
23
|
...(command ? [messages(locale, 'pinyin', { command: command + ' start_pinyin' }), messages(locale, 'char', { command: command + ' start_char' })] : []),
|
|
24
24
|
messages(locale, 'instructions'),
|
|
@@ -28,37 +28,39 @@ export const CHAIN_HELP = getChainHelp();
|
|
|
28
28
|
|
|
29
29
|
export async function runChainCommand(
|
|
30
30
|
services: SessionService,
|
|
31
|
-
message:
|
|
31
|
+
message: GamePlayer,
|
|
32
32
|
action: string,
|
|
33
33
|
): Promise<GameReply> {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
return services.runInScope({ scope: channelKey(message), run: async () => {
|
|
35
|
+
const ch = channelKey(message);
|
|
36
|
+
const userId = message.sender.id;
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
if (!action || action === 'help') {
|
|
39
|
+
const active = await services.getActiveByChannel(ch);
|
|
40
|
+
const lines = [getChainHelp(message), ''];
|
|
41
|
+
if (active) {
|
|
42
|
+
const mode: MatchMode = active.match_mode === 'char' ? 'char' : 'pinyin';
|
|
43
|
+
lines.push(
|
|
44
|
+
messages(active.locale ?? undefined, 'active', { player: active.player_name, mode: modeLabel(mode, active.locale ?? undefined), playerScore: active.player_score, botScore: active.bot_score, streak: active.streak }),
|
|
45
|
+
);
|
|
46
|
+
if (active.last_idiom) lines.push(promptLine(active.last_idiom, mode, active.locale ?? undefined));
|
|
47
|
+
} else {
|
|
48
|
+
lines.push(gameCommandFeedback(message, 'noGame'), gameCommandHint(message, 'chain', 'start_pinyin'));
|
|
49
|
+
}
|
|
50
|
+
return lines.join('\n');
|
|
48
51
|
}
|
|
49
|
-
return lines.join('\n');
|
|
50
|
-
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
if (action === 'start_pinyin') return (await startGame(services, message, 'pinyin')) ?? '';
|
|
54
|
+
if (action === 'start_char') return (await startGame(services, message, 'char')) ?? '';
|
|
55
|
+
if (action === 'continue') return continueGame(services, message);
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
if (action === 'quit') {
|
|
58
|
+
const row = await services.getActiveForUser(ch, userId);
|
|
59
|
+
if (!row) return gameCommandFeedback(message, 'noGame');
|
|
60
|
+
await services.updateSession(row.id, { status: 'aborted' });
|
|
61
|
+
return messages(row.locale ?? undefined, 'quit');
|
|
62
|
+
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getChainHelp(message);
|
|
65
|
+
} });
|
|
64
66
|
}
|