@zhin.js/plugin-blackjack 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/bj/[[action]]/index.js +4 -4
- package/commands/bj/[[action]]/index.ts +4 -4
- package/lib/bj-command.d.ts +2 -1
- package/lib/bj-command.js +8 -13
- package/lib/bj-command.js.map +1 -1
- package/lib/game-flow.js +22 -8
- 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/session-service.js +1 -0
- package/lib/session-service.js.map +1 -1
- package/lib/view.js +32 -14
- package/lib/view.js.map +1 -1
- package/middlewares/bj-alias/index.js +5 -3
- package/middlewares/bj-alias/index.ts +5 -3
- package/package.json +7 -7
- package/plugin.js +4 -0
- package/src/bj-command.ts +10 -14
- package/src/game-flow.ts +23 -8
- package/src/models.ts +4 -2
- package/src/session-service.ts +1 -0
- package/src/view.ts +33 -14
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { defineCommand } from 'zhin.js/command';
|
|
3
3
|
import { messageFromCommandInput } from '@zhin.js/game-kit';
|
|
4
|
-
import {
|
|
4
|
+
import { getBjHelp, runBjCommand } from "../../../lib/bj-command.js";
|
|
5
5
|
import { resolveGameServices } from "../../../lib/runtime-store.js";
|
|
6
6
|
function normalizeBjAction(raw) {
|
|
7
7
|
const a = raw.trim().toLowerCase() || 'help';
|
|
@@ -16,12 +16,12 @@ function normalizeBjAction(raw) {
|
|
|
16
16
|
export default defineCommand({
|
|
17
17
|
description: 'Blackjack',
|
|
18
18
|
params: { action: { type: 'string', default: '' } },
|
|
19
|
-
async execute({ params, input, use,
|
|
19
|
+
async execute({ params, input, use, locale, formatCommand }) {
|
|
20
20
|
const action = normalizeBjAction(String(params.action ?? ''));
|
|
21
21
|
if (!action || action === 'help')
|
|
22
|
-
return
|
|
22
|
+
return getBjHelp({ locale, formatCommand });
|
|
23
23
|
const services = resolveGameServices({ use });
|
|
24
|
-
const message = messageFromCommandInput(input);
|
|
24
|
+
const message = messageFromCommandInput(input, { locale, formatCommand });
|
|
25
25
|
return runBjCommand(services, message, action);
|
|
26
26
|
},
|
|
27
27
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineCommand } from 'zhin.js/command';
|
|
2
2
|
import { messageFromCommandInput } from '@zhin.js/game-kit';
|
|
3
|
-
import {
|
|
3
|
+
import { getBjHelp, runBjCommand } from '../../../src/bj-command.js';
|
|
4
4
|
import { resolveGameServices } from '../../../src/runtime-store.js';
|
|
5
5
|
|
|
6
6
|
function normalizeBjAction(raw: string): string {
|
|
@@ -14,11 +14,11 @@ function normalizeBjAction(raw: string): string {
|
|
|
14
14
|
export default defineCommand({
|
|
15
15
|
description: 'Blackjack',
|
|
16
16
|
params: { action: { type: 'string', default: '' } },
|
|
17
|
-
async execute({ params, input, use,
|
|
17
|
+
async execute({ params, input, use, locale, formatCommand }) {
|
|
18
18
|
const action = normalizeBjAction(String(params.action ?? ''));
|
|
19
|
-
if (!action || action === 'help') return
|
|
19
|
+
if (!action || action === 'help') return getBjHelp({ locale, formatCommand });
|
|
20
20
|
const services = resolveGameServices({ use });
|
|
21
|
-
const message = messageFromCommandInput(input);
|
|
21
|
+
const message = messageFromCommandInput(input, { locale, formatCommand });
|
|
22
22
|
return runBjCommand(services, message, action);
|
|
23
23
|
},
|
|
24
24
|
});
|
package/lib/bj-command.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
|
|
2
2
|
import type { SessionService } from './session-service.js';
|
|
3
|
+
export declare function getBjHelp(message?: Pick<GameMessageLike, 'locale' | 'formatCommand'>): string;
|
|
3
4
|
export declare const BJ_HELP: string;
|
|
4
5
|
export declare function runBjCommand(services: SessionService, message: GameMessageLike, action: string): Promise<GameReply>;
|
package/lib/bj-command.js
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
|
+
import { formatGameHelp, gameCommandFeedback } from '@zhin.js/game-kit';
|
|
1
2
|
import { continueGame, handleChoice, startGame } from './game-flow.js';
|
|
2
|
-
export
|
|
3
|
-
'🃏 **21 点**',
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
'',
|
|
7
|
-
'• `/21点 开始` — 新局',
|
|
8
|
-
'• `/21点 继续` — 刷新界面',
|
|
9
|
-
'• `/21点 放弃` — 结束本局',
|
|
10
|
-
'• 对局中点击 **要牌** / **停牌**',
|
|
11
|
-
].join('\n');
|
|
3
|
+
export function getBjHelp(message = {}) {
|
|
4
|
+
return formatGameHelp(message, { 'zh-CN': "🃏 **21 点**", en: "🃏 **Blackjack**" }, 'bj', ['start', 'continue', 'quit'], { 'zh-CN': "尽量让手牌点数接近 21 且不超过,比庄家大即获胜。对局中点击要牌或停牌。", en: "Get as close to 21 as possible without going over, and beat the dealer. Choose Hit or Stand during play." });
|
|
5
|
+
}
|
|
6
|
+
export const BJ_HELP = getBjHelp();
|
|
12
7
|
export async function runBjCommand(services, message, action) {
|
|
13
8
|
const a = action.trim().toLowerCase() || 'help';
|
|
14
9
|
if (a === 'help' || a === '帮助')
|
|
15
|
-
return
|
|
10
|
+
return getBjHelp(message);
|
|
16
11
|
if (a === 'start' || a === '开始')
|
|
17
12
|
return (await startGame(services, message)) ?? '';
|
|
18
13
|
if (a === 'continue' || a === '继续')
|
|
@@ -20,9 +15,9 @@ export async function runBjCommand(services, message, action) {
|
|
|
20
15
|
if (a === 'quit' || a === '放弃') {
|
|
21
16
|
const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
|
|
22
17
|
if (!session)
|
|
23
|
-
return
|
|
18
|
+
return gameCommandFeedback(message, 'noGame');
|
|
24
19
|
return (await handleChoice(services, message, session.id, 'quit')) ?? '';
|
|
25
20
|
}
|
|
26
|
-
return
|
|
21
|
+
return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getBjHelp(message);
|
|
27
22
|
}
|
|
28
23
|
//# sourceMappingURL=bj-command.js.map
|
package/lib/bj-command.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bj-command.js","sourceRoot":"","sources":["../src/bj-command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bj-command.js","sourceRoot":"","sources":["../src/bj-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAyD,MAAM,mBAAmB,CAAC;AAC/H,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGvE,MAAM,UAAU,SAAS,CAAC,UAA6D,EAAE;IACvF,OAAO,cAAc,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,EACpH,EAAE,OAAO,EAAE,uCAAuC,EAAE,EAAE,EAAE,0GAA0G,EAAE,CAAC,CAAC;AAC1K,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;AAEnC,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAwB,EACxB,OAAwB,EACxB,MAAc;IAEd,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC;IAChD,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACnF,IAAI,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3E,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAC7C,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,EAC1F,OAAO,CAAC,OAAO,CAAC,EAAE,CACnB,CAAC;QACF,IAAI,CAAC,OAAO;YAAE,OAAO,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC5D,OAAO,CAAC,MAAM,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3E,CAAC;IACD,OAAO,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;AACvF,CAAC"}
|
package/lib/game-flow.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createMessages, resolveLocale } from 'zhin.js/i18n';
|
|
1
2
|
import { BJ_PREFIX, compareHands, dealerShouldHit, handValue, TARGET, } from './engine.js';
|
|
2
3
|
import { parseCards, parseDeck } from './session-service.js';
|
|
3
4
|
import { buildBjView, naturalOutcome, playerBust } from './view.js';
|
|
@@ -27,11 +28,12 @@ async function dealerPlay(deck, dealer) {
|
|
|
27
28
|
export async function startGame(services, message) {
|
|
28
29
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
29
30
|
const active = await services.getActiveByChannel(ch);
|
|
31
|
+
const locale = resolveLocale(active ? active.locale : message.locale);
|
|
30
32
|
if (active) {
|
|
31
33
|
if (active.player_id === message.$sender.id) {
|
|
32
|
-
return
|
|
34
|
+
return messages(locale, 'text1');
|
|
33
35
|
}
|
|
34
|
-
return
|
|
36
|
+
return messages(locale, 'text2', { p0: active.player_name });
|
|
35
37
|
}
|
|
36
38
|
const session = await services.createSession(message);
|
|
37
39
|
const natural = naturalOutcome(session);
|
|
@@ -42,22 +44,24 @@ export async function startGame(services, message) {
|
|
|
42
44
|
}
|
|
43
45
|
export async function continueGame(services, message) {
|
|
44
46
|
const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
|
|
47
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
45
48
|
if (!session)
|
|
46
|
-
return
|
|
49
|
+
return messages(locale, 'text3');
|
|
47
50
|
return renderView(session, message);
|
|
48
51
|
}
|
|
49
52
|
export async function handleChoice(services, message, sessionId, choiceId) {
|
|
50
53
|
const session = await services.getById(sessionId);
|
|
54
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
51
55
|
if (!session)
|
|
52
|
-
return '
|
|
56
|
+
return messages(locale, 'text4');
|
|
53
57
|
if (session.player_id !== message.$sender.id)
|
|
54
|
-
return '
|
|
58
|
+
return messages(locale, 'text5');
|
|
55
59
|
if (session.status !== 'active' && choiceId === 'restart') {
|
|
56
60
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
57
61
|
return (await startGame(services, message)) ?? null;
|
|
58
62
|
}
|
|
59
63
|
if (session.status !== 'active')
|
|
60
|
-
return '
|
|
64
|
+
return messages(locale, 'text6');
|
|
61
65
|
if (choiceId === 'quit') {
|
|
62
66
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
63
67
|
return renderView((await services.getById(session.id)), message, true, true);
|
|
@@ -68,7 +72,7 @@ export async function handleChoice(services, message, sessionId, choiceId) {
|
|
|
68
72
|
if (choiceId === 'hit') {
|
|
69
73
|
const card = deck.pop();
|
|
70
74
|
if (!card)
|
|
71
|
-
return '
|
|
75
|
+
return messages(locale, 'text7');
|
|
72
76
|
player = [...player, card];
|
|
73
77
|
await services.updateSession(session.id, {
|
|
74
78
|
deck_json: JSON.stringify(deck),
|
|
@@ -81,7 +85,7 @@ export async function handleChoice(services, message, sessionId, choiceId) {
|
|
|
81
85
|
return renderView(updated, message);
|
|
82
86
|
}
|
|
83
87
|
if (choiceId !== 'stand')
|
|
84
|
-
return '
|
|
88
|
+
return messages(locale, 'text8');
|
|
85
89
|
dealer = await dealerPlay(deck, dealer);
|
|
86
90
|
await services.updateSession(session.id, {
|
|
87
91
|
deck_json: JSON.stringify(deck),
|
|
@@ -92,4 +96,14 @@ export async function handleChoice(services, message, sessionId, choiceId) {
|
|
|
92
96
|
return finishRound(services, message, session, status);
|
|
93
97
|
}
|
|
94
98
|
export { BJ_PREFIX, handValue, TARGET };
|
|
99
|
+
const messages = createMessages({
|
|
100
|
+
text1: { 'zh-CN': "你已有进行中的 21 点,请使用当前对局的操作入口。", en: "You already have an active blackjack game. Continue using its controls." },
|
|
101
|
+
text2: { 'zh-CN': "本频道 {p0} 正在玩 21 点。", en: "{p0} is playing blackjack in this channel." },
|
|
102
|
+
text3: { 'zh-CN': "你没有进行中的 21 点,请使用当前对局的操作入口。", en: "You have no active blackjack game." },
|
|
103
|
+
text4: { 'zh-CN': "对局不存在。", en: "This game no longer exists." },
|
|
104
|
+
text5: { 'zh-CN': "这是别人的对局。", en: "This game belongs to another player." },
|
|
105
|
+
text6: { 'zh-CN': "对局已结束,请点击再来一局。", en: "This game has ended. Choose Play again." },
|
|
106
|
+
text7: { 'zh-CN': "牌堆已空。", en: "The deck is empty." },
|
|
107
|
+
text8: { 'zh-CN': "无效操作。", en: "Invalid action." },
|
|
108
|
+
});
|
|
95
109
|
//# 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
|
bj_sessions: {
|
|
6
6
|
id: string;
|
|
7
|
+
locale?: 'zh-CN' | 'en' | null;
|
|
7
8
|
adapter: string;
|
|
8
9
|
endpoint: string;
|
|
9
10
|
channel_type: string;
|
|
@@ -22,5 +23,7 @@ declare module '@zhin.js/core' {
|
|
|
22
23
|
}
|
|
23
24
|
export type BjSessionRow = Models['bj_sessions'];
|
|
24
25
|
export declare function defineHostTables(db: {
|
|
25
|
-
define: (name: string, definition: Record<string, unknown
|
|
26
|
+
define: (name: string, definition: Record<string, unknown>, options?: {
|
|
27
|
+
readonly addColumns?: readonly string[];
|
|
28
|
+
}) => void;
|
|
26
29
|
}): void;
|
package/lib/models.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export function defineHostTables(db) {
|
|
2
2
|
db.define('bj_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 },
|
|
@@ -14,6 +15,6 @@ export function defineHostTables(db) {
|
|
|
14
15
|
status: { type: 'text', default: 'active' },
|
|
15
16
|
updated_at: { type: 'bigint', default: 0 },
|
|
16
17
|
created_at: { type: 'bigint', default: 0 },
|
|
17
|
-
});
|
|
18
|
+
}, { addColumns: ['locale'] });
|
|
18
19
|
}
|
|
19
20
|
//# 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":"AA6BA,MAAM,UAAU,gBAAgB,CAC9B,EAAkI;IAElI,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE;QACvB,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,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC1C,iBAAiB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAClD,iBAAiB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAClD,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;AAE3B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,MAAM,OAAO,cAAe,SAAQ,kBAAgC;IAClE,YAAY,EAAc;QACxB,KAAK,CAAC,EAAkD,EAAE;YACxD,MAAM,EAAE,WAAW;YACnB,KAAK,EAAE,aAAa;YACpB,UAAU,EAAE,CAAC,WAAW,CAAC;YACzB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC5B,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;uBAClD,OAAO,CAAC,MAAM,KAAK,MAAM;oBAC9B,CAAC,CAAC,CAAC;4BACC,MAAM,EAAE,OAAO,CAAC,SAAS;4BACzB,QAAQ,EAAE,OAAO,CAAC,WAAW;4BAC7B,MAAM,EAAE,OAAO,CAAC,MAAM;4BACtB,KAAK,EAAE,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;yBACjD,CAAC;oBACJ,CAAC,CAAC,EAAE,CAAC;aACR;SACF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB;QAC1C,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,GAAG,EAAG,EAAE,IAAI,CAAC,GAAG,EAAG,CAAC,CAAC;QAC/C,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,GAAG,EAAG,EAAE,IAAI,CAAC,GAAG,EAAG,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAiB;YACxB,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,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/D,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAC/B,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;YAC9C,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;YAC9C,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,EAAc;IAC3C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAkC;IAC9D,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,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACjC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAC1B,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;YAC1D,CAAC,CAAC,EAAE,CAAC;IACT,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAuB;IAC/C,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC"}
|
|
1
|
+
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"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"}
|
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 { BJ_PREFIX, formatHand, handValue, isBlackjack, TARGET } from './engine.js';
|
|
3
4
|
import { parseCards } from './session-service.js';
|
|
@@ -5,32 +6,32 @@ export function buildBjView(session, terminal = false, revealDealer = false, cha
|
|
|
5
6
|
const player = parseCards(session.player_cards_json);
|
|
6
7
|
const dealer = parseCards(session.dealer_cards_json);
|
|
7
8
|
const lines = [
|
|
8
|
-
|
|
9
|
+
messages(session.locale ?? undefined, 'text1'),
|
|
9
10
|
'',
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
messages(session.locale ?? undefined, 'text2', { p0: formatHand(player) }),
|
|
12
|
+
messages(session.locale ?? undefined, 'text3', { p0: revealDealer || terminal ? formatHand(dealer) : formatHand(dealer, true) }),
|
|
12
13
|
'',
|
|
13
14
|
];
|
|
14
15
|
if (terminal) {
|
|
15
16
|
if (session.status === 'won')
|
|
16
|
-
lines.push(
|
|
17
|
+
lines.push(messages(session.locale ?? undefined, 'text4'));
|
|
17
18
|
else if (session.status === 'lost')
|
|
18
|
-
lines.push(
|
|
19
|
+
lines.push(messages(session.locale ?? undefined, 'text5'));
|
|
19
20
|
else if (session.status === 'draw')
|
|
20
|
-
lines.push(
|
|
21
|
+
lines.push(messages(session.locale ?? undefined, 'text6'));
|
|
21
22
|
else
|
|
22
|
-
lines.push(
|
|
23
|
-
lines.push('',
|
|
23
|
+
lines.push(messages(session.locale ?? undefined, 'text7'));
|
|
24
|
+
lines.push('', messages(session.locale ?? undefined, 'text8'));
|
|
24
25
|
}
|
|
25
26
|
else {
|
|
26
|
-
lines.push(
|
|
27
|
+
lines.push(messages(session.locale ?? undefined, 'text9', { p0: TARGET }));
|
|
27
28
|
}
|
|
28
29
|
const choices = terminal
|
|
29
|
-
? [{ id: 'restart', label:
|
|
30
|
+
? [{ id: 'restart', label: messages(session.locale ?? undefined, 'text10'), style: 'primary', keepEnabledWhenTerminal: true }]
|
|
30
31
|
: [
|
|
31
|
-
{ id: 'hit', label:
|
|
32
|
-
{ id: 'stand', label:
|
|
33
|
-
{ id: 'quit', label:
|
|
32
|
+
{ id: 'hit', label: messages(session.locale ?? undefined, 'text11'), style: 'primary' },
|
|
33
|
+
{ id: 'stand', label: messages(session.locale ?? undefined, 'text12'), style: 'secondary' },
|
|
34
|
+
{ id: 'quit', label: messages(session.locale ?? undefined, 'text13'), style: 'danger' },
|
|
34
35
|
];
|
|
35
36
|
return buildChoiceKeyboard({
|
|
36
37
|
gamePrefix: BJ_PREFIX,
|
|
@@ -38,7 +39,7 @@ export function buildBjView(session, terminal = false, revealDealer = false, cha
|
|
|
38
39
|
narrative: lines.join('\n'),
|
|
39
40
|
choices,
|
|
40
41
|
terminal,
|
|
41
|
-
fallbackHint: terminal ?
|
|
42
|
+
fallbackHint: terminal ? messages(session.locale ?? undefined, 'text14') : messages(session.locale ?? undefined, 'text15'),
|
|
42
43
|
interactionProfile: terminal ? 'terminal' : 'gameplay',
|
|
43
44
|
channelType,
|
|
44
45
|
});
|
|
@@ -64,4 +65,21 @@ export function naturalOutcome(session) {
|
|
|
64
65
|
export function playerBust(session) {
|
|
65
66
|
return handValue(parseCards(session.player_cards_json)) > TARGET;
|
|
66
67
|
}
|
|
68
|
+
const messages = createMessages({
|
|
69
|
+
text1: { 'zh-CN': "🃏 **21 点**", en: "🃏 **Blackjack**" },
|
|
70
|
+
text2: { 'zh-CN': "你的牌:{p0}", en: "Your hand: {p0}" },
|
|
71
|
+
text3: { 'zh-CN': "庄家:{p0}", en: "Dealer: {p0}" },
|
|
72
|
+
text4: { 'zh-CN': "🎉 **你赢了!**", en: "🎉 **You won!**" },
|
|
73
|
+
text5: { 'zh-CN': "💀 **你输了**", en: "💀 **You lost**" },
|
|
74
|
+
text6: { 'zh-CN': "🤝 **平局**", en: "🤝 **Draw**" },
|
|
75
|
+
text7: { 'zh-CN': "🏳️ **本局已放弃。**", en: "🏳️ **You quit this game.**" },
|
|
76
|
+
text8: { 'zh-CN': "点击「再来一局」开始新局。", en: "Choose “Play again” to start a new game." },
|
|
77
|
+
text9: { 'zh-CN': "目标:尽量接近 {p0} 且不超过。", en: "Get as close to {p0} as possible without going over." },
|
|
78
|
+
text10: { 'zh-CN': "🔄 再来一局", en: "🔄 Play again" },
|
|
79
|
+
text11: { 'zh-CN': "➕ 要牌", en: "➕ Hit" },
|
|
80
|
+
text12: { 'zh-CN': "✋ 停牌", en: "✋ Stand" },
|
|
81
|
+
text13: { 'zh-CN': "🏳️ 放弃", en: "🏳️ Quit" },
|
|
82
|
+
text14: { 'zh-CN': "回复 1 再来一局", en: "Reply 1 to play again" },
|
|
83
|
+
text15: { 'zh-CN': "1 要牌 · 2 停牌 · 3 放弃", en: "1 Hit · 2 Stand · 3 Quit" },
|
|
84
|
+
});
|
|
67
85
|
//# 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,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEpF,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,UAAU,WAAW,CACzB,OAAqB,EACrB,QAAQ,GAAG,KAAK,EAChB,YAAY,GAAG,KAAK,EACpB,WAAoB;IAEpB,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG;QACZ,
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { defineGameCommandAliasMiddleware, messageFromCommandInput } from '@zhin.js/game-kit';
|
|
3
|
-
import {
|
|
3
|
+
import { getBjHelp, runBjCommand } from "../../lib/bj-command.js";
|
|
4
4
|
import { resolveGameServices } from "../../lib/runtime-store.js";
|
|
5
5
|
function normalizeBjAction(raw) {
|
|
6
6
|
const a = raw.trim().toLowerCase() || 'help';
|
|
@@ -15,11 +15,13 @@ function normalizeBjAction(raw) {
|
|
|
15
15
|
export default defineGameCommandAliasMiddleware({
|
|
16
16
|
aliases: ['21点', 'bj'],
|
|
17
17
|
async run(action, input, context) {
|
|
18
|
+
const message = messageFromCommandInput(input, {
|
|
19
|
+
formatCommand: (path) => context.input.formatCommand?.(path, context.owner.id),
|
|
20
|
+
});
|
|
18
21
|
const normalized = normalizeBjAction(String(action ?? ''));
|
|
19
22
|
if (!normalized || normalized === 'help')
|
|
20
|
-
return
|
|
23
|
+
return getBjHelp(message);
|
|
21
24
|
const services = resolveGameServices(context);
|
|
22
|
-
const message = messageFromCommandInput(input);
|
|
23
25
|
return runBjCommand(services, message, normalized);
|
|
24
26
|
},
|
|
25
27
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineGameCommandAliasMiddleware, messageFromCommandInput } from '@zhin.js/game-kit';
|
|
2
|
-
import {
|
|
2
|
+
import { getBjHelp, runBjCommand } from '../../src/bj-command.js';
|
|
3
3
|
import { resolveGameServices } from '../../src/runtime-store.js';
|
|
4
4
|
|
|
5
5
|
function normalizeBjAction(raw: string): string {
|
|
@@ -13,10 +13,12 @@ function normalizeBjAction(raw: string): string {
|
|
|
13
13
|
export default defineGameCommandAliasMiddleware({
|
|
14
14
|
aliases: ['21点', 'bj'],
|
|
15
15
|
async run(action, input, context) {
|
|
16
|
+
const message = messageFromCommandInput(input, {
|
|
17
|
+
formatCommand: (path) => context.input.formatCommand?.(path, context.owner.id),
|
|
18
|
+
});
|
|
16
19
|
const normalized = normalizeBjAction(String(action ?? ''));
|
|
17
|
-
if (!normalized || normalized === 'help') return
|
|
20
|
+
if (!normalized || normalized === 'help') return getBjHelp(message);
|
|
18
21
|
const services = resolveGameServices(context);
|
|
19
|
-
const message = messageFromCommandInput(input);
|
|
20
22
|
return runBjCommand(services, message, normalized);
|
|
21
23
|
},
|
|
22
24
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-blackjack",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.16",
|
|
4
4
|
"description": "Zhin.js 21 点(Blackjack)(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: 'Blackjack',
|
|
16
16
|
},
|
|
17
17
|
game: {
|
|
18
|
+
commandPath: 'bj',
|
|
19
|
+
titleI18n: { en: 'Blackjack' },
|
|
20
|
+
descriptionI18n: { en: 'Beat the dealer without going over 21' },
|
|
21
|
+
quickStartI18n: { en: 'start' },
|
|
18
22
|
id: 'blackjack',
|
|
19
23
|
title: '21 点',
|
|
20
24
|
icon: '🃏',
|
package/src/bj-command.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { formatGameHelp, gameCommandFeedback, gameCommandHint, type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
|
|
2
2
|
import { continueGame, handleChoice, startGame } from './game-flow.js';
|
|
3
3
|
import type { SessionService } from './session-service.js';
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
'🃏 **21 点**',
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'• `/21点 继续` — 刷新界面',
|
|
12
|
-
'• `/21点 放弃` — 结束本局',
|
|
13
|
-
'• 对局中点击 **要牌** / **停牌**',
|
|
14
|
-
].join('\n');
|
|
5
|
+
export function getBjHelp(message: Pick<GameMessageLike, 'locale' | 'formatCommand'> = {}): string {
|
|
6
|
+
return formatGameHelp(message, { 'zh-CN': "🃏 **21 点**", en: "🃏 **Blackjack**" }, 'bj', ['start', 'continue', 'quit'],
|
|
7
|
+
{ 'zh-CN': "尽量让手牌点数接近 21 且不超过,比庄家大即获胜。对局中点击要牌或停牌。", en: "Get as close to 21 as possible without going over, and beat the dealer. Choose Hit or Stand during play." });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const BJ_HELP = getBjHelp();
|
|
15
11
|
|
|
16
12
|
export async function runBjCommand(
|
|
17
13
|
services: SessionService,
|
|
@@ -19,7 +15,7 @@ export async function runBjCommand(
|
|
|
19
15
|
action: string,
|
|
20
16
|
): Promise<GameReply> {
|
|
21
17
|
const a = action.trim().toLowerCase() || 'help';
|
|
22
|
-
if (a === 'help' || a === '帮助') return
|
|
18
|
+
if (a === 'help' || a === '帮助') return getBjHelp(message);
|
|
23
19
|
if (a === 'start' || a === '开始') return (await startGame(services, message)) ?? '';
|
|
24
20
|
if (a === 'continue' || a === '继续') return continueGame(services, message);
|
|
25
21
|
if (a === 'quit' || a === '放弃') {
|
|
@@ -27,8 +23,8 @@ export async function runBjCommand(
|
|
|
27
23
|
`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`,
|
|
28
24
|
message.$sender.id,
|
|
29
25
|
);
|
|
30
|
-
if (!session) return
|
|
26
|
+
if (!session) return gameCommandFeedback(message, 'noGame');
|
|
31
27
|
return (await handleChoice(services, message, session.id, 'quit')) ?? '';
|
|
32
28
|
}
|
|
33
|
-
return
|
|
29
|
+
return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getBjHelp(message);
|
|
34
30
|
}
|
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
|
BJ_PREFIX,
|
|
@@ -55,11 +56,12 @@ export async function startGame(
|
|
|
55
56
|
): Promise<GameReply | undefined> {
|
|
56
57
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
57
58
|
const active = await services.getActiveByChannel(ch);
|
|
59
|
+
const locale = resolveLocale(active ? active.locale : message.locale);
|
|
58
60
|
if (active) {
|
|
59
61
|
if (active.player_id === message.$sender.id) {
|
|
60
|
-
return
|
|
62
|
+
return messages(locale, 'text1');
|
|
61
63
|
}
|
|
62
|
-
return
|
|
64
|
+
return messages(locale, 'text2', { p0: active.player_name });
|
|
63
65
|
}
|
|
64
66
|
const session = await services.createSession(message);
|
|
65
67
|
const natural = naturalOutcome(session);
|
|
@@ -77,7 +79,8 @@ export async function continueGame(
|
|
|
77
79
|
`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`,
|
|
78
80
|
message.$sender.id,
|
|
79
81
|
);
|
|
80
|
-
|
|
82
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
83
|
+
if (!session) return messages(locale, 'text3');
|
|
81
84
|
return renderView(session, message);
|
|
82
85
|
}
|
|
83
86
|
|
|
@@ -88,15 +91,16 @@ export async function handleChoice(
|
|
|
88
91
|
choiceId: string,
|
|
89
92
|
): Promise<GameReply | null> {
|
|
90
93
|
const session = await services.getById(sessionId);
|
|
91
|
-
|
|
92
|
-
if (session
|
|
94
|
+
const locale = resolveLocale(session ? session.locale : message.locale);
|
|
95
|
+
if (!session) return messages(locale, 'text4');
|
|
96
|
+
if (session.player_id !== message.$sender.id) return messages(locale, 'text5');
|
|
93
97
|
|
|
94
98
|
if (session.status !== 'active' && choiceId === 'restart') {
|
|
95
99
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
96
100
|
return (await startGame(services, message)) ?? null;
|
|
97
101
|
}
|
|
98
102
|
|
|
99
|
-
if (session.status !== 'active') return '
|
|
103
|
+
if (session.status !== 'active') return messages(locale, 'text6');
|
|
100
104
|
|
|
101
105
|
if (choiceId === 'quit') {
|
|
102
106
|
await services.updateSession(session.id, { status: 'aborted' });
|
|
@@ -109,7 +113,7 @@ export async function handleChoice(
|
|
|
109
113
|
|
|
110
114
|
if (choiceId === 'hit') {
|
|
111
115
|
const card = deck.pop();
|
|
112
|
-
if (!card) return '
|
|
116
|
+
if (!card) return messages(locale, 'text7');
|
|
113
117
|
player = [...player, card];
|
|
114
118
|
await services.updateSession(session.id, {
|
|
115
119
|
deck_json: JSON.stringify(deck),
|
|
@@ -122,7 +126,7 @@ export async function handleChoice(
|
|
|
122
126
|
return renderView(updated, message);
|
|
123
127
|
}
|
|
124
128
|
|
|
125
|
-
if (choiceId !== 'stand') return '
|
|
129
|
+
if (choiceId !== 'stand') return messages(locale, 'text8');
|
|
126
130
|
|
|
127
131
|
dealer = await dealerPlay(deck, dealer);
|
|
128
132
|
await services.updateSession(session.id, {
|
|
@@ -136,3 +140,14 @@ export async function handleChoice(
|
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
export { BJ_PREFIX, handValue, TARGET };
|
|
143
|
+
|
|
144
|
+
const messages = createMessages({
|
|
145
|
+
text1: { 'zh-CN': "你已有进行中的 21 点,请使用当前对局的操作入口。", en: "You already have an active blackjack game. Continue using its controls." },
|
|
146
|
+
text2: { 'zh-CN': "本频道 {p0} 正在玩 21 点。", en: "{p0} is playing blackjack in this channel." },
|
|
147
|
+
text3: { 'zh-CN': "你没有进行中的 21 点,请使用当前对局的操作入口。", en: "You have no active blackjack game." },
|
|
148
|
+
text4: { 'zh-CN': "对局不存在。", en: "This game no longer exists." },
|
|
149
|
+
text5: { 'zh-CN': "这是别人的对局。", en: "This game belongs to another player." },
|
|
150
|
+
text6: { 'zh-CN': "对局已结束,请点击再来一局。", en: "This game has ended. Choose Play again." },
|
|
151
|
+
text7: { 'zh-CN': "牌堆已空。", en: "The deck is empty." },
|
|
152
|
+
text8: { 'zh-CN': "无效操作。", en: "Invalid action." },
|
|
153
|
+
});
|
package/src/models.ts
CHANGED
|
@@ -6,6 +6,7 @@ declare module '@zhin.js/core' {
|
|
|
6
6
|
interface Models {
|
|
7
7
|
bj_sessions: {
|
|
8
8
|
id: string;
|
|
9
|
+
locale?: 'zh-CN' | 'en' | null;
|
|
9
10
|
adapter: string;
|
|
10
11
|
endpoint: string;
|
|
11
12
|
channel_type: string;
|
|
@@ -27,10 +28,11 @@ export type BjSessionRow = Models['bj_sessions'];
|
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
export function defineHostTables(
|
|
30
|
-
db: { define: (name: string, definition: Record<string, unknown
|
|
31
|
+
db: { define: (name: string, definition: Record<string, unknown>, options?: { readonly addColumns?: readonly string[] }) => void },
|
|
31
32
|
): void {
|
|
32
33
|
db.define('bj_sessions', {
|
|
33
34
|
id: { type: 'text', primary: true },
|
|
35
|
+
locale: { type: 'text', nullable: true },
|
|
34
36
|
adapter: { type: 'text', nullable: false },
|
|
35
37
|
endpoint: { type: 'text', nullable: false },
|
|
36
38
|
channel_type: { type: 'text', nullable: false },
|
|
@@ -44,5 +46,5 @@ export function defineHostTables(
|
|
|
44
46
|
status: { type: 'text', default: 'active' },
|
|
45
47
|
updated_at: { type: 'bigint', default: 0 },
|
|
46
48
|
created_at: { type: 'bigint', default: 0 },
|
|
47
|
-
});
|
|
49
|
+
}, { addColumns: ['locale'] });
|
|
48
50
|
}
|
package/src/session-service.ts
CHANGED
|
@@ -38,6 +38,7 @@ export class SessionService extends BaseSessionService<BjSessionRow> {
|
|
|
38
38
|
const now = Date.now();
|
|
39
39
|
const row: BjSessionRow = {
|
|
40
40
|
id: generateSessionId(),
|
|
41
|
+
locale: message.locale ?? 'zh-CN',
|
|
41
42
|
adapter: String(message.$adapter),
|
|
42
43
|
endpoint: message.$endpoint,
|
|
43
44
|
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 { BJ_PREFIX, formatHand, handValue, isBlackjack, TARGET } from './engine.js';
|
|
@@ -13,29 +14,29 @@ export function buildBjView(
|
|
|
13
14
|
const player = parseCards(session.player_cards_json);
|
|
14
15
|
const dealer = parseCards(session.dealer_cards_json);
|
|
15
16
|
const lines = [
|
|
16
|
-
|
|
17
|
+
messages(session.locale ?? undefined, 'text1'),
|
|
17
18
|
'',
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
messages(session.locale ?? undefined, 'text2', { p0: formatHand(player) }),
|
|
20
|
+
messages(session.locale ?? undefined, 'text3', { p0: revealDealer || terminal ? formatHand(dealer) : formatHand(dealer, true) }),
|
|
20
21
|
'',
|
|
21
22
|
];
|
|
22
23
|
|
|
23
24
|
if (terminal) {
|
|
24
|
-
if (session.status === 'won') lines.push(
|
|
25
|
-
else if (session.status === 'lost') lines.push(
|
|
26
|
-
else if (session.status === 'draw') lines.push(
|
|
27
|
-
else lines.push(
|
|
28
|
-
lines.push('',
|
|
25
|
+
if (session.status === 'won') lines.push(messages(session.locale ?? undefined, 'text4'));
|
|
26
|
+
else if (session.status === 'lost') lines.push(messages(session.locale ?? undefined, 'text5'));
|
|
27
|
+
else if (session.status === 'draw') lines.push(messages(session.locale ?? undefined, 'text6'));
|
|
28
|
+
else lines.push(messages(session.locale ?? undefined, 'text7'));
|
|
29
|
+
lines.push('', messages(session.locale ?? undefined, 'text8'));
|
|
29
30
|
} else {
|
|
30
|
-
lines.push(
|
|
31
|
+
lines.push(messages(session.locale ?? undefined, 'text9', { p0: TARGET }));
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
const choices = terminal
|
|
34
|
-
? [{ id: 'restart', label:
|
|
35
|
+
? [{ id: 'restart', label: messages(session.locale ?? undefined, 'text10'), style: 'primary' as const, keepEnabledWhenTerminal: true }]
|
|
35
36
|
: [
|
|
36
|
-
{ id: 'hit', label:
|
|
37
|
-
{ id: 'stand', label:
|
|
38
|
-
{ id: 'quit', label:
|
|
37
|
+
{ id: 'hit', label: messages(session.locale ?? undefined, 'text11'), style: 'primary' as const },
|
|
38
|
+
{ id: 'stand', label: messages(session.locale ?? undefined, 'text12'), style: 'secondary' as const },
|
|
39
|
+
{ id: 'quit', label: messages(session.locale ?? undefined, 'text13'), style: 'danger' as const },
|
|
39
40
|
];
|
|
40
41
|
|
|
41
42
|
return buildChoiceKeyboard({
|
|
@@ -44,7 +45,7 @@ export function buildBjView(
|
|
|
44
45
|
narrative: lines.join('\n'),
|
|
45
46
|
choices,
|
|
46
47
|
terminal,
|
|
47
|
-
fallbackHint: terminal ?
|
|
48
|
+
fallbackHint: terminal ? messages(session.locale ?? undefined, 'text14') : messages(session.locale ?? undefined, 'text15'),
|
|
48
49
|
interactionProfile: terminal ? 'terminal' : 'gameplay',
|
|
49
50
|
channelType,
|
|
50
51
|
});
|
|
@@ -70,3 +71,21 @@ export function naturalOutcome(session: BjSessionRow): 'won' | 'lost' | 'draw' |
|
|
|
70
71
|
export function playerBust(session: BjSessionRow): boolean {
|
|
71
72
|
return handValue(parseCards(session.player_cards_json)) > TARGET;
|
|
72
73
|
}
|
|
74
|
+
|
|
75
|
+
const messages = createMessages({
|
|
76
|
+
text1: { 'zh-CN': "🃏 **21 点**", en: "🃏 **Blackjack**" },
|
|
77
|
+
text2: { 'zh-CN': "你的牌:{p0}", en: "Your hand: {p0}" },
|
|
78
|
+
text3: { 'zh-CN': "庄家:{p0}", en: "Dealer: {p0}" },
|
|
79
|
+
text4: { 'zh-CN': "🎉 **你赢了!**", en: "🎉 **You won!**" },
|
|
80
|
+
text5: { 'zh-CN': "💀 **你输了**", en: "💀 **You lost**" },
|
|
81
|
+
text6: { 'zh-CN': "🤝 **平局**", en: "🤝 **Draw**" },
|
|
82
|
+
text7: { 'zh-CN': "🏳️ **本局已放弃。**", en: "🏳️ **You quit this game.**" },
|
|
83
|
+
text8: { 'zh-CN': "点击「再来一局」开始新局。", en: "Choose “Play again” to start a new game." },
|
|
84
|
+
text9: { 'zh-CN': "目标:尽量接近 {p0} 且不超过。", en: "Get as close to {p0} as possible without going over." },
|
|
85
|
+
text10: { 'zh-CN': "🔄 再来一局", en: "🔄 Play again" },
|
|
86
|
+
text11: { 'zh-CN': "➕ 要牌", en: "➕ Hit" },
|
|
87
|
+
text12: { 'zh-CN': "✋ 停牌", en: "✋ Stand" },
|
|
88
|
+
text13: { 'zh-CN': "🏳️ 放弃", en: "🏳️ Quit" },
|
|
89
|
+
text14: { 'zh-CN': "回复 1 再来一局", en: "Reply 1 to play again" },
|
|
90
|
+
text15: { 'zh-CN': "1 要牌 · 2 停牌 · 3 放弃", en: "1 Hit · 2 Stand · 3 Quit" },
|
|
91
|
+
});
|