@zhin.js/plugin-guess-number 1.1.14 → 1.1.16
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/guess/[[action]]/index.js +4 -4
- package/commands/guess/[[action]]/index.ts +4 -4
- package/lib/engine.d.ts +2 -1
- package/lib/engine.js +8 -3
- package/lib/engine.js.map +1 -1
- package/lib/game-flow.js +23 -9
- package/lib/game-flow.js.map +1 -1
- package/lib/guess-command.d.ts +1 -0
- package/lib/guess-command.js +15 -15
- package/lib/guess-command.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/session-service.js +1 -0
- package/lib/session-service.js.map +1 -1
- package/lib/view.js +22 -9
- package/lib/view.js.map +1 -1
- package/middlewares/guess-alias/index.js +5 -3
- package/middlewares/guess-alias/index.ts +5 -3
- package/package.json +7 -7
- package/plugin.js +4 -0
- package/src/engine.ts +9 -3
- package/src/game-flow.ts +24 -9
- package/src/guess-command.ts +18 -19
- package/src/models.ts +4 -2
- package/src/session-service.ts +1 -0
- package/src/view.ts +24 -10
|
@@ -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, normalizeGuessAction } from '@zhin.js/game-kit';
|
|
4
|
-
import {
|
|
4
|
+
import { getGuessHelp, runGuessCommand } from "../../../lib/guess-command.js";
|
|
5
5
|
import { resolveGameServices } from "../../../lib/runtime-store.js";
|
|
6
6
|
export default defineCommand({
|
|
7
7
|
description: 'Guess Number',
|
|
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 = normalizeGuessAction(String(params.action ?? ''));
|
|
11
11
|
if (!action || action === 'help')
|
|
12
|
-
return
|
|
12
|
+
return getGuessHelp({ locale, formatCommand });
|
|
13
13
|
const services = resolveGameServices({ use });
|
|
14
|
-
const message = messageFromCommandInput(input);
|
|
14
|
+
const message = messageFromCommandInput(input, { locale, formatCommand });
|
|
15
15
|
return runGuessCommand(services, message, action);
|
|
16
16
|
},
|
|
17
17
|
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { defineCommand } from 'zhin.js/command';
|
|
2
2
|
import { messageFromCommandInput, normalizeGuessAction } from '@zhin.js/game-kit';
|
|
3
|
-
import {
|
|
3
|
+
import { getGuessHelp, runGuessCommand } from '../../../src/guess-command.js';
|
|
4
4
|
import { resolveGameServices } from '../../../src/runtime-store.js';
|
|
5
5
|
|
|
6
6
|
export default defineCommand({
|
|
7
7
|
description: 'Guess Number',
|
|
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 = normalizeGuessAction(String(params.action ?? ''));
|
|
11
|
-
if (!action || action === 'help') return
|
|
11
|
+
if (!action || action === 'help') return getGuessHelp({ locale, formatCommand });
|
|
12
12
|
const services = resolveGameServices({ use });
|
|
13
|
-
const message = messageFromCommandInput(input);
|
|
13
|
+
const message = messageFromCommandInput(input, { locale, formatCommand });
|
|
14
14
|
return runGuessCommand(services, message, action);
|
|
15
15
|
},
|
|
16
16
|
});
|
package/lib/engine.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Locale } from 'zhin.js/i18n';
|
|
1
2
|
export declare const GUESS_PREFIX = "guess";
|
|
2
3
|
export declare const MIN = 1;
|
|
3
4
|
export declare const MAX = 100;
|
|
@@ -5,4 +6,4 @@ export declare const MAX_ATTEMPTS = 7;
|
|
|
5
6
|
export type GuessResult = 'win' | 'low' | 'high' | 'invalid';
|
|
6
7
|
export declare function newSecret(): number;
|
|
7
8
|
export declare function evaluateGuess(secret: number, value: number): GuessResult;
|
|
8
|
-
export declare function hintText(result: Exclude<GuessResult, 'win' | 'invalid'>, rangeMin: number, rangeMax: number): string;
|
|
9
|
+
export declare function hintText(result: Exclude<GuessResult, 'win' | 'invalid'>, rangeMin: number, rangeMax: number, locale?: Locale): string;
|
package/lib/engine.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
1
2
|
import { secureRandomIntInclusive } from '@zhin.js/game-kit';
|
|
2
3
|
export const GUESS_PREFIX = 'guess';
|
|
3
4
|
export const MIN = 1;
|
|
@@ -13,9 +14,13 @@ export function evaluateGuess(secret, value) {
|
|
|
13
14
|
return 'win';
|
|
14
15
|
return value < secret ? 'low' : 'high';
|
|
15
16
|
}
|
|
16
|
-
export function hintText(result, rangeMin, rangeMax) {
|
|
17
|
+
export function hintText(result, rangeMin, rangeMax, locale) {
|
|
17
18
|
if (result === 'low')
|
|
18
|
-
return
|
|
19
|
-
return
|
|
19
|
+
return messages(locale, 'text1', { p0: rangeMin, p1: rangeMax });
|
|
20
|
+
return messages(locale, 'text2', { p0: rangeMin, p1: rangeMax });
|
|
20
21
|
}
|
|
22
|
+
const messages = createMessages({
|
|
23
|
+
text1: { 'zh-CN': "📈 **太小了!** 范围 {p0} ~ {p1}", en: "📈 **Too low!** Range {p0} ~ {p1}" },
|
|
24
|
+
text2: { 'zh-CN': "📉 **太大了!** 范围 {p0} ~ {p1}", en: "📉 **Too high!** Range {p0} ~ {p1}" },
|
|
25
|
+
});
|
|
21
26
|
//# 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,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AACpC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;AACrB,MAAM,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC;AACvB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAI9B,MAAM,UAAU,SAAS;IACvB,OAAO,wBAAwB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,KAAa;IACzD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG;QAAE,OAAO,SAAS,CAAC;IAC7E,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACnC,OAAO,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAA+C,EAAE,QAAgB,EAAE,QAAgB;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAe,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AACpC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;AACrB,MAAM,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC;AACvB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAI9B,MAAM,UAAU,SAAS;IACvB,OAAO,wBAAwB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,KAAa;IACzD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG;QAAE,OAAO,SAAS,CAAC;IAC7E,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACnC,OAAO,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAA+C,EAAE,QAAgB,EAAE,QAAgB,EAAE,MAAe;IAC3H,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IACvF,OAAO,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,KAAK,EAAE,EAAE,OAAO,EAAE,4BAA4B,EAAE,EAAE,EAAE,mCAAmC,EAAE;IACzF,KAAK,EAAE,EAAE,OAAO,EAAE,4BAA4B,EAAE,EAAE,EAAE,oCAAoC,EAAE;CAC3F,CAAC,CAAC"}
|
package/lib/game-flow.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { createMessages, resolveLocale } from 'zhin.js/i18n';
|
|
1
2
|
import { evaluateGuess, hintText, MAX, MIN } from './engine.js';
|
|
2
3
|
import { buildGuessView } from './view.js';
|
|
3
4
|
export async function startGame(services, message) {
|
|
4
5
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
5
6
|
const mine = await services.getActiveForUser(ch, message.$sender.id);
|
|
7
|
+
const locale = resolveLocale(mine ? mine.locale : message.locale);
|
|
6
8
|
if (mine) {
|
|
7
|
-
return buildGuessView(mine, ['
|
|
9
|
+
return buildGuessView(mine, [messages(locale, 'text1')], message.$channel.type);
|
|
8
10
|
}
|
|
9
11
|
const session = await services.createSession(message);
|
|
10
12
|
return buildGuessView(session, [], message.$channel.type);
|
|
@@ -12,17 +14,18 @@ export async function startGame(services, message) {
|
|
|
12
14
|
export async function processGuess(services, message, value) {
|
|
13
15
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
14
16
|
const session = await services.getActiveForUser(ch, message.$sender.id);
|
|
17
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
15
18
|
if (!session)
|
|
16
19
|
return null;
|
|
17
20
|
const result = evaluateGuess(session.secret, value);
|
|
18
21
|
if (result === 'invalid') {
|
|
19
|
-
return
|
|
22
|
+
return messages(locale, 'text2', { p0: MIN, p1: MAX });
|
|
20
23
|
}
|
|
21
24
|
const attempts = session.attempts + 1;
|
|
22
25
|
if (result === 'win') {
|
|
23
26
|
await services.updateSession(session.id, { attempts, status: 'won' });
|
|
24
27
|
const updated = (await services.getById(session.id));
|
|
25
|
-
return buildGuessView(updated, [
|
|
28
|
+
return buildGuessView(updated, [messages(locale, 'text3', { p0: attempts })], message.$channel.type);
|
|
26
29
|
}
|
|
27
30
|
if (attempts >= session.max_attempts) {
|
|
28
31
|
await services.updateSession(session.id, { attempts, status: 'lost' });
|
|
@@ -37,28 +40,39 @@ export async function processGuess(services, message, value) {
|
|
|
37
40
|
rangeMax = Math.min(rangeMax, value - 1);
|
|
38
41
|
await services.updateSession(session.id, { attempts, range_min: rangeMin, range_max: rangeMax });
|
|
39
42
|
const updated = (await services.getById(session.id));
|
|
40
|
-
return buildGuessView(updated, [hintText(result, rangeMin, rangeMax)], message.$channel.type);
|
|
43
|
+
return buildGuessView(updated, [hintText(result, rangeMin, rangeMax, locale)], message.$channel.type);
|
|
41
44
|
}
|
|
42
45
|
export async function handleGuessChoice(services, message, sessionId, choiceId) {
|
|
43
46
|
const session = await services.getById(sessionId);
|
|
47
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
44
48
|
if (!session)
|
|
45
|
-
return '
|
|
49
|
+
return messages(locale, 'text4');
|
|
46
50
|
if (session.channel_key
|
|
47
51
|
!== `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`) {
|
|
48
|
-
return '
|
|
52
|
+
return messages(locale, 'text5');
|
|
49
53
|
}
|
|
50
54
|
if (session.player_id !== message.$sender.id)
|
|
51
|
-
return '
|
|
55
|
+
return messages(locale, 'text6');
|
|
52
56
|
if (choiceId === 'restart' && session.status !== 'active') {
|
|
53
57
|
return startGame(services, message);
|
|
54
58
|
}
|
|
55
59
|
if (choiceId === 'quit' && session.status === 'active') {
|
|
56
60
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
57
61
|
const updated = (await services.getById(session.id));
|
|
58
|
-
return buildGuessView(updated, ['
|
|
62
|
+
return buildGuessView(updated, [messages(locale, 'text7')], message.$channel.type);
|
|
59
63
|
}
|
|
60
64
|
return session.status === 'active'
|
|
61
|
-
? '
|
|
65
|
+
? messages(locale, 'text8')
|
|
62
66
|
: buildGuessView(session, [], message.$channel.type);
|
|
63
67
|
}
|
|
68
|
+
const messages = createMessages({
|
|
69
|
+
text1: { 'zh-CN': "你已有进行中的一局,请继续猜数字。", en: "You already have an active game. Keep guessing." },
|
|
70
|
+
text2: { 'zh-CN': "请输入 {p0} ~ {p1} 之间的整数。", en: "Enter an integer between {p0} and {p1}." },
|
|
71
|
+
text3: { 'zh-CN': "你用了 **{p0}** 次。", en: "You used **{p0}** guesses." },
|
|
72
|
+
text4: { 'zh-CN': "这局已经不存在了,请重新开始。", en: "This game no longer exists. Please start again." },
|
|
73
|
+
text5: { 'zh-CN': "请回到开局的频道操作。", en: "Return to the channel where this game started." },
|
|
74
|
+
text6: { 'zh-CN': "这是别人的猜数字对局。", en: "This game belongs to another player." },
|
|
75
|
+
text7: { 'zh-CN': "你放弃了本局。", en: "You quit this game." },
|
|
76
|
+
text8: { 'zh-CN': "请直接回复一个范围内的整数。", en: "Reply with an integer in the range." },
|
|
77
|
+
});
|
|
64
78
|
//# 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/guess-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 getGuessHelp(message?: Pick<GameMessageLike, 'locale' | 'formatCommand'>): string;
|
|
3
4
|
export declare const GUESS_HELP: string;
|
|
4
5
|
export declare function runGuessCommand(services: SessionService, message: GameMessageLike, action: string): Promise<GameReply>;
|
package/lib/guess-command.js
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatGameHelp, gameCommandFeedback, gameCommandHint, channelKey } from '@zhin.js/game-kit';
|
|
2
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
2
3
|
import { startGame } from './game-flow.js';
|
|
3
4
|
import { buildGuessView } from './view.js';
|
|
4
|
-
export
|
|
5
|
-
'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
'猜数 放弃 — 结束当前局',
|
|
9
|
-
'',
|
|
10
|
-
'进行中直接回复数字即可。',
|
|
11
|
-
].join('\n');
|
|
5
|
+
export function getGuessHelp(message = {}) {
|
|
6
|
+
return formatGameHelp(message, { 'zh-CN': "猜数字(1~100,7 次机会)", en: "Guess the Number (1–100, seven guesses)" }, 'guess', ['start', 'quit'], { 'zh-CN': "进行中直接回复范围内的整数。", en: "During a game, reply with an integer in the range." });
|
|
7
|
+
}
|
|
8
|
+
export const GUESS_HELP = getGuessHelp();
|
|
12
9
|
export async function runGuessCommand(services, message, action) {
|
|
13
10
|
const ch = channelKey(message);
|
|
14
11
|
const userId = message.$sender.id;
|
|
15
12
|
if (!action || action === 'help') {
|
|
16
13
|
const active = await services.getActiveForUser(ch, userId);
|
|
17
|
-
const lines = [
|
|
14
|
+
const lines = [getGuessHelp(message), ''];
|
|
18
15
|
if (active) {
|
|
19
|
-
return buildGuessView(active, [
|
|
16
|
+
return buildGuessView(active, [getGuessHelp(message)], message.$channel.type);
|
|
20
17
|
}
|
|
21
18
|
else {
|
|
22
|
-
lines.push('
|
|
19
|
+
lines.push(gameCommandFeedback(message, 'noGame'), gameCommandHint(message, 'guess'));
|
|
23
20
|
}
|
|
24
21
|
return lines.join('\n');
|
|
25
22
|
}
|
|
@@ -28,11 +25,14 @@ export async function runGuessCommand(services, message, action) {
|
|
|
28
25
|
if (action === 'quit') {
|
|
29
26
|
const row = await services.getActiveForUser(ch, userId);
|
|
30
27
|
if (!row)
|
|
31
|
-
return '
|
|
28
|
+
return gameCommandFeedback(message, 'noGame');
|
|
32
29
|
await services.updateSession(row.id, { status: 'aborted' });
|
|
33
30
|
const updated = (await services.getById(row.id));
|
|
34
|
-
return buildGuessView(updated, ['
|
|
31
|
+
return buildGuessView(updated, [messages(row.locale ?? undefined, 'text1')], message.$channel.type);
|
|
35
32
|
}
|
|
36
|
-
return
|
|
33
|
+
return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getGuessHelp(message);
|
|
37
34
|
}
|
|
35
|
+
const messages = createMessages({
|
|
36
|
+
text1: { 'zh-CN': "已放弃本局。", en: "You quit this game." },
|
|
37
|
+
});
|
|
38
38
|
//# sourceMappingURL=guess-command.js.map
|
package/lib/guess-command.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guess-command.js","sourceRoot":"","sources":["../src/guess-command.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"guess-command.js","sourceRoot":"","sources":["../src/guess-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,EAAwC,MAAM,mBAAmB,CAAC;AAC3I,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,UAAU,YAAY,CAAC,UAA6D,EAAE;IAC1F,OAAO,cAAc,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,kBAAkB,EAAE,EAAE,EAAE,yCAAyC,EAAE,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,EACvI,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE,oDAAoD,EAAE,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,EAAE,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAwB,EACxB,OAAwB,EACxB,MAAc;IAEd,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1C,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,cAAc,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChF,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE5D,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG;YAAE,OAAO,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACxD,MAAM,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAE,CAAC;QAClD,OAAO,cAAc,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,IAAI,SAAS,EAAE,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACtG,CAAC;IAED,OAAO,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,qBAAqB,EAAE;CACxD,CAAC,CAAC"}
|
package/lib/models.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ declare module '@zhin.js/core' {
|
|
|
4
4
|
interface Models {
|
|
5
5
|
guess_sessions: {
|
|
6
6
|
id: string;
|
|
7
|
+
locale?: 'zh-CN' | 'en' | null;
|
|
7
8
|
adapter: string;
|
|
8
9
|
endpoint: string;
|
|
9
10
|
channel_type: string;
|
|
@@ -24,5 +25,7 @@ declare module '@zhin.js/core' {
|
|
|
24
25
|
}
|
|
25
26
|
export type GuessSessionRow = Models['guess_sessions'];
|
|
26
27
|
export declare function defineHostTables(db: {
|
|
27
|
-
define: (name: string, definition: Record<string, unknown
|
|
28
|
+
define: (name: string, definition: Record<string, unknown>, options?: {
|
|
29
|
+
readonly addColumns?: readonly string[];
|
|
30
|
+
}) => void;
|
|
28
31
|
}): void;
|
package/lib/models.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export function defineHostTables(db) {
|
|
2
2
|
db.define('guess_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 },
|
|
@@ -16,6 +17,6 @@ export function defineHostTables(db) {
|
|
|
16
17
|
status: { type: 'text', default: 'active' },
|
|
17
18
|
updated_at: { type: 'bigint', default: 0 },
|
|
18
19
|
created_at: { type: 'bigint', default: 0 },
|
|
19
|
-
});
|
|
20
|
+
}, { addColumns: ['locale'] });
|
|
20
21
|
}
|
|
21
22
|
//# 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":"AA+BA,MAAM,UAAU,gBAAgB,CAC9B,EAAkI;IAElI,EAAE,CAAC,MAAM,CAAC,gBAAgB,EAAE;QAC1B,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,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC5C,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC1C,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE;QAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7C,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/session-service.js
CHANGED
|
@@ -26,6 +26,7 @@ export class SessionService extends BaseSessionService {
|
|
|
26
26
|
const now = Date.now();
|
|
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,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKhE,MAAM,OAAO,cAAe,SAAQ,kBAAmC;IACrE,YAAY,EAAiB;QAC3B,KAAK,CAAC,EAAqD,EAAE;YAC3D,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,gBAAgB;YACvB,UAAU,EAAE,CAAC,WAAW,CAAC;YACzB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK;gBACpD,CAAC,CAAC,CAAC;wBACC,MAAM,EAAE,OAAO,CAAC,SAAS;wBACzB,QAAQ,EAAE,OAAO,CAAC,WAAW;wBAC7B,MAAM,EAAE,KAAK;wBACb,KAAK,EAAE,IAAI,CAAC,GAAG,CACb,CAAC,EACD,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAC5C,GAAG,EAAE;qBACP,CAAC;gBACJ,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM;oBACzB,CAAC,CAAC,CAAC;4BACC,MAAM,EAAE,OAAO,CAAC,SAAS;4BACzB,QAAQ,EAAE,OAAO,CAAC,WAAW;4BAC7B,MAAM,EAAE,MAAM;yBACf,CAAC;oBACJ,CAAC,CAAC,EAAE;SACT,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAoB;YAC3B,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,MAAM,EAAE,SAAS,EAAE;YACnB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,QAAQ,EAAE,CAAC;YACX,YAAY,EAAE,YAAY;YAC1B,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,EAAiB;IAC9C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,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,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKhE,MAAM,OAAO,cAAe,SAAQ,kBAAmC;IACrE,YAAY,EAAiB;QAC3B,KAAK,CAAC,EAAqD,EAAE;YAC3D,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,gBAAgB;YACvB,UAAU,EAAE,CAAC,WAAW,CAAC;YACzB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK;gBACpD,CAAC,CAAC,CAAC;wBACC,MAAM,EAAE,OAAO,CAAC,SAAS;wBACzB,QAAQ,EAAE,OAAO,CAAC,WAAW;wBAC7B,MAAM,EAAE,KAAK;wBACb,KAAK,EAAE,IAAI,CAAC,GAAG,CACb,CAAC,EACD,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAC5C,GAAG,EAAE;qBACP,CAAC;gBACJ,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM;oBACzB,CAAC,CAAC,CAAC;4BACC,MAAM,EAAE,OAAO,CAAC,SAAS;4BACzB,QAAQ,EAAE,OAAO,CAAC,WAAW;4BAC7B,MAAM,EAAE,MAAM;yBACf,CAAC;oBACJ,CAAC,CAAC,EAAE;SACT,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAoB;YAC3B,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,MAAM,EAAE,SAAS,EAAE;YACnB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,QAAQ,EAAE,CAAC;YACX,YAAY,EAAE,YAAY;YAC1B,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,EAAiB;IAC9C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC"}
|
package/lib/view.js
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
|
+
import { createMessages } from 'zhin.js/i18n';
|
|
1
2
|
import { buildChoiceKeyboard } from '@zhin.js/game-kit';
|
|
2
3
|
export const GUESS_PREFIX = 'guess';
|
|
3
4
|
export function buildGuessView(session, eventLines = [], channelType) {
|
|
4
5
|
const terminal = session.status !== 'active';
|
|
5
6
|
const left = Math.max(0, session.max_attempts - session.attempts);
|
|
6
7
|
const lines = [
|
|
7
|
-
|
|
8
|
+
messages(session.locale ?? undefined, 'text1'),
|
|
8
9
|
'',
|
|
9
10
|
terminal
|
|
10
|
-
?
|
|
11
|
-
:
|
|
11
|
+
? messages(session.locale ?? undefined, 'text2', { p0: session.secret, p1: session.attempts })
|
|
12
|
+
: messages(session.locale ?? undefined, 'text3', { p0: session.range_min, p1: session.range_max }),
|
|
12
13
|
];
|
|
13
14
|
if (eventLines.length > 0)
|
|
14
15
|
lines.push('', ...eventLines);
|
|
15
16
|
if (terminal) {
|
|
16
17
|
if (session.status === 'won')
|
|
17
|
-
lines.push('',
|
|
18
|
+
lines.push('', messages(session.locale ?? undefined, 'text4'));
|
|
18
19
|
else if (session.status === 'lost')
|
|
19
|
-
lines.push('',
|
|
20
|
+
lines.push('', messages(session.locale ?? undefined, 'text5'));
|
|
20
21
|
else
|
|
21
|
-
lines.push('',
|
|
22
|
+
lines.push('', messages(session.locale ?? undefined, 'text6'));
|
|
22
23
|
}
|
|
23
24
|
else {
|
|
24
|
-
lines.push(
|
|
25
|
+
lines.push(messages(session.locale ?? undefined, 'text7', { p0: left, p1: session.attempts }), '', messages(session.locale ?? undefined, 'text8'));
|
|
25
26
|
}
|
|
26
27
|
return buildChoiceKeyboard({
|
|
27
28
|
gamePrefix: GUESS_PREFIX,
|
|
@@ -30,14 +31,26 @@ export function buildGuessView(session, eventLines = [], channelType) {
|
|
|
30
31
|
choices: terminal
|
|
31
32
|
? [{
|
|
32
33
|
id: 'restart',
|
|
33
|
-
label:
|
|
34
|
+
label: messages(session.locale ?? undefined, 'text9'),
|
|
34
35
|
style: 'primary',
|
|
35
36
|
keepEnabledWhenTerminal: true,
|
|
36
37
|
}]
|
|
37
|
-
: [{ id: 'quit', label:
|
|
38
|
+
: [{ id: 'quit', label: messages(session.locale ?? undefined, 'text10'), style: 'danger' }],
|
|
38
39
|
terminal,
|
|
39
40
|
interactionProfile: terminal ? 'terminal' : 'gameplay',
|
|
40
41
|
channelType,
|
|
41
42
|
});
|
|
42
43
|
}
|
|
44
|
+
const messages = createMessages({
|
|
45
|
+
text1: { 'zh-CN': "🔢 **猜数字**", en: "🔢 **Guess the Number**" },
|
|
46
|
+
text2: { 'zh-CN': "答案:**{p0}** · 共猜 {p1} 次", en: "Answer: **{p0}** · {p1} guesses" },
|
|
47
|
+
text3: { 'zh-CN': "范围:**{p0} ~ {p1}**", en: "Range: **{p0} ~ {p1}**" },
|
|
48
|
+
text4: { 'zh-CN': "🎉 **猜对了!**", en: "🎉 **Correct!**" },
|
|
49
|
+
text5: { 'zh-CN': "💀 **机会用完了。**", en: "💀 **No guesses left.**" },
|
|
50
|
+
text6: { 'zh-CN': "🏳️ 本局已结束。", en: "🏳️ This game has ended." },
|
|
51
|
+
text7: { 'zh-CN': "机会:**{p0}** 次 · 已猜 {p1} 次", en: "Guesses remaining: **{p0}** · Used: {p1}" },
|
|
52
|
+
text8: { 'zh-CN': "直接回复范围内的整数。", en: "Reply with an integer in the range." },
|
|
53
|
+
text9: { 'zh-CN': "🔄 再来一局", en: "🔄 Play again" },
|
|
54
|
+
text10: { 'zh-CN': "🏳️ 放弃", en: "🏳️ Quit" },
|
|
55
|
+
});
|
|
43
56
|
//# 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;AAIxD,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAEpC,MAAM,UAAU,cAAc,CAC5B,OAAwB,EACxB,aAAgC,EAAE,EAClC,WAAoB;IAEpB,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG;QACZ,
|
|
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, isGuessAction, messageFromCommandInput, normalizeGuessAction, } from '@zhin.js/game-kit';
|
|
3
|
-
import {
|
|
3
|
+
import { getGuessHelp, runGuessCommand } from "../../lib/guess-command.js";
|
|
4
4
|
import { resolveGameServices } from "../../lib/runtime-store.js";
|
|
5
5
|
export default defineGameCommandAliasMiddleware({
|
|
6
6
|
aliases: ['猜数', 'guess'],
|
|
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 = normalizeGuessAction(String(action ?? ''));
|
|
9
12
|
if (normalized === 'help')
|
|
10
|
-
return
|
|
13
|
+
return getGuessHelp(message);
|
|
11
14
|
// action 无法识别:放行给后续中间件,避免劫持普通聊天
|
|
12
15
|
if (!isGuessAction(normalized))
|
|
13
16
|
return null;
|
|
14
17
|
const services = resolveGameServices(context);
|
|
15
|
-
const message = messageFromCommandInput(input);
|
|
16
18
|
return runGuessCommand(services, message, normalized);
|
|
17
19
|
},
|
|
18
20
|
});
|
|
@@ -4,18 +4,20 @@ import {
|
|
|
4
4
|
messageFromCommandInput,
|
|
5
5
|
normalizeGuessAction,
|
|
6
6
|
} from '@zhin.js/game-kit';
|
|
7
|
-
import {
|
|
7
|
+
import { getGuessHelp, runGuessCommand } from '../../src/guess-command.js';
|
|
8
8
|
import { resolveGameServices } from '../../src/runtime-store.js';
|
|
9
9
|
|
|
10
10
|
export default defineGameCommandAliasMiddleware({
|
|
11
11
|
aliases: ['猜数', 'guess'],
|
|
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 = normalizeGuessAction(String(action ?? ''));
|
|
14
|
-
if (normalized === 'help') return
|
|
17
|
+
if (normalized === 'help') return getGuessHelp(message);
|
|
15
18
|
// action 无法识别:放行给后续中间件,避免劫持普通聊天
|
|
16
19
|
if (!isGuessAction(normalized)) return null;
|
|
17
20
|
const services = resolveGameServices(context);
|
|
18
|
-
const message = messageFromCommandInput(input);
|
|
19
21
|
return runGuessCommand(services, message, normalized);
|
|
20
22
|
},
|
|
21
23
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-guess-number",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.16",
|
|
4
4
|
"description": "Zhin.js 猜数字 — 1~100 七步之内猜中 (Plugin Runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
],
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@zhin.js/core": "1.1.
|
|
27
|
-
"@zhin.js/game-kit": "1.1.
|
|
26
|
+
"@zhin.js/core": "1.1.51",
|
|
27
|
+
"@zhin.js/game-kit": "1.1.16"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^6.0.3",
|
|
31
31
|
"vitest": "^4.1.10",
|
|
32
|
-
"zhin.js": "1.1.
|
|
32
|
+
"zhin.js": "1.1.16"
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|
|
@@ -66,9 +66,9 @@
|
|
|
66
66
|
"plugins": []
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@zhin.js/command": "^1.1.
|
|
70
|
-
"@zhin.js/middleware": "^1.1.
|
|
71
|
-
"zhin.js": "^1.1.
|
|
69
|
+
"@zhin.js/command": "^1.1.11",
|
|
70
|
+
"@zhin.js/middleware": "^1.1.10",
|
|
71
|
+
"zhin.js": "^1.1.16"
|
|
72
72
|
},
|
|
73
73
|
"peerDependenciesMeta": {
|
|
74
74
|
"@zhin.js/command": {
|
package/plugin.js
CHANGED
|
@@ -15,6 +15,10 @@ export default defineGamePlugin({
|
|
|
15
15
|
displayName: 'Guess Number',
|
|
16
16
|
},
|
|
17
17
|
game: {
|
|
18
|
+
commandPath: 'guess',
|
|
19
|
+
titleI18n: { en: 'Guess the Number' },
|
|
20
|
+
descriptionI18n: { en: 'Guess the secret number from 1 to 100 in seven tries' },
|
|
21
|
+
quickStartI18n: { en: 'start' },
|
|
18
22
|
id: 'guess',
|
|
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 { secureRandomIntInclusive } from '@zhin.js/game-kit';
|
|
2
3
|
|
|
3
4
|
export const GUESS_PREFIX = 'guess';
|
|
@@ -17,7 +18,12 @@ export function evaluateGuess(secret: number, value: number): GuessResult {
|
|
|
17
18
|
return value < secret ? 'low' : 'high';
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
export function hintText(result: Exclude<GuessResult, 'win' | 'invalid'>, rangeMin: number, rangeMax: number): string {
|
|
21
|
-
if (result === 'low') return
|
|
22
|
-
return
|
|
21
|
+
export function hintText(result: Exclude<GuessResult, 'win' | 'invalid'>, rangeMin: number, rangeMax: number, locale?: Locale): string {
|
|
22
|
+
if (result === 'low') return messages(locale, 'text1', { p0: rangeMin, p1: rangeMax });
|
|
23
|
+
return messages(locale, 'text2', { p0: rangeMin, p1: rangeMax });
|
|
23
24
|
}
|
|
25
|
+
|
|
26
|
+
const messages = createMessages({
|
|
27
|
+
text1: { 'zh-CN': "📈 **太小了!** 范围 {p0} ~ {p1}", en: "📈 **Too low!** Range {p0} ~ {p1}" },
|
|
28
|
+
text2: { 'zh-CN': "📉 **太大了!** 范围 {p0} ~ {p1}", en: "📉 **Too high!** Range {p0} ~ {p1}" },
|
|
29
|
+
});
|
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 { evaluateGuess, hintText, MAX, MIN } from './engine.js';
|
|
3
4
|
import type { SessionService } from './session-service.js';
|
|
@@ -9,10 +10,11 @@ export async function startGame(
|
|
|
9
10
|
): Promise<GameReply> {
|
|
10
11
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
11
12
|
const mine = await services.getActiveForUser(ch, message.$sender.id);
|
|
13
|
+
const locale = resolveLocale(mine ? mine.locale : message.locale);
|
|
12
14
|
if (mine) {
|
|
13
15
|
return buildGuessView(
|
|
14
16
|
mine,
|
|
15
|
-
['
|
|
17
|
+
[messages(locale, 'text1')],
|
|
16
18
|
message.$channel.type,
|
|
17
19
|
);
|
|
18
20
|
}
|
|
@@ -27,11 +29,12 @@ export async function processGuess(
|
|
|
27
29
|
): Promise<GameReply | null> {
|
|
28
30
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
29
31
|
const session = await services.getActiveForUser(ch, message.$sender.id);
|
|
32
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
30
33
|
if (!session) return null;
|
|
31
34
|
|
|
32
35
|
const result = evaluateGuess(session.secret, value);
|
|
33
36
|
if (result === 'invalid') {
|
|
34
|
-
return
|
|
37
|
+
return messages(locale, 'text2', { p0: MIN, p1: MAX });
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
const attempts = session.attempts + 1;
|
|
@@ -41,7 +44,7 @@ export async function processGuess(
|
|
|
41
44
|
const updated = (await services.getById(session.id))!;
|
|
42
45
|
return buildGuessView(
|
|
43
46
|
updated,
|
|
44
|
-
[
|
|
47
|
+
[messages(locale, 'text3', { p0: attempts })],
|
|
45
48
|
message.$channel.type,
|
|
46
49
|
);
|
|
47
50
|
}
|
|
@@ -62,7 +65,7 @@ export async function processGuess(
|
|
|
62
65
|
const updated = (await services.getById(session.id))!;
|
|
63
66
|
return buildGuessView(
|
|
64
67
|
updated,
|
|
65
|
-
[hintText(result, rangeMin, rangeMax)],
|
|
68
|
+
[hintText(result, rangeMin, rangeMax, locale)],
|
|
66
69
|
message.$channel.type,
|
|
67
70
|
);
|
|
68
71
|
}
|
|
@@ -74,12 +77,13 @@ export async function handleGuessChoice(
|
|
|
74
77
|
choiceId: string,
|
|
75
78
|
): Promise<GameReply> {
|
|
76
79
|
const session = await services.getById(sessionId);
|
|
77
|
-
|
|
80
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
81
|
+
if (!session) return messages(locale, 'text4');
|
|
78
82
|
if (session.channel_key
|
|
79
83
|
!== `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`) {
|
|
80
|
-
return '
|
|
84
|
+
return messages(locale, 'text5');
|
|
81
85
|
}
|
|
82
|
-
if (session.player_id !== message.$sender.id) return '
|
|
86
|
+
if (session.player_id !== message.$sender.id) return messages(locale, 'text6');
|
|
83
87
|
|
|
84
88
|
if (choiceId === 'restart' && session.status !== 'active') {
|
|
85
89
|
return startGame(services, message);
|
|
@@ -87,9 +91,20 @@ export async function handleGuessChoice(
|
|
|
87
91
|
if (choiceId === 'quit' && session.status === 'active') {
|
|
88
92
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
89
93
|
const updated = (await services.getById(session.id))!;
|
|
90
|
-
return buildGuessView(updated, ['
|
|
94
|
+
return buildGuessView(updated, [messages(locale, 'text7')], message.$channel.type);
|
|
91
95
|
}
|
|
92
96
|
return session.status === 'active'
|
|
93
|
-
? '
|
|
97
|
+
? messages(locale, 'text8')
|
|
94
98
|
: buildGuessView(session, [], message.$channel.type);
|
|
95
99
|
}
|
|
100
|
+
|
|
101
|
+
const messages = createMessages({
|
|
102
|
+
text1: { 'zh-CN': "你已有进行中的一局,请继续猜数字。", en: "You already have an active game. Keep guessing." },
|
|
103
|
+
text2: { 'zh-CN': "请输入 {p0} ~ {p1} 之间的整数。", en: "Enter an integer between {p0} and {p1}." },
|
|
104
|
+
text3: { 'zh-CN': "你用了 **{p0}** 次。", en: "You used **{p0}** guesses." },
|
|
105
|
+
text4: { 'zh-CN': "这局已经不存在了,请重新开始。", en: "This game no longer exists. Please start again." },
|
|
106
|
+
text5: { 'zh-CN': "请回到开局的频道操作。", en: "Return to the channel where this game started." },
|
|
107
|
+
text6: { 'zh-CN': "这是别人的猜数字对局。", en: "This game belongs to another player." },
|
|
108
|
+
text7: { 'zh-CN': "你放弃了本局。", en: "You quit this game." },
|
|
109
|
+
text8: { 'zh-CN': "请直接回复一个范围内的整数。", en: "Reply with an integer in the range." },
|
|
110
|
+
});
|
package/src/guess-command.ts
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
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 { startGame } from './game-flow.js';
|
|
7
4
|
import type { SessionService } from './session-service.js';
|
|
8
5
|
import { buildGuessView } from './view.js';
|
|
9
6
|
|
|
10
|
-
export
|
|
11
|
-
'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
'进行中直接回复数字即可。',
|
|
17
|
-
].join('\n');
|
|
7
|
+
export function getGuessHelp(message: Pick<GameMessageLike, 'locale' | 'formatCommand'> = {}): string {
|
|
8
|
+
return formatGameHelp(message, { 'zh-CN': "猜数字(1~100,7 次机会)", en: "Guess the Number (1–100, seven guesses)" }, 'guess', ['start', 'quit'],
|
|
9
|
+
{ 'zh-CN': "进行中直接回复范围内的整数。", en: "During a game, reply with an integer in the range." });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const GUESS_HELP = getGuessHelp();
|
|
18
13
|
|
|
19
14
|
export async function runGuessCommand(
|
|
20
15
|
services: SessionService,
|
|
@@ -26,11 +21,11 @@ export async function runGuessCommand(
|
|
|
26
21
|
|
|
27
22
|
if (!action || action === 'help') {
|
|
28
23
|
const active = await services.getActiveForUser(ch, userId);
|
|
29
|
-
const lines = [
|
|
24
|
+
const lines = [getGuessHelp(message), ''];
|
|
30
25
|
if (active) {
|
|
31
|
-
return buildGuessView(active, [
|
|
26
|
+
return buildGuessView(active, [getGuessHelp(message)], message.$channel.type);
|
|
32
27
|
} else {
|
|
33
|
-
lines.push('
|
|
28
|
+
lines.push(gameCommandFeedback(message, 'noGame'), gameCommandHint(message, 'guess'));
|
|
34
29
|
}
|
|
35
30
|
return lines.join('\n');
|
|
36
31
|
}
|
|
@@ -39,11 +34,15 @@ export async function runGuessCommand(
|
|
|
39
34
|
|
|
40
35
|
if (action === 'quit') {
|
|
41
36
|
const row = await services.getActiveForUser(ch, userId);
|
|
42
|
-
if (!row) return '
|
|
37
|
+
if (!row) return gameCommandFeedback(message, 'noGame');
|
|
43
38
|
await services.updateSession(row.id, { status: 'aborted' });
|
|
44
39
|
const updated = (await services.getById(row.id))!;
|
|
45
|
-
return buildGuessView(updated, ['
|
|
40
|
+
return buildGuessView(updated, [messages(row.locale ?? undefined, 'text1')], message.$channel.type);
|
|
46
41
|
}
|
|
47
42
|
|
|
48
|
-
return
|
|
43
|
+
return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getGuessHelp(message);
|
|
49
44
|
}
|
|
45
|
+
|
|
46
|
+
const messages = createMessages({
|
|
47
|
+
text1: { 'zh-CN': "已放弃本局。", en: "You quit this game." },
|
|
48
|
+
});
|
package/src/models.ts
CHANGED
|
@@ -6,6 +6,7 @@ declare module '@zhin.js/core' {
|
|
|
6
6
|
interface Models {
|
|
7
7
|
guess_sessions: {
|
|
8
8
|
id: string;
|
|
9
|
+
locale?: 'zh-CN' | 'en' | null;
|
|
9
10
|
adapter: string;
|
|
10
11
|
endpoint: string;
|
|
11
12
|
channel_type: string;
|
|
@@ -29,10 +30,11 @@ export type GuessSessionRow = Models['guess_sessions'];
|
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
export function defineHostTables(
|
|
32
|
-
db: { define: (name: string, definition: Record<string, unknown
|
|
33
|
+
db: { define: (name: string, definition: Record<string, unknown>, options?: { readonly addColumns?: readonly string[] }) => void },
|
|
33
34
|
): void {
|
|
34
35
|
db.define('guess_sessions', {
|
|
35
36
|
id: { type: 'text', primary: true },
|
|
37
|
+
locale: { type: 'text', nullable: true },
|
|
36
38
|
adapter: { type: 'text', nullable: false },
|
|
37
39
|
endpoint: { type: 'text', nullable: false },
|
|
38
40
|
channel_type: { type: 'text', nullable: false },
|
|
@@ -48,5 +50,5 @@ export function defineHostTables(
|
|
|
48
50
|
status: { type: 'text', default: 'active' },
|
|
49
51
|
updated_at: { type: 'bigint', default: 0 },
|
|
50
52
|
created_at: { type: 'bigint', default: 0 },
|
|
51
|
-
});
|
|
53
|
+
}, { addColumns: ['locale'] });
|
|
52
54
|
}
|
package/src/session-service.ts
CHANGED
|
@@ -41,6 +41,7 @@ export class SessionService extends BaseSessionService<GuessSessionRow> {
|
|
|
41
41
|
const now = Date.now();
|
|
42
42
|
const row: GuessSessionRow = {
|
|
43
43
|
id: generateSessionId(),
|
|
44
|
+
locale: message.locale ?? 'zh-CN',
|
|
44
45
|
adapter: String(message.$adapter),
|
|
45
46
|
endpoint: message.$endpoint,
|
|
46
47
|
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 type { GuessSessionRow } from './models.js';
|
|
@@ -12,24 +13,24 @@ export function buildGuessView(
|
|
|
12
13
|
const terminal = session.status !== 'active';
|
|
13
14
|
const left = Math.max(0, session.max_attempts - session.attempts);
|
|
14
15
|
const lines = [
|
|
15
|
-
|
|
16
|
+
messages(session.locale ?? undefined, 'text1'),
|
|
16
17
|
'',
|
|
17
18
|
terminal
|
|
18
|
-
?
|
|
19
|
-
:
|
|
19
|
+
? messages(session.locale ?? undefined, 'text2', { p0: session.secret, p1: session.attempts })
|
|
20
|
+
: messages(session.locale ?? undefined, 'text3', { p0: session.range_min, p1: session.range_max }),
|
|
20
21
|
];
|
|
21
22
|
|
|
22
23
|
if (eventLines.length > 0) lines.push('', ...eventLines);
|
|
23
24
|
|
|
24
25
|
if (terminal) {
|
|
25
|
-
if (session.status === 'won') lines.push('',
|
|
26
|
-
else if (session.status === 'lost') lines.push('',
|
|
27
|
-
else lines.push('',
|
|
26
|
+
if (session.status === 'won') lines.push('', messages(session.locale ?? undefined, 'text4'));
|
|
27
|
+
else if (session.status === 'lost') lines.push('', messages(session.locale ?? undefined, 'text5'));
|
|
28
|
+
else lines.push('', messages(session.locale ?? undefined, 'text6'));
|
|
28
29
|
} else {
|
|
29
30
|
lines.push(
|
|
30
|
-
|
|
31
|
+
messages(session.locale ?? undefined, 'text7', { p0: left, p1: session.attempts }),
|
|
31
32
|
'',
|
|
32
|
-
'
|
|
33
|
+
messages(session.locale ?? undefined, 'text8'),
|
|
33
34
|
);
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -40,13 +41,26 @@ export function buildGuessView(
|
|
|
40
41
|
choices: terminal
|
|
41
42
|
? [{
|
|
42
43
|
id: 'restart',
|
|
43
|
-
label:
|
|
44
|
+
label: messages(session.locale ?? undefined, 'text9'),
|
|
44
45
|
style: 'primary',
|
|
45
46
|
keepEnabledWhenTerminal: true,
|
|
46
47
|
}]
|
|
47
|
-
: [{ id: 'quit', label:
|
|
48
|
+
: [{ id: 'quit', label: messages(session.locale ?? undefined, 'text10'), style: 'danger' }],
|
|
48
49
|
terminal,
|
|
49
50
|
interactionProfile: terminal ? 'terminal' : 'gameplay',
|
|
50
51
|
channelType,
|
|
51
52
|
});
|
|
52
53
|
}
|
|
54
|
+
|
|
55
|
+
const messages = createMessages({
|
|
56
|
+
text1: { 'zh-CN': "🔢 **猜数字**", en: "🔢 **Guess the Number**" },
|
|
57
|
+
text2: { 'zh-CN': "答案:**{p0}** · 共猜 {p1} 次", en: "Answer: **{p0}** · {p1} guesses" },
|
|
58
|
+
text3: { 'zh-CN': "范围:**{p0} ~ {p1}**", en: "Range: **{p0} ~ {p1}**" },
|
|
59
|
+
text4: { 'zh-CN': "🎉 **猜对了!**", en: "🎉 **Correct!**" },
|
|
60
|
+
text5: { 'zh-CN': "💀 **机会用完了。**", en: "💀 **No guesses left.**" },
|
|
61
|
+
text6: { 'zh-CN': "🏳️ 本局已结束。", en: "🏳️ This game has ended." },
|
|
62
|
+
text7: { 'zh-CN': "机会:**{p0}** 次 · 已猜 {p1} 次", en: "Guesses remaining: **{p0}** · Used: {p1}" },
|
|
63
|
+
text8: { 'zh-CN': "直接回复范围内的整数。", en: "Reply with an integer in the range." },
|
|
64
|
+
text9: { 'zh-CN': "🔄 再来一局", en: "🔄 Play again" },
|
|
65
|
+
text10: { 'zh-CN': "🏳️ 放弃", en: "🏳️ Quit" },
|
|
66
|
+
});
|