@zhin.js/plugin-word-riddle 1.1.15 → 1.1.17
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/riddle/[[action]]/index.js +4 -4
- package/commands/riddle/[[action]]/index.ts +4 -4
- package/lib/engine.d.ts +2 -1
- package/lib/engine.js +7 -2
- package/lib/engine.js.map +1 -1
- package/lib/game-flow.js +45 -19
- package/lib/game-flow.js.map +1 -1
- package/lib/models.d.ts +4 -1
- package/lib/models.js +2 -1
- package/lib/models.js.map +1 -1
- package/lib/riddle-command.d.ts +1 -0
- package/lib/riddle-command.js +26 -19
- package/lib/riddle-command.js.map +1 -1
- package/lib/session-service.js +1 -0
- package/lib/session-service.js.map +1 -1
- package/lib/view.js +28 -12
- package/lib/view.js.map +1 -1
- package/middlewares/riddle-alias/index.js +5 -3
- package/middlewares/riddle-alias/index.ts +5 -3
- package/package.json +7 -7
- package/plugin.js +4 -0
- package/src/engine.ts +8 -2
- package/src/game-flow.ts +46 -19
- package/src/models.ts +4 -2
- package/src/riddle-command.ts +28 -23
- package/src/session-service.ts +1 -0
- package/src/view.ts +29 -12
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { defineCommand } from 'zhin.js/command';
|
|
3
3
|
import { messageFromCommandInput, normalizeRiddleAction } from '@zhin.js/game-kit';
|
|
4
|
-
import {
|
|
4
|
+
import { getRiddleHelp, runRiddleCommand } from "../../../lib/riddle-command.js";
|
|
5
5
|
import { resolveGameServices } from "../../../lib/runtime-store.js";
|
|
6
6
|
export default defineCommand({
|
|
7
7
|
description: 'Word Riddle',
|
|
8
8
|
params: { action: { type: 'string', default: '' } },
|
|
9
|
-
async execute({ params, input, use,
|
|
9
|
+
async execute({ params, input, use, locale, formatCommand }) {
|
|
10
10
|
const action = normalizeRiddleAction(String(params.action ?? ''));
|
|
11
11
|
if (!action || action === 'help')
|
|
12
|
-
return
|
|
12
|
+
return getRiddleHelp({ locale, formatCommand });
|
|
13
13
|
const services = resolveGameServices({ use });
|
|
14
|
-
const message = messageFromCommandInput(input);
|
|
14
|
+
const message = messageFromCommandInput(input, { locale, formatCommand });
|
|
15
15
|
return runRiddleCommand(services, message, action);
|
|
16
16
|
},
|
|
17
17
|
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { defineCommand } from 'zhin.js/command';
|
|
2
2
|
import { messageFromCommandInput, normalizeRiddleAction } from '@zhin.js/game-kit';
|
|
3
|
-
import {
|
|
3
|
+
import { getRiddleHelp, runRiddleCommand } from '../../../src/riddle-command.js';
|
|
4
4
|
import { resolveGameServices } from '../../../src/runtime-store.js';
|
|
5
5
|
|
|
6
6
|
export default defineCommand({
|
|
7
7
|
description: 'Word Riddle',
|
|
8
8
|
params: { action: { type: 'string', default: '' } },
|
|
9
|
-
async execute({ params, input, use,
|
|
9
|
+
async execute({ params, input, use, locale, formatCommand }) {
|
|
10
10
|
const action = normalizeRiddleAction(String(params.action ?? ''));
|
|
11
|
-
if (!action || action === 'help') return
|
|
11
|
+
if (!action || action === 'help') return getRiddleHelp({ locale, formatCommand });
|
|
12
12
|
const services = resolveGameServices({ use });
|
|
13
|
-
const message = messageFromCommandInput(input);
|
|
13
|
+
const message = messageFromCommandInput(input, { locale, formatCommand });
|
|
14
14
|
return runRiddleCommand(services, message, action);
|
|
15
15
|
},
|
|
16
16
|
});
|
package/lib/engine.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { type Locale } from 'zhin.js/i18n';
|
|
1
2
|
import { getRiddleById, type RiddleEntry, type RiddleType } from './riddle-provider.js';
|
|
2
3
|
export type { RiddleType };
|
|
3
4
|
export declare const RIDDLE_PREFIX = "riddle";
|
|
4
5
|
export declare function normalizeAnswer(raw: string): string;
|
|
5
6
|
export declare function answersFor(entry: RiddleEntry): string[];
|
|
6
7
|
export declare function checkAnswer(entry: RiddleEntry, raw: string): boolean;
|
|
7
|
-
export declare function typeLabel(type: RiddleType): string;
|
|
8
|
+
export declare function typeLabel(type: RiddleType, locale?: Locale): string;
|
|
8
9
|
export { getRiddleById };
|
package/lib/engine.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
1
2
|
import { getRiddleById, } from './riddle-provider.js';
|
|
2
3
|
export const RIDDLE_PREFIX = 'riddle';
|
|
3
4
|
export function normalizeAnswer(raw) {
|
|
@@ -13,8 +14,12 @@ export function checkAnswer(entry, raw) {
|
|
|
13
14
|
return false;
|
|
14
15
|
return answersFor(entry).some((x) => x === a);
|
|
15
16
|
}
|
|
16
|
-
export function typeLabel(type) {
|
|
17
|
-
return type === 'char' ? '
|
|
17
|
+
export function typeLabel(type, locale) {
|
|
18
|
+
return type === 'char' ? messages(locale, 'text1') : messages(locale, 'text2');
|
|
18
19
|
}
|
|
19
20
|
export { getRiddleById };
|
|
21
|
+
const messages = createMessages({
|
|
22
|
+
text1: { 'zh-CN': "字谜", en: "Chinese Character Riddles" },
|
|
23
|
+
text2: { 'zh-CN': "猜成语", en: "Chinese Idiom Riddles" },
|
|
24
|
+
});
|
|
20
25
|
//# sourceMappingURL=engine.js.map
|
package/lib/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,GAGd,MAAM,sBAAsB,CAAC;AAI9B,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAC;AAEtC,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAkB;IAC3C,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAkB,EAAE,GAAW;IACzD,MAAM,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAgB;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAe,MAAM,cAAc,CAAC;AAC3D,OAAO,EACL,aAAa,GAGd,MAAM,sBAAsB,CAAC;AAI9B,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAC;AAEtC,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAkB;IAC3C,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAkB,EAAE,GAAW;IACzD,MAAM,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAgB,EAAE,MAAe;IACzD,OAAO,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACjF,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,2BAA2B,EAAE;IACzD,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,uBAAuB,EAAE;CACvD,CAAC,CAAC"}
|
package/lib/game-flow.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createMessages, resolveLocale } from 'zhin.js/i18n';
|
|
1
2
|
import { answersFor, checkAnswer, getRiddleById, normalizeAnswer, RIDDLE_PREFIX, typeLabel, } from './engine.js';
|
|
2
3
|
import { currentRiddleId, parseQueue, } from './session-service.js';
|
|
3
4
|
import { buildRiddleView, MAX_WRONG } from './view.js';
|
|
@@ -23,24 +24,27 @@ async function advanceQuestion(services, session) {
|
|
|
23
24
|
export async function startGame(services, message, mode) {
|
|
24
25
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
25
26
|
const active = await services.getActiveByChannel(ch);
|
|
27
|
+
const locale = resolveLocale(active ? active.locale : message.locale);
|
|
26
28
|
if (active) {
|
|
27
29
|
if (active.player_id === message.$sender.id) {
|
|
28
|
-
return
|
|
30
|
+
return messages(locale, 'text1', { p0: typeLabel(active.mode, locale) });
|
|
29
31
|
}
|
|
30
|
-
return
|
|
32
|
+
return messages(locale, 'text2', { p0: active.player_name });
|
|
31
33
|
}
|
|
32
34
|
const session = await services.createSession(message, mode);
|
|
33
35
|
return renderView(message, session);
|
|
34
36
|
}
|
|
35
37
|
export async function continueGame(services, message) {
|
|
36
38
|
const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
|
|
39
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
37
40
|
if (!session)
|
|
38
|
-
return
|
|
41
|
+
return messages(locale, 'text3');
|
|
39
42
|
return renderView(message, session);
|
|
40
43
|
}
|
|
41
44
|
export async function processAnswerText(services, message, raw) {
|
|
42
45
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
43
46
|
const session = await services.getActiveForUser(ch, message.$sender.id);
|
|
47
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
44
48
|
if (!session || session.status !== 'active')
|
|
45
49
|
return null;
|
|
46
50
|
const riddleId = currentRiddleId(session);
|
|
@@ -50,7 +54,7 @@ export async function processAnswerText(services, message, raw) {
|
|
|
50
54
|
// 格式不合规(字数与答案不符)只提示、不扣失误:避免闲聊(「好的」「谢谢」)被累计判负
|
|
51
55
|
const normalized = normalizeAnswer(raw);
|
|
52
56
|
if (!answersFor(entry).some((a) => a.length === normalized.length)) {
|
|
53
|
-
return
|
|
57
|
+
return messages(locale, 'text4', { p0: entry.answer.length });
|
|
54
58
|
}
|
|
55
59
|
if (checkAnswer(entry, raw)) {
|
|
56
60
|
const streak = session.streak + 1;
|
|
@@ -64,8 +68,8 @@ export async function processAnswerText(services, message, raw) {
|
|
|
64
68
|
const after = await advanceQuestion(services, (await services.getById(session.id)));
|
|
65
69
|
const explain = entry.explanation ? `\n📖 ${entry.explanation}` : '';
|
|
66
70
|
return renderView(message, after, [
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
messages(locale, 'text5', { p0: entry.answer, p1: explain }),
|
|
72
|
+
messages(locale, 'text6', { p0: 10 + Math.min(streak, 5) }),
|
|
69
73
|
]);
|
|
70
74
|
}
|
|
71
75
|
const wrong = session.wrong_count + 1;
|
|
@@ -73,20 +77,21 @@ export async function processAnswerText(services, message, raw) {
|
|
|
73
77
|
await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
|
|
74
78
|
const after = await advanceQuestion(services, (await services.getById(session.id)));
|
|
75
79
|
return renderView(message, after, [
|
|
76
|
-
|
|
77
|
-
'
|
|
80
|
+
messages(locale, 'text7', { p0: entry.answer }),
|
|
81
|
+
messages(locale, 'text8'),
|
|
78
82
|
]);
|
|
79
83
|
}
|
|
80
84
|
await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
|
|
81
85
|
const updated = (await services.getById(session.id));
|
|
82
|
-
return renderView(message, updated, [
|
|
86
|
+
return renderView(message, updated, [messages(locale, 'text9')]);
|
|
83
87
|
}
|
|
84
88
|
export async function handleChoice(services, message, sessionId, choiceId) {
|
|
85
89
|
const session = await services.getById(sessionId);
|
|
90
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
86
91
|
if (!session)
|
|
87
|
-
return '
|
|
92
|
+
return messages(locale, 'text10');
|
|
88
93
|
if (session.player_id !== message.$sender.id)
|
|
89
|
-
return '
|
|
94
|
+
return messages(locale, 'text11');
|
|
90
95
|
if (choiceId === 'restart_char') {
|
|
91
96
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
92
97
|
return (await startGame(services, message, 'char')) ?? null;
|
|
@@ -96,32 +101,53 @@ export async function handleChoice(services, message, sessionId, choiceId) {
|
|
|
96
101
|
return (await startGame(services, message, 'idiom')) ?? null;
|
|
97
102
|
}
|
|
98
103
|
if (session.status !== 'active')
|
|
99
|
-
return '
|
|
104
|
+
return messages(locale, 'text12');
|
|
100
105
|
const riddleId = currentRiddleId(session);
|
|
101
106
|
const entry = riddleId ? getRiddleById(riddleId) : undefined;
|
|
102
107
|
if (!entry)
|
|
103
|
-
return '
|
|
108
|
+
return messages(locale, 'text13');
|
|
104
109
|
if (choiceId === 'hint') {
|
|
105
|
-
const hint = entry.hint ??
|
|
110
|
+
const hint = entry.hint ?? messages(locale, 'text14', { p0: entry.answer.length });
|
|
106
111
|
await services.updateSession(session.id, { hints_used: session.hints_used + 1, streak: 0 });
|
|
107
112
|
const updated = (await services.getById(session.id));
|
|
108
113
|
return renderView(message, updated, [
|
|
109
|
-
|
|
110
|
-
'
|
|
114
|
+
messages(locale, 'text15', { p0: hint }),
|
|
115
|
+
messages(locale, 'text16'),
|
|
111
116
|
]);
|
|
112
117
|
}
|
|
113
118
|
if (choiceId === 'skip') {
|
|
114
119
|
await services.updateSession(session.id, { streak: 0 });
|
|
115
120
|
const after = await advanceQuestion(services, session);
|
|
116
121
|
return renderView(message, after, [
|
|
117
|
-
|
|
122
|
+
messages(locale, 'text17', { p0: entry.answer }),
|
|
118
123
|
]);
|
|
119
124
|
}
|
|
120
125
|
if (choiceId === 'quit') {
|
|
121
126
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
122
|
-
return '
|
|
127
|
+
return messages(locale, 'text18');
|
|
123
128
|
}
|
|
124
|
-
return '
|
|
129
|
+
return messages(locale, 'text19');
|
|
125
130
|
}
|
|
126
131
|
export { RIDDLE_PREFIX };
|
|
132
|
+
const messages = createMessages({
|
|
133
|
+
text1: { 'zh-CN': "你已有进行中的猜谜({p0}),请使用当前对局的操作入口继续。", en: "You already have an active riddle game ({p0}). Continue using its controls." },
|
|
134
|
+
text2: { 'zh-CN': "本频道 {p0} 正在猜谜。", en: "{p0} is solving riddles in this channel." },
|
|
135
|
+
text3: { 'zh-CN': "你没有进行中的猜谜。", en: "You have no active riddle game." },
|
|
136
|
+
text4: { 'zh-CN': "本题答案应为 {p0} 个字(这条不算失误)。", en: "The answer has {p0} characters (this does not count as a mistake)." },
|
|
137
|
+
text5: { 'zh-CN': "✅ 正确!答案:**{p0}**{p1}", en: "✅ Correct! Answer: **{p0}**{p1}" },
|
|
138
|
+
text6: { 'zh-CN': "+{p0} 分", en: "+{p0} points" },
|
|
139
|
+
text7: { 'zh-CN': "❌ 本题答案:**{p0}**", en: "❌ Answer: **{p0}**" },
|
|
140
|
+
text8: { 'zh-CN': "失误过多,自动下一题。", en: "Too many mistakes. Moving to the next riddle." },
|
|
141
|
+
text9: { 'zh-CN': "❌ 不对,再想想!", en: "❌ Not quite. Try again!" },
|
|
142
|
+
text10: { 'zh-CN': "会话不存在。", en: "This game no longer exists." },
|
|
143
|
+
text11: { 'zh-CN': "这是别人的猜谜。", en: "This riddle game belongs to another player." },
|
|
144
|
+
text12: { 'zh-CN': "本轮已结束。", en: "This round has ended." },
|
|
145
|
+
text13: { 'zh-CN': "题目丢失。", en: "The riddle is unavailable." },
|
|
146
|
+
text14: { 'zh-CN': "答案共 {p0} 个字", en: "The answer has {p0} characters" },
|
|
147
|
+
text15: { 'zh-CN': "💡 提示:{p0}", en: "💡 Hint: {p0}" },
|
|
148
|
+
text16: { 'zh-CN': "(连击清零)", en: "(Streak reset)" },
|
|
149
|
+
text17: { 'zh-CN': "⏭️ 跳过,答案:**{p0}**", en: "⏭️ Skipped. Answer: **{p0}**" },
|
|
150
|
+
text18: { 'zh-CN': "已结束猜谜。", en: "The riddle game has ended." },
|
|
151
|
+
text19: { 'zh-CN': "未知操作。", en: "Unknown action." },
|
|
152
|
+
});
|
|
127
153
|
//# sourceMappingURL=game-flow.js.map
|
package/lib/game-flow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
|
package/lib/models.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ declare module '@zhin.js/core' {
|
|
|
4
4
|
interface Models {
|
|
5
5
|
word_riddle_sessions: {
|
|
6
6
|
id: string;
|
|
7
|
+
locale?: 'zh-CN' | 'en' | null;
|
|
7
8
|
adapter: string;
|
|
8
9
|
endpoint: string;
|
|
9
10
|
channel_type: string;
|
|
@@ -27,5 +28,7 @@ declare module '@zhin.js/core' {
|
|
|
27
28
|
}
|
|
28
29
|
export type RiddleSessionRow = Models['word_riddle_sessions'];
|
|
29
30
|
export declare function defineHostTables(db: {
|
|
30
|
-
define: (name: string, definition: Record<string, unknown
|
|
31
|
+
define: (name: string, definition: Record<string, unknown>, options?: {
|
|
32
|
+
readonly addColumns?: readonly string[];
|
|
33
|
+
}) => void;
|
|
31
34
|
}): void;
|
package/lib/models.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export function defineHostTables(db) {
|
|
2
2
|
db.define('word_riddle_sessions', {
|
|
3
3
|
id: { type: 'text', primary: true },
|
|
4
|
+
locale: { type: 'text', nullable: true },
|
|
4
5
|
adapter: { type: 'text', nullable: false },
|
|
5
6
|
endpoint: { type: 'text', nullable: false },
|
|
6
7
|
channel_type: { type: 'text', nullable: false },
|
|
@@ -19,6 +20,6 @@ export function defineHostTables(db) {
|
|
|
19
20
|
status: { type: 'text', default: 'active' },
|
|
20
21
|
updated_at: { type: 'bigint', default: 0 },
|
|
21
22
|
created_at: { type: 'bigint', default: 0 },
|
|
22
|
-
});
|
|
23
|
+
}, { addColumns: ['locale'] });
|
|
23
24
|
}
|
|
24
25
|
//# sourceMappingURL=models.js.map
|
package/lib/models.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAkCA,MAAM,UAAU,gBAAgB,CAC9B,EAAkI;IAElI,EAAE,CAAC,MAAM,CAAC,sBAAsB,EAAE;QAChC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACnC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;QACxC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC1C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC3C,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC7C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1C,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;QACvC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACtC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACvC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;QAC1C,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;KAC3C,EAAE,EAAE,UAAU,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjC,CAAC"}
|
package/lib/riddle-command.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
|
|
2
2
|
import type { SessionService } from './session-service.js';
|
|
3
|
+
export declare function getRiddleHelp(message?: Pick<GameMessageLike, 'locale' | 'formatCommand'>): string;
|
|
3
4
|
export declare const RIDDLE_HELP: string;
|
|
4
5
|
export declare function runRiddleCommand(services: SessionService, message: GameMessageLike, action: string): Promise<GameReply>;
|
package/lib/riddle-command.js
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatGameHelp, gameCommandFeedback, gameCommandHint, channelKey } from '@zhin.js/game-kit';
|
|
2
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
2
3
|
import { continueGame, startGame } from './game-flow.js';
|
|
3
4
|
import { riddleCount } from './riddles-catalog.js';
|
|
4
5
|
import { typeLabel } from './engine.js';
|
|
5
6
|
const counts = riddleCount();
|
|
6
|
-
|
|
7
|
-
'
|
|
8
|
-
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
''
|
|
16
|
-
'
|
|
17
|
-
|
|
7
|
+
const messages = createMessages({
|
|
8
|
+
counts: { 'zh-CN': '字谜 {chars} 题 · 成语 {idioms} 题', en: '{chars} character riddles · {idioms} idiom riddles' },
|
|
9
|
+
char: { 'zh-CN': '{command} — 字谜模式', en: '{command} — Chinese character riddles' },
|
|
10
|
+
idiom: { 'zh-CN': '{command} — 猜成语模式', en: '{command} — Chinese idiom riddles' },
|
|
11
|
+
instructions: { 'zh-CN': '进行中直接回复答案;连击加分,提示/失误会清零连击。', en: 'Reply with the answer during play. Streaks earn bonus points; hints and mistakes reset the streak.' },
|
|
12
|
+
active: { 'zh-CN': '进行中:{mode} · 得分 {score} · 连击 {streak}', en: 'Playing: {mode} · Score {score} · Streak {streak}' },
|
|
13
|
+
quit: { 'zh-CN': '已放弃猜谜。', en: 'You quit the riddle game.' },
|
|
14
|
+
});
|
|
15
|
+
export function getRiddleHelp(message = {}) {
|
|
16
|
+
const locale = message.locale ?? 'zh-CN';
|
|
17
|
+
const command = message.formatCommand?.('riddle');
|
|
18
|
+
return [formatGameHelp(message, { 'zh-CN': '🧩 猜谜(字谜 + 猜成语)', en: '🧩 Chinese Character and Idiom Riddles' }, 'riddle', ['start', 'continue', 'quit']),
|
|
19
|
+
messages(locale, 'counts', { chars: counts.char.toLocaleString(locale), idioms: counts.idiom.toLocaleString(locale) }),
|
|
20
|
+
...(command ? [messages(locale, 'char', { command: command + ' char' }), messages(locale, 'idiom', { command: command + ' idiom' })] : []),
|
|
21
|
+
messages(locale, 'instructions'),
|
|
22
|
+
].join('\n');
|
|
23
|
+
}
|
|
24
|
+
export const RIDDLE_HELP = getRiddleHelp();
|
|
18
25
|
function parseMode(action) {
|
|
19
26
|
if (action === 'char' || action === '字谜')
|
|
20
27
|
return 'char';
|
|
@@ -29,12 +36,12 @@ export async function runRiddleCommand(services, message, action) {
|
|
|
29
36
|
const userId = message.$sender.id;
|
|
30
37
|
if (!action || action === 'help') {
|
|
31
38
|
const active = await services.getActiveByChannel(ch);
|
|
32
|
-
const lines = [
|
|
39
|
+
const lines = [getRiddleHelp(message), ''];
|
|
33
40
|
if (active) {
|
|
34
|
-
lines.push(
|
|
41
|
+
lines.push(messages(active.locale ?? undefined, 'active', { mode: typeLabel(active.mode, active.locale ?? undefined), score: active.score, streak: active.streak }));
|
|
35
42
|
}
|
|
36
43
|
else {
|
|
37
|
-
lines.push('
|
|
44
|
+
lines.push(gameCommandFeedback(message, 'noGame'), gameCommandHint(message, 'riddle'));
|
|
38
45
|
}
|
|
39
46
|
return lines.join('\n');
|
|
40
47
|
}
|
|
@@ -47,10 +54,10 @@ export async function runRiddleCommand(services, message, action) {
|
|
|
47
54
|
if (action === 'quit' || action === '放弃') {
|
|
48
55
|
const row = await services.getActiveForUser(ch, userId);
|
|
49
56
|
if (!row)
|
|
50
|
-
return '
|
|
57
|
+
return gameCommandFeedback(message, 'noGame');
|
|
51
58
|
await services.updateSession(row.id, { status: 'aborted' });
|
|
52
|
-
return '
|
|
59
|
+
return messages(row.locale ?? undefined, 'quit');
|
|
53
60
|
}
|
|
54
|
-
return
|
|
61
|
+
return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getRiddleHelp(message);
|
|
55
62
|
}
|
|
56
63
|
//# sourceMappingURL=riddle-command.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"riddle-command.js","sourceRoot":"","sources":["../src/riddle-command.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"riddle-command.js","sourceRoot":"","sources":["../src/riddle-command.ts"],"names":[],"mappings":"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"}
|
package/lib/session-service.js
CHANGED
|
@@ -26,6 +26,7 @@ export class SessionService extends BaseSessionService {
|
|
|
26
26
|
const queue = pickRoundQueue(mode).map((r) => r.id);
|
|
27
27
|
const row = {
|
|
28
28
|
id: generateSessionId(),
|
|
29
|
+
locale: message.locale ?? 'zh-CN',
|
|
29
30
|
adapter: String(message.$adapter),
|
|
30
31
|
endpoint: message.$endpoint,
|
|
31
32
|
channel_type: message.$channel.type,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,iBAAiB,GAGlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAKvE,MAAM,UAAU,UAAU,CAAC,KAAkC;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IACzF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,kBAAoC;IACtE,YAAY,EAAkB;QAC5B,KAAK,CAAC,EAAsD,EAAE;YAC5D,MAAM,EAAE,QAAQ;YAChB,KAAK,EAAE,sBAAsB;YAC7B,UAAU,EAAE,CAAC,WAAW,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB,EAAE,IAAgB;QAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,GAAG,GAAqB;YAC5B,EAAE,EAAE,iBAAiB,EAAE;YACvB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YACjC,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;YACnC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC/B,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC;YAChC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YAC7B,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;YAC/D,IAAI;YACJ,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YAC5B,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;SAChB,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAAkB;IAC/C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAGD,MAAM,UAAU,eAAe,CAAC,OAAyB;IACvD,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;AACtC,CAAC"}
|
|
1
|
+
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,iBAAiB,GAGlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAKvE,MAAM,UAAU,UAAU,CAAC,KAAkC;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IACzF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,kBAAoC;IACtE,YAAY,EAAkB;QAC5B,KAAK,CAAC,EAAsD,EAAE;YAC5D,MAAM,EAAE,QAAQ;YAChB,KAAK,EAAE,sBAAsB;YAC7B,UAAU,EAAE,CAAC,WAAW,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB,EAAE,IAAgB;QAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,GAAG,GAAqB;YAC5B,EAAE,EAAE,iBAAiB,EAAE;YACvB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO;YACjC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YACjC,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;YACnC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC/B,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC;YAChC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YAC7B,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;YAC/D,IAAI;YACJ,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YAC5B,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;SAChB,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAAkB;IAC/C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAGD,MAAM,UAAU,eAAe,CAAC,OAAyB;IACvD,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;AACtC,CAAC"}
|
package/lib/view.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
1
2
|
import { buildChoiceKeyboard } from '@zhin.js/game-kit';
|
|
2
3
|
import { getRiddleById, RIDDLE_PREFIX, typeLabel } from './engine.js';
|
|
3
4
|
import { currentRiddleId, parseQueue } from './session-service.js';
|
|
@@ -8,33 +9,33 @@ export function buildRiddleView(session, eventLines = [], channelType) {
|
|
|
8
9
|
const riddleId = currentRiddleId(session);
|
|
9
10
|
const entry = riddleId ? getRiddleById(riddleId) : undefined;
|
|
10
11
|
const lines = [
|
|
11
|
-
`🧩 **${typeLabel(session.mode)}**`,
|
|
12
|
+
`🧩 **${typeLabel(session.mode, session.locale ?? undefined)}**`,
|
|
12
13
|
'',
|
|
13
|
-
|
|
14
|
+
messages(session.locale ?? undefined, 'text1', { p0: Math.min(session.index + 1, queue.length), p1: queue.length, p2: session.score, p3: session.streak, p4: session.best_streak }),
|
|
14
15
|
];
|
|
15
16
|
if (terminal) {
|
|
16
|
-
lines.push('', '
|
|
17
|
+
lines.push('', messages(session.locale ?? undefined, 'text2'), messages(session.locale ?? undefined, 'text3', { p0: session.score }));
|
|
17
18
|
}
|
|
18
19
|
else if (entry) {
|
|
19
20
|
lines.push('', `❓ ${entry.question}`);
|
|
20
21
|
if (session.wrong_count > 0) {
|
|
21
|
-
lines.push(
|
|
22
|
+
lines.push(messages(session.locale ?? undefined, 'text4', { p0: session.wrong_count, p1: MAX_WRONG }));
|
|
22
23
|
}
|
|
23
|
-
lines.push('', session.mode === 'char' ? '
|
|
24
|
+
lines.push('', session.mode === 'char' ? messages(session.locale ?? undefined, 'text5') : messages(session.locale ?? undefined, 'text6'));
|
|
24
25
|
}
|
|
25
26
|
if (eventLines.length)
|
|
26
27
|
lines.push('', ...eventLines);
|
|
27
28
|
if (!entry && !terminal)
|
|
28
|
-
return '
|
|
29
|
+
return messages(session.locale ?? undefined, 'text7');
|
|
29
30
|
const choices = terminal
|
|
30
31
|
? [
|
|
31
|
-
{ id: 'restart_char', label:
|
|
32
|
-
{ id: 'restart_idiom', label:
|
|
32
|
+
{ id: 'restart_char', label: messages(session.locale ?? undefined, 'text8'), style: 'primary', keepEnabledWhenTerminal: true },
|
|
33
|
+
{ id: 'restart_idiom', label: messages(session.locale ?? undefined, 'text9'), style: 'primary', keepEnabledWhenTerminal: true },
|
|
33
34
|
]
|
|
34
35
|
: [
|
|
35
|
-
{ id: 'hint', label:
|
|
36
|
-
{ id: 'skip', label:
|
|
37
|
-
{ id: 'quit', label:
|
|
36
|
+
{ id: 'hint', label: messages(session.locale ?? undefined, 'text10'), style: 'secondary' },
|
|
37
|
+
{ id: 'skip', label: messages(session.locale ?? undefined, 'text11'), style: 'secondary' },
|
|
38
|
+
{ id: 'quit', label: messages(session.locale ?? undefined, 'text12'), style: 'danger' },
|
|
38
39
|
];
|
|
39
40
|
return buildChoiceKeyboard({
|
|
40
41
|
gamePrefix: RIDDLE_PREFIX,
|
|
@@ -43,10 +44,25 @@ export function buildRiddleView(session, eventLines = [], channelType) {
|
|
|
43
44
|
choices,
|
|
44
45
|
terminal,
|
|
45
46
|
buttonsPerRow: terminal ? 2 : 3,
|
|
46
|
-
fallbackHint:
|
|
47
|
+
fallbackHint: messages(session.locale ?? undefined, 'text13'),
|
|
47
48
|
interactionProfile: terminal ? 'terminal' : 'gameplay',
|
|
48
49
|
channelType,
|
|
49
50
|
});
|
|
50
51
|
}
|
|
51
52
|
export { MAX_WRONG };
|
|
53
|
+
const messages = createMessages({
|
|
54
|
+
text1: { 'zh-CN': "进度 {p0}/{p1} · 得分 **{p2}** · 连击 **{p3}**(最佳 {p4})", en: "Progress {p0}/{p1} · Score **{p2}** · Streak **{p3}** (best {p4})" },
|
|
55
|
+
text2: { 'zh-CN': "🎊 **本轮题目已全部完成!**", en: "🎊 **All riddles completed!**" },
|
|
56
|
+
text3: { 'zh-CN': "最终得分:**{p0}**", en: "Final score: **{p0}**" },
|
|
57
|
+
text4: { 'zh-CN': "⚠️ 本题失误 {p0}/{p1}", en: "⚠️ Mistakes on this riddle: {p0}/{p1}" },
|
|
58
|
+
text5: { 'zh-CN': "请回复一个汉字。", en: "Reply with one Chinese character." },
|
|
59
|
+
text6: { 'zh-CN': "请回复四字成语。", en: "Reply with a four-character Chinese idiom." },
|
|
60
|
+
text7: { 'zh-CN': "题目加载失败,请重新开始。", en: "The riddle could not be loaded. Please start again." },
|
|
61
|
+
text8: { 'zh-CN': "🔤 再来字谜", en: "🔤 More character riddles" },
|
|
62
|
+
text9: { 'zh-CN': "📜 再来成语", en: "📜 More idiom riddles" },
|
|
63
|
+
text10: { 'zh-CN': "💡 提示", en: "💡 Hint" },
|
|
64
|
+
text11: { 'zh-CN': "⏭️ 跳过", en: "⏭️ Skip" },
|
|
65
|
+
text12: { 'zh-CN': "🏳️ 结束", en: "🏳️ End" },
|
|
66
|
+
text13: { 'zh-CN': "回复答案,或 1提示 2跳过 3结束", en: "Reply with your answer, or 1 Hint · 2 Skip · 3 End" },
|
|
67
|
+
});
|
|
52
68
|
//# sourceMappingURL=view.js.map
|
package/lib/view.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEnE,MAAM,SAAS,GAAG,CAAC,CAAC;AAEpB,MAAM,UAAU,eAAe,CAC7B,OAAyB,EACzB,aAAuB,EAAE,EACzB,WAAoB;IAEpB,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC;IAC7C,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE7D,MAAM,KAAK,GAAG;QACZ,QAAQ,SAAS,CAAC,OAAO,CAAC,IAAwB,CAAC,IAAI;
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { defineGameCommandAliasMiddleware, isRiddleAction, messageFromCommandInput, normalizeRiddleAction, } from '@zhin.js/game-kit';
|
|
3
|
-
import {
|
|
3
|
+
import { getRiddleHelp, runRiddleCommand } from "../../lib/riddle-command.js";
|
|
4
4
|
import { resolveGameServices } from "../../lib/runtime-store.js";
|
|
5
5
|
export default defineGameCommandAliasMiddleware({
|
|
6
6
|
aliases: ['猜谜', 'riddle'],
|
|
7
7
|
async run(action, input, context) {
|
|
8
|
+
const message = messageFromCommandInput(input, {
|
|
9
|
+
formatCommand: (path) => context.input.formatCommand?.(path, context.owner.id),
|
|
10
|
+
});
|
|
8
11
|
const normalized = normalizeRiddleAction(String(action ?? ''));
|
|
9
12
|
if (normalized === 'help')
|
|
10
|
-
return
|
|
13
|
+
return getRiddleHelp(message);
|
|
11
14
|
// action 无法识别:放行给后续中间件,避免劫持普通聊天
|
|
12
15
|
if (!isRiddleAction(normalized))
|
|
13
16
|
return null;
|
|
14
17
|
const services = resolveGameServices(context);
|
|
15
|
-
const message = messageFromCommandInput(input);
|
|
16
18
|
return runRiddleCommand(services, message, normalized);
|
|
17
19
|
},
|
|
18
20
|
});
|
|
@@ -4,18 +4,20 @@ import {
|
|
|
4
4
|
messageFromCommandInput,
|
|
5
5
|
normalizeRiddleAction,
|
|
6
6
|
} from '@zhin.js/game-kit';
|
|
7
|
-
import {
|
|
7
|
+
import { getRiddleHelp, runRiddleCommand } from '../../src/riddle-command.js';
|
|
8
8
|
import { resolveGameServices } from '../../src/runtime-store.js';
|
|
9
9
|
|
|
10
10
|
export default defineGameCommandAliasMiddleware({
|
|
11
11
|
aliases: ['猜谜', 'riddle'],
|
|
12
12
|
async run(action, input, context) {
|
|
13
|
+
const message = messageFromCommandInput(input, {
|
|
14
|
+
formatCommand: (path) => context.input.formatCommand?.(path, context.owner.id),
|
|
15
|
+
});
|
|
13
16
|
const normalized = normalizeRiddleAction(String(action ?? ''));
|
|
14
|
-
if (normalized === 'help') return
|
|
17
|
+
if (normalized === 'help') return getRiddleHelp(message);
|
|
15
18
|
// action 无法识别:放行给后续中间件,避免劫持普通聊天
|
|
16
19
|
if (!isRiddleAction(normalized)) return null;
|
|
17
20
|
const services = resolveGameServices(context);
|
|
18
|
-
const message = messageFromCommandInput(input);
|
|
19
21
|
return runRiddleCommand(services, message, normalized);
|
|
20
22
|
},
|
|
21
23
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-word-riddle",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
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.52",
|
|
28
|
+
"@zhin.js/game-kit": "1.1.17"
|
|
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.17"
|
|
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.11",
|
|
71
|
+
"@zhin.js/middleware": "^1.1.10",
|
|
72
|
+
"zhin.js": "^1.1.17"
|
|
73
73
|
},
|
|
74
74
|
"peerDependenciesMeta": {
|
|
75
75
|
"@zhin.js/command": {
|
package/plugin.js
CHANGED
|
@@ -15,6 +15,10 @@ export default defineGamePlugin({
|
|
|
15
15
|
displayName: 'Word Riddle',
|
|
16
16
|
},
|
|
17
17
|
game: {
|
|
18
|
+
commandPath: 'riddle',
|
|
19
|
+
titleI18n: { en: 'Word Riddle' },
|
|
20
|
+
descriptionI18n: { en: 'Solve Chinese character and idiom riddles' },
|
|
21
|
+
quickStartI18n: { en: 'start' },
|
|
18
22
|
id: 'riddle',
|
|
19
23
|
title: '猜谜',
|
|
20
24
|
icon: '🧩',
|
package/src/engine.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createMessages, type Locale } from 'zhin.js/i18n';
|
|
1
2
|
import {
|
|
2
3
|
getRiddleById,
|
|
3
4
|
type RiddleEntry,
|
|
@@ -23,8 +24,13 @@ export function checkAnswer(entry: RiddleEntry, raw: string): boolean {
|
|
|
23
24
|
return answersFor(entry).some((x) => x === a);
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export function typeLabel(type: RiddleType): string {
|
|
27
|
-
return type === 'char' ? '
|
|
27
|
+
export function typeLabel(type: RiddleType, locale?: Locale): string {
|
|
28
|
+
return type === 'char' ? messages(locale, 'text1') : messages(locale, 'text2');
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export { getRiddleById };
|
|
32
|
+
|
|
33
|
+
const messages = createMessages({
|
|
34
|
+
text1: { 'zh-CN': "字谜", en: "Chinese Character Riddles" },
|
|
35
|
+
text2: { 'zh-CN': "猜成语", en: "Chinese Idiom Riddles" },
|
|
36
|
+
});
|
package/src/game-flow.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createMessages, resolveLocale } from 'zhin.js/i18n';
|
|
1
2
|
import type { GameMessageLike, GameReply } from '@zhin.js/game-kit';
|
|
2
3
|
import {
|
|
3
4
|
answersFor,
|
|
@@ -50,11 +51,12 @@ export async function startGame(
|
|
|
50
51
|
): Promise<GameReply | undefined> {
|
|
51
52
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
52
53
|
const active = await services.getActiveByChannel(ch);
|
|
54
|
+
const locale = resolveLocale(active ? active.locale : message.locale);
|
|
53
55
|
if (active) {
|
|
54
56
|
if (active.player_id === message.$sender.id) {
|
|
55
|
-
return
|
|
57
|
+
return messages(locale, 'text1', { p0: typeLabel(active.mode as RiddleType, locale) });
|
|
56
58
|
}
|
|
57
|
-
return
|
|
59
|
+
return messages(locale, 'text2', { p0: active.player_name });
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
const session = await services.createSession(message, mode);
|
|
@@ -69,7 +71,8 @@ export async function continueGame(
|
|
|
69
71
|
`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`,
|
|
70
72
|
message.$sender.id,
|
|
71
73
|
);
|
|
72
|
-
|
|
74
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
75
|
+
if (!session) return messages(locale, 'text3');
|
|
73
76
|
return renderView(message, session);
|
|
74
77
|
}
|
|
75
78
|
|
|
@@ -80,6 +83,7 @@ export async function processAnswerText(
|
|
|
80
83
|
): Promise<GameReply | null> {
|
|
81
84
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
82
85
|
const session = await services.getActiveForUser(ch, message.$sender.id);
|
|
86
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
83
87
|
if (!session || session.status !== 'active') return null;
|
|
84
88
|
|
|
85
89
|
const riddleId = currentRiddleId(session);
|
|
@@ -89,7 +93,7 @@ export async function processAnswerText(
|
|
|
89
93
|
// 格式不合规(字数与答案不符)只提示、不扣失误:避免闲聊(「好的」「谢谢」)被累计判负
|
|
90
94
|
const normalized = normalizeAnswer(raw);
|
|
91
95
|
if (!answersFor(entry).some((a) => a.length === normalized.length)) {
|
|
92
|
-
return
|
|
96
|
+
return messages(locale, 'text4', { p0: entry.answer.length });
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
if (checkAnswer(entry, raw)) {
|
|
@@ -104,8 +108,8 @@ export async function processAnswerText(
|
|
|
104
108
|
const after = await advanceQuestion(services, (await services.getById(session.id))!);
|
|
105
109
|
const explain = entry.explanation ? `\n📖 ${entry.explanation}` : '';
|
|
106
110
|
return renderView(message, after, [
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
messages(locale, 'text5', { p0: entry.answer, p1: explain }),
|
|
112
|
+
messages(locale, 'text6', { p0: 10 + Math.min(streak, 5) }),
|
|
109
113
|
]);
|
|
110
114
|
}
|
|
111
115
|
|
|
@@ -114,14 +118,14 @@ export async function processAnswerText(
|
|
|
114
118
|
await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
|
|
115
119
|
const after = await advanceQuestion(services, (await services.getById(session.id))!);
|
|
116
120
|
return renderView(message, after, [
|
|
117
|
-
|
|
118
|
-
'
|
|
121
|
+
messages(locale, 'text7', { p0: entry.answer }),
|
|
122
|
+
messages(locale, 'text8'),
|
|
119
123
|
]);
|
|
120
124
|
}
|
|
121
125
|
|
|
122
126
|
await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
|
|
123
127
|
const updated = (await services.getById(session.id))!;
|
|
124
|
-
return renderView(message, updated, [
|
|
128
|
+
return renderView(message, updated, [messages(locale, 'text9')]);
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
export async function handleChoice(
|
|
@@ -131,8 +135,9 @@ export async function handleChoice(
|
|
|
131
135
|
choiceId: string,
|
|
132
136
|
): Promise<GameReply | null> {
|
|
133
137
|
const session = await services.getById(sessionId);
|
|
134
|
-
|
|
135
|
-
if (session
|
|
138
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
139
|
+
if (!session) return messages(locale, 'text10');
|
|
140
|
+
if (session.player_id !== message.$sender.id) return messages(locale, 'text11');
|
|
136
141
|
|
|
137
142
|
if (choiceId === 'restart_char') {
|
|
138
143
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
@@ -143,19 +148,19 @@ export async function handleChoice(
|
|
|
143
148
|
return (await startGame(services, message, 'idiom')) ?? null;
|
|
144
149
|
}
|
|
145
150
|
|
|
146
|
-
if (session.status !== 'active') return '
|
|
151
|
+
if (session.status !== 'active') return messages(locale, 'text12');
|
|
147
152
|
|
|
148
153
|
const riddleId = currentRiddleId(session);
|
|
149
154
|
const entry = riddleId ? getRiddleById(riddleId) : undefined;
|
|
150
|
-
if (!entry) return '
|
|
155
|
+
if (!entry) return messages(locale, 'text13');
|
|
151
156
|
|
|
152
157
|
if (choiceId === 'hint') {
|
|
153
|
-
const hint = entry.hint ??
|
|
158
|
+
const hint = entry.hint ?? messages(locale, 'text14', { p0: entry.answer.length });
|
|
154
159
|
await services.updateSession(session.id, { hints_used: session.hints_used + 1, streak: 0 });
|
|
155
160
|
const updated = (await services.getById(session.id))!;
|
|
156
161
|
return renderView(message, updated, [
|
|
157
|
-
|
|
158
|
-
'
|
|
162
|
+
messages(locale, 'text15', { p0: hint }),
|
|
163
|
+
messages(locale, 'text16'),
|
|
159
164
|
]);
|
|
160
165
|
}
|
|
161
166
|
|
|
@@ -163,16 +168,38 @@ export async function handleChoice(
|
|
|
163
168
|
await services.updateSession(session.id, { streak: 0 });
|
|
164
169
|
const after = await advanceQuestion(services, session);
|
|
165
170
|
return renderView(message, after, [
|
|
166
|
-
|
|
171
|
+
messages(locale, 'text17', { p0: entry.answer }),
|
|
167
172
|
]);
|
|
168
173
|
}
|
|
169
174
|
|
|
170
175
|
if (choiceId === 'quit') {
|
|
171
176
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
172
|
-
return '
|
|
177
|
+
return messages(locale, 'text18');
|
|
173
178
|
}
|
|
174
179
|
|
|
175
|
-
return '
|
|
180
|
+
return messages(locale, 'text19');
|
|
176
181
|
}
|
|
177
182
|
|
|
178
183
|
export { RIDDLE_PREFIX };
|
|
184
|
+
|
|
185
|
+
const messages = createMessages({
|
|
186
|
+
text1: { 'zh-CN': "你已有进行中的猜谜({p0}),请使用当前对局的操作入口继续。", en: "You already have an active riddle game ({p0}). Continue using its controls." },
|
|
187
|
+
text2: { 'zh-CN': "本频道 {p0} 正在猜谜。", en: "{p0} is solving riddles in this channel." },
|
|
188
|
+
text3: { 'zh-CN': "你没有进行中的猜谜。", en: "You have no active riddle game." },
|
|
189
|
+
text4: { 'zh-CN': "本题答案应为 {p0} 个字(这条不算失误)。", en: "The answer has {p0} characters (this does not count as a mistake)." },
|
|
190
|
+
text5: { 'zh-CN': "✅ 正确!答案:**{p0}**{p1}", en: "✅ Correct! Answer: **{p0}**{p1}" },
|
|
191
|
+
text6: { 'zh-CN': "+{p0} 分", en: "+{p0} points" },
|
|
192
|
+
text7: { 'zh-CN': "❌ 本题答案:**{p0}**", en: "❌ Answer: **{p0}**" },
|
|
193
|
+
text8: { 'zh-CN': "失误过多,自动下一题。", en: "Too many mistakes. Moving to the next riddle." },
|
|
194
|
+
text9: { 'zh-CN': "❌ 不对,再想想!", en: "❌ Not quite. Try again!" },
|
|
195
|
+
text10: { 'zh-CN': "会话不存在。", en: "This game no longer exists." },
|
|
196
|
+
text11: { 'zh-CN': "这是别人的猜谜。", en: "This riddle game belongs to another player." },
|
|
197
|
+
text12: { 'zh-CN': "本轮已结束。", en: "This round has ended." },
|
|
198
|
+
text13: { 'zh-CN': "题目丢失。", en: "The riddle is unavailable." },
|
|
199
|
+
text14: { 'zh-CN': "答案共 {p0} 个字", en: "The answer has {p0} characters" },
|
|
200
|
+
text15: { 'zh-CN': "💡 提示:{p0}", en: "💡 Hint: {p0}" },
|
|
201
|
+
text16: { 'zh-CN': "(连击清零)", en: "(Streak reset)" },
|
|
202
|
+
text17: { 'zh-CN': "⏭️ 跳过,答案:**{p0}**", en: "⏭️ Skipped. Answer: **{p0}**" },
|
|
203
|
+
text18: { 'zh-CN': "已结束猜谜。", en: "The riddle game has ended." },
|
|
204
|
+
text19: { 'zh-CN': "未知操作。", en: "Unknown action." },
|
|
205
|
+
});
|
package/src/models.ts
CHANGED
|
@@ -6,6 +6,7 @@ declare module '@zhin.js/core' {
|
|
|
6
6
|
interface Models {
|
|
7
7
|
word_riddle_sessions: {
|
|
8
8
|
id: string;
|
|
9
|
+
locale?: 'zh-CN' | 'en' | null;
|
|
9
10
|
adapter: string;
|
|
10
11
|
endpoint: string;
|
|
11
12
|
channel_type: string;
|
|
@@ -32,10 +33,11 @@ export type RiddleSessionRow = Models['word_riddle_sessions'];
|
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
export function defineHostTables(
|
|
35
|
-
db: { define: (name: string, definition: Record<string, unknown
|
|
36
|
+
db: { define: (name: string, definition: Record<string, unknown>, options?: { readonly addColumns?: readonly string[] }) => void },
|
|
36
37
|
): void {
|
|
37
38
|
db.define('word_riddle_sessions', {
|
|
38
39
|
id: { type: 'text', primary: true },
|
|
40
|
+
locale: { type: 'text', nullable: true },
|
|
39
41
|
adapter: { type: 'text', nullable: false },
|
|
40
42
|
endpoint: { type: 'text', nullable: false },
|
|
41
43
|
channel_type: { type: 'text', nullable: false },
|
|
@@ -54,5 +56,5 @@ export function defineHostTables(
|
|
|
54
56
|
status: { type: 'text', default: 'active' },
|
|
55
57
|
updated_at: { type: 'bigint', default: 0 },
|
|
56
58
|
created_at: { type: 'bigint', default: 0 },
|
|
57
|
-
});
|
|
59
|
+
}, { addColumns: ['locale'] });
|
|
58
60
|
}
|
package/src/riddle-command.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type GameMessageLike,
|
|
4
|
-
type GameReply,
|
|
5
|
-
} from '@zhin.js/game-kit';
|
|
1
|
+
import { formatGameHelp, gameCommandFeedback, gameCommandHint, channelKey, type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
|
|
2
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
6
3
|
import { continueGame, startGame } from './game-flow.js';
|
|
7
4
|
import { riddleCount, type RiddleType } from './riddles-catalog.js';
|
|
8
5
|
|
|
@@ -11,18 +8,26 @@ import type { SessionService } from './session-service.js';
|
|
|
11
8
|
|
|
12
9
|
const counts = riddleCount();
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
|
|
12
|
+
const messages = createMessages({
|
|
13
|
+
counts: { 'zh-CN': '字谜 {chars} 题 · 成语 {idioms} 题', en: '{chars} character riddles · {idioms} idiom riddles' },
|
|
14
|
+
char: { 'zh-CN': '{command} — 字谜模式', en: '{command} — Chinese character riddles' },
|
|
15
|
+
idiom: { 'zh-CN': '{command} — 猜成语模式', en: '{command} — Chinese idiom riddles' },
|
|
16
|
+
instructions: { 'zh-CN': '进行中直接回复答案;连击加分,提示/失误会清零连击。', en: 'Reply with the answer during play. Streaks earn bonus points; hints and mistakes reset the streak.' },
|
|
17
|
+
active: { 'zh-CN': '进行中:{mode} · 得分 {score} · 连击 {streak}', en: 'Playing: {mode} · Score {score} · Streak {streak}' },
|
|
18
|
+
quit: { 'zh-CN': '已放弃猜谜。', en: 'You quit the riddle game.' },
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export function getRiddleHelp(message: Pick<GameMessageLike, 'locale' | 'formatCommand'> = {}): string {
|
|
22
|
+
const locale = message.locale ?? 'zh-CN';
|
|
23
|
+
const command = message.formatCommand?.('riddle');
|
|
24
|
+
return [formatGameHelp(message, { 'zh-CN': '🧩 猜谜(字谜 + 猜成语)', en: '🧩 Chinese Character and Idiom Riddles' }, 'riddle', ['start', 'continue', 'quit']),
|
|
25
|
+
messages(locale, 'counts', { chars: counts.char.toLocaleString(locale), idioms: counts.idiom.toLocaleString(locale) }),
|
|
26
|
+
...(command ? [messages(locale, 'char', { command: command + ' char' }), messages(locale, 'idiom', { command: command + ' idiom' })] : []),
|
|
27
|
+
messages(locale, 'instructions'),
|
|
28
|
+
].join('\n');
|
|
29
|
+
}
|
|
30
|
+
export const RIDDLE_HELP = getRiddleHelp();
|
|
26
31
|
|
|
27
32
|
function parseMode(action: string): RiddleType | null {
|
|
28
33
|
if (action === 'char' || action === '字谜') return 'char';
|
|
@@ -41,11 +46,11 @@ export async function runRiddleCommand(
|
|
|
41
46
|
|
|
42
47
|
if (!action || action === 'help') {
|
|
43
48
|
const active = await services.getActiveByChannel(ch);
|
|
44
|
-
const lines = [
|
|
49
|
+
const lines = [getRiddleHelp(message), ''];
|
|
45
50
|
if (active) {
|
|
46
|
-
lines.push(
|
|
51
|
+
lines.push(messages(active.locale ?? undefined, 'active', { mode: typeLabel(active.mode as RiddleType, active.locale ?? undefined), score: active.score, streak: active.streak }));
|
|
47
52
|
} else {
|
|
48
|
-
lines.push('
|
|
53
|
+
lines.push(gameCommandFeedback(message, 'noGame'), gameCommandHint(message, 'riddle'));
|
|
49
54
|
}
|
|
50
55
|
return lines.join('\n');
|
|
51
56
|
}
|
|
@@ -59,10 +64,10 @@ export async function runRiddleCommand(
|
|
|
59
64
|
|
|
60
65
|
if (action === 'quit' || action === '放弃') {
|
|
61
66
|
const row = await services.getActiveForUser(ch, userId);
|
|
62
|
-
if (!row) return '
|
|
67
|
+
if (!row) return gameCommandFeedback(message, 'noGame');
|
|
63
68
|
await services.updateSession(row.id, { status: 'aborted' });
|
|
64
|
-
return '
|
|
69
|
+
return messages(row.locale ?? undefined, 'quit');
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
return
|
|
72
|
+
return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getRiddleHelp(message);
|
|
68
73
|
}
|
package/src/session-service.ts
CHANGED
|
@@ -36,6 +36,7 @@ export class SessionService extends BaseSessionService<RiddleSessionRow> {
|
|
|
36
36
|
const queue = pickRoundQueue(mode).map((r) => r.id);
|
|
37
37
|
const row: RiddleSessionRow = {
|
|
38
38
|
id: generateSessionId(),
|
|
39
|
+
locale: message.locale ?? 'zh-CN',
|
|
39
40
|
adapter: String(message.$adapter),
|
|
40
41
|
endpoint: message.$endpoint,
|
|
41
42
|
channel_type: message.$channel.type,
|
package/src/view.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
1
2
|
import { buildChoiceKeyboard } from '@zhin.js/game-kit';
|
|
2
3
|
import type { SendContent } from '@zhin.js/core/runtime';
|
|
3
4
|
import { getRiddleById, RIDDLE_PREFIX, typeLabel } from './engine.js';
|
|
@@ -17,34 +18,34 @@ export function buildRiddleView(
|
|
|
17
18
|
const entry = riddleId ? getRiddleById(riddleId) : undefined;
|
|
18
19
|
|
|
19
20
|
const lines = [
|
|
20
|
-
`🧩 **${typeLabel(session.mode as 'char' | 'idiom')}**`,
|
|
21
|
+
`🧩 **${typeLabel(session.mode as 'char' | 'idiom', session.locale ?? undefined)}**`,
|
|
21
22
|
'',
|
|
22
|
-
|
|
23
|
+
messages(session.locale ?? undefined, 'text1', { p0: Math.min(session.index + 1, queue.length), p1: queue.length, p2: session.score, p3: session.streak, p4: session.best_streak }),
|
|
23
24
|
];
|
|
24
25
|
|
|
25
26
|
if (terminal) {
|
|
26
|
-
lines.push('', '
|
|
27
|
+
lines.push('', messages(session.locale ?? undefined, 'text2'), messages(session.locale ?? undefined, 'text3', { p0: session.score }));
|
|
27
28
|
} else if (entry) {
|
|
28
29
|
lines.push('', `❓ ${entry.question}`);
|
|
29
30
|
if (session.wrong_count > 0) {
|
|
30
|
-
lines.push(
|
|
31
|
+
lines.push(messages(session.locale ?? undefined, 'text4', { p0: session.wrong_count, p1: MAX_WRONG }));
|
|
31
32
|
}
|
|
32
|
-
lines.push('', session.mode === 'char' ? '
|
|
33
|
+
lines.push('', session.mode === 'char' ? messages(session.locale ?? undefined, 'text5') : messages(session.locale ?? undefined, 'text6'));
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
if (eventLines.length) lines.push('', ...eventLines);
|
|
36
37
|
|
|
37
|
-
if (!entry && !terminal) return '
|
|
38
|
+
if (!entry && !terminal) return messages(session.locale ?? undefined, 'text7');
|
|
38
39
|
|
|
39
40
|
const choices = terminal
|
|
40
41
|
? [
|
|
41
|
-
{ id: 'restart_char', label:
|
|
42
|
-
{ id: 'restart_idiom', label:
|
|
42
|
+
{ id: 'restart_char', label: messages(session.locale ?? undefined, 'text8'), style: 'primary' as const, keepEnabledWhenTerminal: true },
|
|
43
|
+
{ id: 'restart_idiom', label: messages(session.locale ?? undefined, 'text9'), style: 'primary' as const, keepEnabledWhenTerminal: true },
|
|
43
44
|
]
|
|
44
45
|
: [
|
|
45
|
-
{ id: 'hint', label:
|
|
46
|
-
{ id: 'skip', label:
|
|
47
|
-
{ id: 'quit', label:
|
|
46
|
+
{ id: 'hint', label: messages(session.locale ?? undefined, 'text10'), style: 'secondary' as const },
|
|
47
|
+
{ id: 'skip', label: messages(session.locale ?? undefined, 'text11'), style: 'secondary' as const },
|
|
48
|
+
{ id: 'quit', label: messages(session.locale ?? undefined, 'text12'), style: 'danger' as const },
|
|
48
49
|
];
|
|
49
50
|
|
|
50
51
|
return buildChoiceKeyboard({
|
|
@@ -54,10 +55,26 @@ export function buildRiddleView(
|
|
|
54
55
|
choices,
|
|
55
56
|
terminal,
|
|
56
57
|
buttonsPerRow: terminal ? 2 : 3,
|
|
57
|
-
fallbackHint:
|
|
58
|
+
fallbackHint: messages(session.locale ?? undefined, 'text13'),
|
|
58
59
|
interactionProfile: terminal ? 'terminal' : 'gameplay',
|
|
59
60
|
channelType,
|
|
60
61
|
});
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
export { MAX_WRONG };
|
|
65
|
+
|
|
66
|
+
const messages = createMessages({
|
|
67
|
+
text1: { 'zh-CN': "进度 {p0}/{p1} · 得分 **{p2}** · 连击 **{p3}**(最佳 {p4})", en: "Progress {p0}/{p1} · Score **{p2}** · Streak **{p3}** (best {p4})" },
|
|
68
|
+
text2: { 'zh-CN': "🎊 **本轮题目已全部完成!**", en: "🎊 **All riddles completed!**" },
|
|
69
|
+
text3: { 'zh-CN': "最终得分:**{p0}**", en: "Final score: **{p0}**" },
|
|
70
|
+
text4: { 'zh-CN': "⚠️ 本题失误 {p0}/{p1}", en: "⚠️ Mistakes on this riddle: {p0}/{p1}" },
|
|
71
|
+
text5: { 'zh-CN': "请回复一个汉字。", en: "Reply with one Chinese character." },
|
|
72
|
+
text6: { 'zh-CN': "请回复四字成语。", en: "Reply with a four-character Chinese idiom." },
|
|
73
|
+
text7: { 'zh-CN': "题目加载失败,请重新开始。", en: "The riddle could not be loaded. Please start again." },
|
|
74
|
+
text8: { 'zh-CN': "🔤 再来字谜", en: "🔤 More character riddles" },
|
|
75
|
+
text9: { 'zh-CN': "📜 再来成语", en: "📜 More idiom riddles" },
|
|
76
|
+
text10: { 'zh-CN': "💡 提示", en: "💡 Hint" },
|
|
77
|
+
text11: { 'zh-CN': "⏭️ 跳过", en: "⏭️ Skip" },
|
|
78
|
+
text12: { 'zh-CN': "🏳️ 结束", en: "🏳️ End" },
|
|
79
|
+
text13: { 'zh-CN': "回复答案,或 1提示 2跳过 3结束", en: "Reply with your answer, or 1 Hint · 2 Skip · 3 End" },
|
|
80
|
+
});
|