@zhin.js/plugin-dice-duel 1.1.15 → 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.
@@ -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, normalizeDiceAction } from '@zhin.js/game-kit';
4
- import { DICE_HELP, runDiceCommand } from "../../../lib/dice-command.js";
4
+ import { getDiceHelp, runDiceCommand } from "../../../lib/dice-command.js";
5
5
  import { resolveGameServices } from "../../../lib/runtime-store.js";
6
6
  export default defineCommand({
7
7
  description: 'Dice Duel',
8
8
  params: { action: { type: 'string', default: '' } },
9
- async execute({ params, input, use, owner }) {
9
+ async execute({ params, input, use, locale, formatCommand }) {
10
10
  const action = normalizeDiceAction(String(params.action ?? ''));
11
11
  if (!action || action === 'help')
12
- return DICE_HELP;
12
+ return getDiceHelp({ locale, formatCommand });
13
13
  const services = resolveGameServices({ use });
14
- const message = messageFromCommandInput(input);
14
+ const message = messageFromCommandInput(input, { locale, formatCommand });
15
15
  return runDiceCommand(services, message, action);
16
16
  },
17
17
  });
@@ -1,16 +1,16 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
2
  import { messageFromCommandInput, normalizeDiceAction } from '@zhin.js/game-kit';
3
- import { DICE_HELP, runDiceCommand } from '../../../src/dice-command.js';
3
+ import { getDiceHelp, runDiceCommand } from '../../../src/dice-command.js';
4
4
  import { resolveGameServices } from '../../../src/runtime-store.js';
5
5
 
6
6
  export default defineCommand({
7
7
  description: 'Dice Duel',
8
8
  params: { action: { type: 'string', default: '' } },
9
- async execute({ params, input, use, owner }) {
9
+ async execute({ params, input, use, locale, formatCommand }) {
10
10
  const action = normalizeDiceAction(String(params.action ?? ''));
11
- if (!action || action === 'help') return DICE_HELP;
11
+ if (!action || action === 'help') return getDiceHelp({ locale, formatCommand });
12
12
  const services = resolveGameServices({ use });
13
- const message = messageFromCommandInput(input);
13
+ const message = messageFromCommandInput(input, { locale, formatCommand });
14
14
  return runDiceCommand(services, message, action);
15
15
  },
16
16
  });
@@ -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 getDiceHelp(message?: Pick<GameMessageLike, 'locale' | 'formatCommand'>): string;
3
4
  export declare const DICE_HELP: string;
4
5
  export declare function runDiceCommand(services: SessionService, message: GameMessageLike, action: string): Promise<GameReply>;
@@ -1,23 +1,21 @@
1
- import { channelKey, } from '@zhin.js/game-kit';
1
+ import { formatGameHelp, gameCommandFeedback, gameCommandHint, channelKey } from '@zhin.js/game-kit';
2
+ import { createMessages } from 'zhin.js/i18n';
2
3
  import { continueGame, handleChoice, startGame } from './game-flow.js';
3
- export const DICE_HELP = [
4
- '🎲 骰子对决(三局两胜)',
5
- '骰子 / dice — 帮助',
6
- '骰子 开始 — 新对局',
7
- '骰子 继续 — 刷新界面',
8
- '骰子 放弃 — 结束对局',
9
- ].join('\n');
4
+ export function getDiceHelp(message = {}) {
5
+ return formatGameHelp(message, { 'zh-CN': "🎲 骰子对决(三局两胜)", en: "🎲 Dice Duel (best of three)" }, 'dice', ['start', 'continue', 'quit'], { 'zh-CN': "点击按钮或回复选项数字掷骰。", en: "Choose a button or reply with its option number." });
6
+ }
7
+ export const DICE_HELP = getDiceHelp();
10
8
  export async function runDiceCommand(services, message, action) {
11
9
  const ch = channelKey(message);
12
10
  const userId = message.$sender.id;
13
11
  if (!action || action === 'help') {
14
12
  const active = await services.getActiveByChannel(ch);
15
- const lines = [DICE_HELP, ''];
13
+ const lines = [getDiceHelp(message), ''];
16
14
  if (active) {
17
- lines.push(`进行中:${active.player_name} · ${active.player_wins}:${active.bot_wins}`);
15
+ lines.push(messages(active.locale ?? undefined, 'text1', { p0: active.player_name, p1: active.player_wins, p2: active.bot_wins }));
18
16
  }
19
17
  else {
20
- lines.push('暂无对局,发送「骰子 开始」或从游戏大厅进入。');
18
+ lines.push(gameCommandFeedback(message, 'noGame'), gameCommandHint(message, 'dice'));
21
19
  }
22
20
  return lines.join('\n');
23
21
  }
@@ -28,9 +26,12 @@ export async function runDiceCommand(services, message, action) {
28
26
  if (action === 'quit') {
29
27
  const row = await services.getActiveForUser(ch, userId);
30
28
  if (!row)
31
- return '你没有进行中的骰子对决。';
29
+ return gameCommandFeedback(message, 'noGame');
32
30
  return (await handleChoice(services, message, row.id, 'quit')) ?? '';
33
31
  }
34
- return `未知子命令:${action}\n\n${DICE_HELP}`;
32
+ return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getDiceHelp(message);
35
33
  }
34
+ const messages = createMessages({
35
+ text1: { 'zh-CN': "进行中:{p0} · {p1}:{p2}", en: "Playing: {p0} · {p1}:{p2}" },
36
+ });
36
37
  //# sourceMappingURL=dice-command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dice-command.js","sourceRoot":"","sources":["../src/dice-command.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,GAGX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGvE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,eAAe;IACf,gBAAgB;IAChB,aAAa;IACb,cAAc;IACd,cAAc;CACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,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,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC9B,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,WAAW,MAAM,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrF,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1E,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElE,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,cAAc,CAAC;QAChC,OAAO,CAAC,MAAM,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACvE,CAAC;IAED,OAAO,SAAS,MAAM,OAAO,SAAS,EAAE,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"dice-command.js","sourceRoot":"","sources":["../src/dice-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,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGvE,MAAM,UAAU,WAAW,CAAC,UAA6D,EAAE;IACzF,OAAO,cAAc,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,8BAA8B,EAAE,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,EACpI,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE,kDAAkD,EAAE,CAAC,CAAC;AAC3F,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,EAAE,CAAC;AAEvC,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,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,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,IAAI,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACrI,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1E,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElE,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,OAAO,CAAC,MAAM,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACvE,CAAC;IAED,OAAO,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,KAAK,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,EAAE,EAAE,2BAA2B,EAAE;CAC5E,CAAC,CAAC"}
package/lib/game-flow.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createMessages, resolveLocale } from 'zhin.js/i18n';
1
2
  import { compareRolls, DICE_PREFIX, rollD6, WIN_TARGET } from './engine.js';
2
3
  import { buildDiceView } from './view.js';
3
4
  /**
@@ -11,29 +12,32 @@ function renderView(session, message, lastRound) {
11
12
  export async function startGame(services, message) {
12
13
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
13
14
  const active = await services.getActiveByChannel(ch);
15
+ const locale = resolveLocale(active ? active.locale : message.locale);
14
16
  if (active) {
15
17
  if (active.player_id === message.$sender.id) {
16
- return '你已有进行中的骰子对决,发送「骰子 继续」刷新。';
18
+ return messages(locale, 'text1');
17
19
  }
18
- return `本频道 ${active.player_name} 正在掷骰对决中。`;
20
+ return messages(locale, 'text2', { p0: active.player_name });
19
21
  }
20
22
  const session = await services.createSession(message);
21
23
  return renderView(session, message);
22
24
  }
23
25
  export async function continueGame(services, message) {
24
26
  const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
27
+ const locale = resolveLocale(session ? session.locale : message.locale);
25
28
  if (!session)
26
- return '你没有进行中的骰子对决,发送「骰子 开始」。';
29
+ return messages(locale, 'text3');
27
30
  return renderView(session, message);
28
31
  }
29
32
  export async function handleChoice(services, message, sessionId, choiceId) {
30
33
  const session = await services.getById(sessionId);
34
+ const locale = resolveLocale(session ? session.locale : message.locale);
31
35
  if (!session)
32
- return '对局不存在。';
36
+ return messages(locale, 'text4');
33
37
  if (session.player_id !== message.$sender.id)
34
- return '这是别人的对局。';
38
+ return messages(locale, 'text5');
35
39
  if (session.status !== 'active' && choiceId !== 'restart') {
36
- return '对局已结束,请点击再来一局。';
40
+ return messages(locale, 'text6');
37
41
  }
38
42
  if (choiceId === 'restart') {
39
43
  await services.updateSession(session.id, { status: 'aborted' });
@@ -44,7 +48,7 @@ export async function handleChoice(services, message, sessionId, choiceId) {
44
48
  return renderView((await services.getById(session.id)), message);
45
49
  }
46
50
  if (choiceId !== 'roll')
47
- return '无效操作。';
51
+ return messages(locale, 'text7');
48
52
  const player = rollD6();
49
53
  const bot = rollD6();
50
54
  const result = compareRolls(player, bot);
@@ -71,4 +75,13 @@ export async function handleChoice(services, message, sessionId, choiceId) {
71
75
  return renderView(updated, message, { player, bot, result });
72
76
  }
73
77
  export { DICE_PREFIX };
78
+ const messages = createMessages({
79
+ text1: { 'zh-CN': "你已有进行中的骰子对决,请使用当前对局的操作入口。", en: "You already have an active dice duel. Continue using its controls." },
80
+ text2: { 'zh-CN': "本频道 {p0} 正在掷骰对决中。", en: "{p0} is playing a dice duel in this channel." },
81
+ text3: { 'zh-CN': "你没有进行中的骰子对决,请使用当前对局的操作入口。", en: "You have no active dice duel." },
82
+ text4: { 'zh-CN': "对局不存在。", en: "This game no longer exists." },
83
+ text5: { 'zh-CN': "这是别人的对局。", en: "This game belongs to another player." },
84
+ text6: { 'zh-CN': "对局已结束,请点击再来一局。", en: "This game has ended. Choose Play again." },
85
+ text7: { 'zh-CN': "无效操作。", en: "Invalid action." },
86
+ });
74
87
  //# sourceMappingURL=game-flow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
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
  dice_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 DiceSessionRow = Models['dice_sessions'];
26
27
  export declare function defineHostTables(db: {
27
- define: (name: string, definition: Record<string, unknown>) => void;
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('dice_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":"AA8BA,MAAM,UAAU,gBAAgB,CAC9B,EAA2E;IAE3E,EAAE,CAAC,MAAM,CAAC,eAAe,EAAE;QACzB,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACnC,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,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACjD,aAAa,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC9C,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,CAAC,CAAC;AACL,CAAC"}
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,eAAe,EAAE;QACzB,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,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACjD,aAAa,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC9C,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"}
@@ -25,6 +25,7 @@ export class SessionService extends BaseSessionService {
25
25
  const now = Date.now();
26
26
  const row = {
27
27
  id: generateSessionId(),
28
+ locale: message.locale ?? 'zh-CN',
28
29
  adapter: String(message.$adapter),
29
30
  endpoint: message.$endpoint,
30
31
  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;AAK3B,MAAM,OAAO,cAAe,SAAQ,kBAAkC;IACpE,YAAY,EAAgB;QAC1B,KAAK,CAAC,EAAoD,EAAE;YAC1D,MAAM,EAAE,MAAM;YACd,KAAK,EAAE,eAAe;YACtB,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,OAAO,CAAC,WAAW,GAAG,EAAE;qBAChC,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,GAAmB;YAC1B,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,WAAW,EAAE,CAAC;YACd,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,CAAC;YACR,gBAAgB,EAAE,CAAC;YACnB,aAAa,EAAE,CAAC;YAChB,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,EAAgB;IAC7C,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;AAK3B,MAAM,OAAO,cAAe,SAAQ,kBAAkC;IACpE,YAAY,EAAgB;QAC1B,KAAK,CAAC,EAAoD,EAAE;YAC1D,MAAM,EAAE,MAAM;YACd,KAAK,EAAE,eAAe;YACtB,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,OAAO,CAAC,WAAW,GAAG,EAAE;qBAChC,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,GAAmB;YAC1B,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,WAAW,EAAE,CAAC;YACd,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,CAAC;YACR,gBAAgB,EAAE,CAAC;YACnB,aAAa,EAAE,CAAC;YAChB,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,EAAgB;IAC7C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC"}
package/lib/view.js CHANGED
@@ -1,38 +1,39 @@
1
+ import { createMessages } from 'zhin.js/i18n';
1
2
  import { buildChoiceKeyboard } from '@zhin.js/game-kit';
2
3
  import { DICE_PREFIX, diceEmoji } from './engine.js';
3
4
  export function buildDiceView(session, lastRound, channelType) {
4
5
  const terminal = session.status !== 'active';
5
6
  const lines = [
6
- '🎲 **骰子对决**',
7
+ messages(session.locale ?? undefined, 'text1'),
7
8
  '',
8
- `比分 · 你 **${session.player_wins}** : **${session.bot_wins}** 机器人(三局两胜)`,
9
+ messages(session.locale ?? undefined, 'text2', { p0: session.player_wins, p1: session.bot_wins }),
9
10
  ];
10
11
  if (lastRound) {
11
12
  lines.push('');
12
- lines.push(`你 ${diceEmoji(lastRound.player)}(${lastRound.player}) vs 机器人 ${diceEmoji(lastRound.bot)}(${lastRound.bot})`);
13
+ lines.push(messages(session.locale ?? undefined, 'text3', { p0: diceEmoji(lastRound.player), p1: lastRound.player, p2: diceEmoji(lastRound.bot), p3: lastRound.bot }));
13
14
  lines.push(lastRound.result === 0
14
- ? '🤝 平局,再来!'
15
+ ? messages(session.locale ?? undefined, 'text4')
15
16
  : lastRound.result === 1
16
- ? '🎉 你赢本局!'
17
- : '😅 机器人赢本局。');
17
+ ? messages(session.locale ?? undefined, 'text5')
18
+ : messages(session.locale ?? undefined, 'text6'));
18
19
  }
19
20
  if (terminal) {
20
21
  lines.push('');
21
22
  if (session.status === 'won')
22
- lines.push('🏆 **你赢得比赛!**');
23
+ lines.push(messages(session.locale ?? undefined, 'text7'));
23
24
  else if (session.status === 'lost')
24
- lines.push('💀 **机器人赢得比赛。**');
25
+ lines.push(messages(session.locale ?? undefined, 'text8'));
25
26
  else
26
- lines.push('🏳️ **本局已放弃。**');
27
+ lines.push(messages(session.locale ?? undefined, 'text9'));
27
28
  }
28
29
  else {
29
- lines.push('', lastRound ? '点击继续掷骰:' : '点击掷骰开始!');
30
+ lines.push('', lastRound ? messages(session.locale ?? undefined, 'text10') : messages(session.locale ?? undefined, 'text11'));
30
31
  }
31
32
  const choices = terminal
32
- ? [{ id: 'restart', label: '🔄 再来一局', style: 'primary', keepEnabledWhenTerminal: true }]
33
+ ? [{ id: 'restart', label: messages(session.locale ?? undefined, 'text12'), style: 'primary', keepEnabledWhenTerminal: true }]
33
34
  : [
34
- { id: 'roll', label: '🎲 掷骰', style: 'primary' },
35
- { id: 'quit', label: '🏳️ 放弃', style: 'danger' },
35
+ { id: 'roll', label: messages(session.locale ?? undefined, 'text13'), style: 'primary' },
36
+ { id: 'quit', label: messages(session.locale ?? undefined, 'text14'), style: 'danger' },
36
37
  ];
37
38
  return buildChoiceKeyboard({
38
39
  gamePrefix: DICE_PREFIX,
@@ -40,9 +41,26 @@ export function buildDiceView(session, lastRound, channelType) {
40
41
  narrative: lines.join('\n'),
41
42
  choices,
42
43
  terminal,
43
- fallbackHint: '回复 1 掷骰 · 2 放弃',
44
+ fallbackHint: messages(session.locale ?? undefined, 'text15'),
44
45
  interactionProfile: terminal ? 'terminal' : 'gameplay',
45
46
  channelType,
46
47
  });
47
48
  }
49
+ const messages = createMessages({
50
+ text1: { 'zh-CN': "🎲 **骰子对决**", en: "🎲 **Dice Duel**" },
51
+ text2: { 'zh-CN': "比分 · 你 **{p0}** : **{p1}** 机器人(三局两胜)", en: "Score · You **{p0}** : **{p1}** Bot (best of three)" },
52
+ text3: { 'zh-CN': "你 {p0}({p1}) vs 机器人 {p2}({p3})", en: "You {p0}({p1}) vs Bot {p2}({p3})" },
53
+ text4: { 'zh-CN': "🤝 平局,再来!", en: "🤝 Draw — roll again!" },
54
+ text5: { 'zh-CN': "🎉 你赢本局!", en: "🎉 You won this round!" },
55
+ text6: { 'zh-CN': "😅 机器人赢本局。", en: "😅 The bot won this round." },
56
+ text7: { 'zh-CN': "🏆 **你赢得比赛!**", en: "🏆 **You won the match!**" },
57
+ text8: { 'zh-CN': "💀 **机器人赢得比赛。**", en: "💀 **The bot won the match.**" },
58
+ text9: { 'zh-CN': "🏳️ **本局已放弃。**", en: "🏳️ **You quit this match.**" },
59
+ text10: { 'zh-CN': "点击继续掷骰:", en: "Roll again:" },
60
+ text11: { 'zh-CN': "点击掷骰开始!", en: "Roll the dice to start!" },
61
+ text12: { 'zh-CN': "🔄 再来一局", en: "🔄 Play again" },
62
+ text13: { 'zh-CN': "🎲 掷骰", en: "🎲 Roll" },
63
+ text14: { 'zh-CN': "🏳️ 放弃", en: "🏳️ Quit" },
64
+ text15: { 'zh-CN': "回复 1 掷骰 · 2 放弃", en: "Reply 1 to roll · 2 to quit" },
65
+ });
48
66
  //# 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;AAGxD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAc,MAAM,aAAa,CAAC;AAEjE,MAAM,UAAU,aAAa,CAC3B,OAAuB,EACvB,SAA8D,EAC9D,WAAoB;IAEpB,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC;IAC7C,MAAM,KAAK,GAAG;QACZ,aAAa;QACb,EAAE;QACF,YAAY,OAAO,CAAC,WAAW,UAAU,OAAO,CAAC,QAAQ,cAAc;KACxE,CAAC;IAEF,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,MAAM,cAAc,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC;QAC3H,KAAK,CAAC,IAAI,CACR,SAAS,CAAC,MAAM,KAAK,CAAC;YACpB,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;gBACtB,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,YAAY,CACnB,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;aACrD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;;YAC7D,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ;QACtB,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAkB,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC;QACjG,CAAC,CAAC;YACE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAkB,EAAE;YACzD,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAiB,EAAE;SAC1D,CAAC;IAEN,OAAO,mBAAmB,CAAC;QACzB,UAAU,EAAE,WAAW;QACvB,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAC3B,OAAO;QACP,QAAQ;QACR,YAAY,EAAE,gBAAgB;QAC9B,kBAAkB,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU;QACtD,WAAW;KACZ,CAAC,CAAC;AACL,CAAC"}
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, isDiceAction, messageFromCommandInput, normalizeDiceAction, } from '@zhin.js/game-kit';
3
- import { DICE_HELP, runDiceCommand } from "../../lib/dice-command.js";
3
+ import { getDiceHelp, runDiceCommand } from "../../lib/dice-command.js";
4
4
  import { resolveGameServices } from "../../lib/runtime-store.js";
5
5
  export default defineGameCommandAliasMiddleware({
6
6
  aliases: ['骰子', 'dice'],
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 = normalizeDiceAction(String(action ?? ''));
9
12
  if (normalized === 'help')
10
- return DICE_HELP;
13
+ return getDiceHelp(message);
11
14
  // action 无法识别:放行给后续中间件,避免劫持普通聊天
12
15
  if (!isDiceAction(normalized))
13
16
  return null;
14
17
  const services = resolveGameServices(context);
15
- const message = messageFromCommandInput(input);
16
18
  return runDiceCommand(services, message, normalized);
17
19
  },
18
20
  });
@@ -4,18 +4,20 @@ import {
4
4
  messageFromCommandInput,
5
5
  normalizeDiceAction,
6
6
  } from '@zhin.js/game-kit';
7
- import { DICE_HELP, runDiceCommand } from '../../src/dice-command.js';
7
+ import { getDiceHelp, runDiceCommand } from '../../src/dice-command.js';
8
8
  import { resolveGameServices } from '../../src/runtime-store.js';
9
9
 
10
10
  export default defineGameCommandAliasMiddleware({
11
11
  aliases: ['骰子', 'dice'],
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 = normalizeDiceAction(String(action ?? ''));
14
- if (normalized === 'help') return DICE_HELP;
17
+ if (normalized === 'help') return getDiceHelp(message);
15
18
  // action 无法识别:放行给后续中间件,避免劫持普通聊天
16
19
  if (!isDiceAction(normalized)) return null;
17
20
  const services = resolveGameServices(context);
18
- const message = messageFromCommandInput(input);
19
21
  return runDiceCommand(services, message, normalized);
20
22
  },
21
23
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-dice-duel",
3
- "version": "1.1.15",
3
+ "version": "1.1.16",
4
4
  "description": "Zhin.js 骰子对决 — 三局两胜比大小 (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.50",
27
- "@zhin.js/game-kit": "1.1.15"
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.15"
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.10",
70
- "@zhin.js/middleware": "^1.1.9",
71
- "zhin.js": "^1.1.15"
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: 'Dice Duel',
16
16
  },
17
17
  game: {
18
+ commandPath: 'dice',
19
+ titleI18n: { en: 'Dice Duel' },
20
+ descriptionI18n: { en: 'Challenge the bot to a dice duel' },
21
+ quickStartI18n: { en: 'start' },
18
22
  id: 'dice',
19
23
  title: '骰子对决',
20
24
  icon: '🎲',
@@ -1,18 +1,14 @@
1
- import {
2
- channelKey,
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, handleChoice, startGame } from './game-flow.js';
7
4
  import type { SessionService } from './session-service.js';
8
5
 
9
- export const DICE_HELP = [
10
- '🎲 骰子对决(三局两胜)',
11
- '骰子 / dice — 帮助',
12
- '骰子 开始 — 新对局',
13
- '骰子 继续 — 刷新界面',
14
- '骰子 放弃 — 结束对局',
15
- ].join('\n');
6
+ export function getDiceHelp(message: Pick<GameMessageLike, 'locale' | 'formatCommand'> = {}): string {
7
+ return formatGameHelp(message, { 'zh-CN': "🎲 骰子对决(三局两胜)", en: "🎲 Dice Duel (best of three)" }, 'dice', ['start', 'continue', 'quit'],
8
+ { 'zh-CN': "点击按钮或回复选项数字掷骰。", en: "Choose a button or reply with its option number." });
9
+ }
10
+
11
+ export const DICE_HELP = getDiceHelp();
16
12
 
17
13
  export async function runDiceCommand(
18
14
  services: SessionService,
@@ -24,11 +20,11 @@ export async function runDiceCommand(
24
20
 
25
21
  if (!action || action === 'help') {
26
22
  const active = await services.getActiveByChannel(ch);
27
- const lines = [DICE_HELP, ''];
23
+ const lines = [getDiceHelp(message), ''];
28
24
  if (active) {
29
- lines.push(`进行中:${active.player_name} · ${active.player_wins}:${active.bot_wins}`);
25
+ lines.push(messages(active.locale ?? undefined, 'text1', { p0: active.player_name, p1: active.player_wins, p2: active.bot_wins }));
30
26
  } else {
31
- lines.push('暂无对局,发送「骰子 开始」或从游戏大厅进入。');
27
+ lines.push(gameCommandFeedback(message, 'noGame'), gameCommandHint(message, 'dice'));
32
28
  }
33
29
  return lines.join('\n');
34
30
  }
@@ -38,9 +34,13 @@ export async function runDiceCommand(
38
34
 
39
35
  if (action === 'quit') {
40
36
  const row = await services.getActiveForUser(ch, userId);
41
- if (!row) return '你没有进行中的骰子对决。';
37
+ if (!row) return gameCommandFeedback(message, 'noGame');
42
38
  return (await handleChoice(services, message, row.id, 'quit')) ?? '';
43
39
  }
44
40
 
45
- return `未知子命令:${action}\n\n${DICE_HELP}`;
41
+ return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getDiceHelp(message);
46
42
  }
43
+
44
+ const messages = createMessages({
45
+ text1: { 'zh-CN': "进行中:{p0} · {p1}:{p2}", en: "Playing: {p0} · {p1}:{p2}" },
46
+ });
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 type { DiceSessionRow } from './models.js';
3
4
  import { compareRolls, DICE_PREFIX, rollD6, WIN_TARGET } from './engine.js';
@@ -23,11 +24,12 @@ export async function startGame(
23
24
  ): Promise<GameReply | undefined> {
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');
29
31
  }
30
- return `本频道 ${active.player_name} 正在掷骰对决中。`;
32
+ return messages(locale, 'text2', { p0: active.player_name });
31
33
  }
32
34
  const session = await services.createSession(message);
33
35
  return renderView(session, message);
@@ -41,7 +43,8 @@ export async function continueGame(
41
43
  `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`,
42
44
  message.$sender.id,
43
45
  );
44
- if (!session) return '你没有进行中的骰子对决,发送「骰子 开始」。';
46
+ const locale = resolveLocale(session ? session.locale : message.locale);
47
+ if (!session) return messages(locale, 'text3');
45
48
  return renderView(session, message);
46
49
  }
47
50
 
@@ -52,11 +55,12 @@ export async function handleChoice(
52
55
  choiceId: string,
53
56
  ): Promise<GameReply | null> {
54
57
  const session = await services.getById(sessionId);
55
- if (!session) return '对局不存在。';
56
- if (session.player_id !== message.$sender.id) return '这是别人的对局。';
58
+ const locale = resolveLocale(session ? session.locale : message.locale);
59
+ if (!session) return messages(locale, 'text4');
60
+ if (session.player_id !== message.$sender.id) return messages(locale, 'text5');
57
61
 
58
62
  if (session.status !== 'active' && choiceId !== 'restart') {
59
- return '对局已结束,请点击再来一局。';
63
+ return messages(locale, 'text6');
60
64
  }
61
65
 
62
66
  if (choiceId === 'restart') {
@@ -68,7 +72,7 @@ export async function handleChoice(
68
72
  return renderView((await services.getById(session.id))!, message);
69
73
  }
70
74
 
71
- if (choiceId !== 'roll') return '无效操作。';
75
+ if (choiceId !== 'roll') return messages(locale, 'text7');
72
76
 
73
77
  const player = rollD6();
74
78
  const bot = rollD6();
@@ -97,3 +101,13 @@ export async function handleChoice(
97
101
  }
98
102
 
99
103
  export { DICE_PREFIX };
104
+
105
+ const messages = createMessages({
106
+ text1: { 'zh-CN': "你已有进行中的骰子对决,请使用当前对局的操作入口。", en: "You already have an active dice duel. Continue using its controls." },
107
+ text2: { 'zh-CN': "本频道 {p0} 正在掷骰对决中。", en: "{p0} is playing a dice duel in this channel." },
108
+ text3: { 'zh-CN': "你没有进行中的骰子对决,请使用当前对局的操作入口。", en: "You have no active dice duel." },
109
+ text4: { 'zh-CN': "对局不存在。", en: "This game no longer exists." },
110
+ text5: { 'zh-CN': "这是别人的对局。", en: "This game belongs to another player." },
111
+ text6: { 'zh-CN': "对局已结束,请点击再来一局。", en: "This game has ended. Choose Play again." },
112
+ text7: { 'zh-CN': "无效操作。", en: "Invalid action." },
113
+ });
package/src/models.ts CHANGED
@@ -6,6 +6,7 @@ declare module '@zhin.js/core' {
6
6
  interface Models {
7
7
  dice_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 DiceSessionRow = Models['dice_sessions'];
29
30
 
30
31
 
31
32
  export function defineHostTables(
32
- db: { define: (name: string, definition: Record<string, unknown>) => void },
33
+ db: { define: (name: string, definition: Record<string, unknown>, options?: { readonly addColumns?: readonly string[] }) => void },
33
34
  ): void {
34
35
  db.define('dice_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
  }
@@ -37,6 +37,7 @@ export class SessionService extends BaseSessionService<DiceSessionRow> {
37
37
  const now = Date.now();
38
38
  const row: DiceSessionRow = {
39
39
  id: generateSessionId(),
40
+ locale: message.locale ?? 'zh-CN',
40
41
  adapter: String(message.$adapter),
41
42
  endpoint: message.$endpoint,
42
43
  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 { DiceSessionRow } from './models.js';
@@ -10,37 +11,37 @@ export function buildDiceView(
10
11
  ): SendContent {
11
12
  const terminal = session.status !== 'active';
12
13
  const lines = [
13
- '🎲 **骰子对决**',
14
+ messages(session.locale ?? undefined, 'text1'),
14
15
  '',
15
- `比分 · 你 **${session.player_wins}** : **${session.bot_wins}** 机器人(三局两胜)`,
16
+ messages(session.locale ?? undefined, 'text2', { p0: session.player_wins, p1: session.bot_wins }),
16
17
  ];
17
18
 
18
19
  if (lastRound) {
19
20
  lines.push('');
20
- lines.push(`你 ${diceEmoji(lastRound.player)}(${lastRound.player}) vs 机器人 ${diceEmoji(lastRound.bot)}(${lastRound.bot})`);
21
+ lines.push(messages(session.locale ?? undefined, 'text3', { p0: diceEmoji(lastRound.player), p1: lastRound.player, p2: diceEmoji(lastRound.bot), p3: lastRound.bot }));
21
22
  lines.push(
22
23
  lastRound.result === 0
23
- ? '🤝 平局,再来!'
24
+ ? messages(session.locale ?? undefined, 'text4')
24
25
  : lastRound.result === 1
25
- ? '🎉 你赢本局!'
26
- : '😅 机器人赢本局。',
26
+ ? messages(session.locale ?? undefined, 'text5')
27
+ : messages(session.locale ?? undefined, 'text6'),
27
28
  );
28
29
  }
29
30
 
30
31
  if (terminal) {
31
32
  lines.push('');
32
- if (session.status === 'won') lines.push('🏆 **你赢得比赛!**');
33
- else if (session.status === 'lost') lines.push('💀 **机器人赢得比赛。**');
34
- else lines.push('🏳️ **本局已放弃。**');
33
+ if (session.status === 'won') lines.push(messages(session.locale ?? undefined, 'text7'));
34
+ else if (session.status === 'lost') lines.push(messages(session.locale ?? undefined, 'text8'));
35
+ else lines.push(messages(session.locale ?? undefined, 'text9'));
35
36
  } else {
36
- lines.push('', lastRound ? '点击继续掷骰:' : '点击掷骰开始!');
37
+ lines.push('', lastRound ? messages(session.locale ?? undefined, 'text10') : messages(session.locale ?? undefined, 'text11'));
37
38
  }
38
39
 
39
40
  const choices = terminal
40
- ? [{ id: 'restart', label: '🔄 再来一局', style: 'primary' as const, keepEnabledWhenTerminal: true }]
41
+ ? [{ id: 'restart', label: messages(session.locale ?? undefined, 'text12'), style: 'primary' as const, keepEnabledWhenTerminal: true }]
41
42
  : [
42
- { id: 'roll', label: '🎲 掷骰', style: 'primary' as const },
43
- { id: 'quit', label: '🏳️ 放弃', style: 'danger' as const },
43
+ { id: 'roll', label: messages(session.locale ?? undefined, 'text13'), style: 'primary' as const },
44
+ { id: 'quit', label: messages(session.locale ?? undefined, 'text14'), style: 'danger' as const },
44
45
  ];
45
46
 
46
47
  return buildChoiceKeyboard({
@@ -49,8 +50,26 @@ export function buildDiceView(
49
50
  narrative: lines.join('\n'),
50
51
  choices,
51
52
  terminal,
52
- fallbackHint: '回复 1 掷骰 · 2 放弃',
53
+ fallbackHint: messages(session.locale ?? undefined, 'text15'),
53
54
  interactionProfile: terminal ? 'terminal' : 'gameplay',
54
55
  channelType,
55
56
  });
56
57
  }
58
+
59
+ const messages = createMessages({
60
+ text1: { 'zh-CN': "🎲 **骰子对决**", en: "🎲 **Dice Duel**" },
61
+ text2: { 'zh-CN': "比分 · 你 **{p0}** : **{p1}** 机器人(三局两胜)", en: "Score · You **{p0}** : **{p1}** Bot (best of three)" },
62
+ text3: { 'zh-CN': "你 {p0}({p1}) vs 机器人 {p2}({p3})", en: "You {p0}({p1}) vs Bot {p2}({p3})" },
63
+ text4: { 'zh-CN': "🤝 平局,再来!", en: "🤝 Draw — roll again!" },
64
+ text5: { 'zh-CN': "🎉 你赢本局!", en: "🎉 You won this round!" },
65
+ text6: { 'zh-CN': "😅 机器人赢本局。", en: "😅 The bot won this round." },
66
+ text7: { 'zh-CN': "🏆 **你赢得比赛!**", en: "🏆 **You won the match!**" },
67
+ text8: { 'zh-CN': "💀 **机器人赢得比赛。**", en: "💀 **The bot won the match.**" },
68
+ text9: { 'zh-CN': "🏳️ **本局已放弃。**", en: "🏳️ **You quit this match.**" },
69
+ text10: { 'zh-CN': "点击继续掷骰:", en: "Roll again:" },
70
+ text11: { 'zh-CN': "点击掷骰开始!", en: "Roll the dice to start!" },
71
+ text12: { 'zh-CN': "🔄 再来一局", en: "🔄 Play again" },
72
+ text13: { 'zh-CN': "🎲 掷骰", en: "🎲 Roll" },
73
+ text14: { 'zh-CN': "🏳️ 放弃", en: "🏳️ Quit" },
74
+ text15: { 'zh-CN': "回复 1 掷骰 · 2 放弃", en: "Reply 1 to roll · 2 to quit" },
75
+ });