@zhin.js/plugin-dungeon-expedition 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/src/view.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { createMessages, resolveLocale, type Locale } from 'zhin.js/i18n';
1
2
  import type { SendContent } from '@zhin.js/core/runtime';
2
3
  import {
3
4
  buildChoiceKeyboard,
@@ -20,35 +21,35 @@ export function parseDungeonSessionToken(
20
21
  return { sessionId: match[1], revision: Number(match[2]) };
21
22
  }
22
23
 
23
- export function choicesForState(state: Readonly<DungeonState>): ChoiceOption[] {
24
+ export function choicesForState(state: Readonly<DungeonState>, locale?: Locale): ChoiceOption[] {
24
25
  if (state.phase === 'completed') {
25
26
  return [{
26
27
  id: 'restart',
27
- label: '再来一局',
28
+ label: messages(locale, 'text1'),
28
29
  style: 'primary',
29
30
  keepEnabledWhenTerminal: true,
30
31
  }];
31
32
  }
32
33
  if (state.phase === 'lobby') {
33
34
  return [
34
- { id: 'join', label: '加入队伍', style: 'secondary' },
35
- { id: 'ready', label: '准备/取消', style: 'secondary' },
36
- { id: 'start', label: '开始远征', style: 'primary' },
37
- { id: 'abort', label: '解散队伍', style: 'danger' },
35
+ { id: 'join', label: messages(locale, 'text2'), style: 'secondary' },
36
+ { id: 'ready', label: messages(locale, 'text3'), style: 'secondary' },
37
+ { id: 'start', label: messages(locale, 'text4'), style: 'primary' },
38
+ { id: 'abort', label: messages(locale, 'text5'), style: 'danger' },
38
39
  ];
39
40
  }
40
41
  if (state.phase === 'combat') {
41
42
  return [
42
- { id: 'attack', label: '攻击', style: 'primary' },
43
- { id: 'defend', label: '防御', style: 'secondary' },
44
- { id: 'potion', label: '药水', style: 'secondary' },
45
- { id: 'abort', label: '结束远征', style: 'danger' },
43
+ { id: 'attack', label: messages(locale, 'text6'), style: 'primary' },
44
+ { id: 'defend', label: messages(locale, 'text7'), style: 'secondary' },
45
+ { id: 'potion', label: messages(locale, 'text8'), style: 'secondary' },
46
+ { id: 'abort', label: messages(locale, 'text9'), style: 'danger' },
46
47
  ];
47
48
  }
48
49
  return [
49
- { id: 'explore', label: '探索下一房间', style: 'primary' },
50
- { id: 'potion', label: '使用药水', style: 'secondary' },
51
- { id: 'abort', label: '结束远征', style: 'danger' },
50
+ { id: 'explore', label: messages(locale, 'text10'), style: 'primary' },
51
+ { id: 'potion', label: messages(locale, 'text11'), style: 'secondary' },
52
+ { id: 'abort', label: messages(locale, 'text9'), style: 'danger' },
52
53
  ];
53
54
  }
54
55
 
@@ -57,38 +58,39 @@ export function buildDungeonView(
57
58
  state: Readonly<DungeonState>,
58
59
  channelType?: string,
59
60
  ): SendContent {
61
+ const locale = resolveLocale(session.locale);
60
62
  const current = activePlayer(state);
61
63
  const lines = [
62
- `地牢远征 · 第 ${state.floor}/${3} 层 · 房间 ${state.room}/${4}`,
63
- `状态:${phaseLabel(state)}`,
64
+ messages(locale, 'text12', { p0: state.floor, p1: 3, p2: state.room, p3: 4 }),
65
+ messages(locale, 'text13', { p0: phaseLabel(state, locale) }),
64
66
  '',
65
67
  ...state.players.map((player, index) => {
66
- const turn = current?.id === player.id && state.phase !== 'lobby' ? ' <- 当前回合' : '';
67
- const ready = state.phase === 'lobby' ? player.ready ? ' [已准备]' : ' [未准备]' : '';
68
+ const turn = current?.id === player.id && state.phase !== 'lobby' ? messages(locale, 'text14') : '';
69
+ const ready = state.phase === 'lobby' ? player.ready ? messages(locale, 'text15') : messages(locale, 'text16') : '';
68
70
  return `${index + 1}. ${player.name}${ready} HP ${player.hp}/${player.maxHp}`
69
- + ` · 药水 ${player.potions} · 金币 ${player.gold}${turn}`;
71
+ + messages(locale, 'text17', { p0: player.potions, p1: player.gold, p2: turn });
70
72
  }),
71
73
  ];
72
74
  if (state.enemy) {
73
75
  lines.push(
74
76
  '',
75
- `${state.enemy.boss ? '守层者' : '敌人'}:${state.enemy.name}`,
76
- `HP ${state.enemy.hp}/${state.enemy.maxHp} · 攻击 ${state.enemy.attack}`,
77
+ `${state.enemy.boss ? messages(locale, 'text18') : messages(locale, 'text19')}:${state.enemy.name}`,
78
+ messages(locale, 'text20', { p0: state.enemy.hp, p1: state.enemy.maxHp, p2: state.enemy.attack }),
77
79
  );
78
80
  }
79
- lines.push('', '最近事件:', ...state.log.slice(-4).map((line) => `- ${line}`));
81
+ lines.push('', messages(locale, 'text21'), ...state.log.slice(-4).map((line) => `- ${line}`));
80
82
  if (state.phase === 'completed') {
81
83
  lines.push(
82
84
  '',
83
85
  state.result === 'victory'
84
- ? '远征胜利,地牢已被征服。'
86
+ ? messages(locale, 'text22')
85
87
  : state.result === 'aborted'
86
- ? '本次远征由队长结束。'
87
- : '远征失败,队伍全员倒下。',
88
+ ? messages(locale, 'text23')
89
+ : messages(locale, 'text24'),
88
90
  );
89
91
  }
90
92
 
91
- const choices = choicesForState(state);
93
+ const choices = choicesForState(state, locale);
92
94
  return buildChoiceKeyboard({
93
95
  gamePrefix: DUNGEON_PREFIX,
94
96
  sessionId: dungeonSessionToken(session),
@@ -103,11 +105,44 @@ export function buildDungeonView(
103
105
  });
104
106
  }
105
107
 
106
- function phaseLabel(state: Readonly<DungeonState>): string {
107
- if (state.phase === 'lobby') return '等待队员';
108
- if (state.phase === 'exploring') return '探索中';
109
- if (state.phase === 'combat') return '战斗中';
110
- if (state.result === 'victory') return '胜利';
111
- if (state.result === 'aborted') return '已结束';
112
- return '失败';
108
+ function phaseLabel(state: Readonly<DungeonState>, locale?: Locale): string {
109
+ if (state.phase === 'lobby') return messages(locale, 'text25');
110
+ if (state.phase === 'exploring') return messages(locale, 'text26');
111
+ if (state.phase === 'combat') return messages(locale, 'text27');
112
+ if (state.result === 'victory') return messages(locale, 'text28');
113
+ if (state.result === 'aborted') return messages(locale, 'text29');
114
+ return messages(locale, 'text30');
113
115
  }
116
+
117
+ const messages = createMessages({
118
+ text1: { 'zh-CN': "再来一局", en: "Play again" },
119
+ text2: { 'zh-CN': "加入队伍", en: "Join party" },
120
+ text3: { 'zh-CN': "准备/取消", en: "Ready / Not ready" },
121
+ text4: { 'zh-CN': "开始远征", en: "Start expedition" },
122
+ text5: { 'zh-CN': "解散队伍", en: "Disband party" },
123
+ text6: { 'zh-CN': "攻击", en: "Attack" },
124
+ text7: { 'zh-CN': "防御", en: "Defend" },
125
+ text8: { 'zh-CN': "药水", en: "Potion" },
126
+ text9: { 'zh-CN': "结束远征", en: "End expedition" },
127
+ text10: { 'zh-CN': "探索下一房间", en: "Explore next room" },
128
+ text11: { 'zh-CN': "使用药水", en: "Use potion" },
129
+ text12: { 'zh-CN': "地牢远征 · 第 {p0}/{p1} 层 · 房间 {p2}/{p3}", en: "Dungeon Expedition · Floor {p0}/{p1} · Room {p2}/{p3}" },
130
+ text13: { 'zh-CN': "状态:{p0}", en: "Status: {p0}" },
131
+ text14: { 'zh-CN': " <- 当前回合", en: " <- Current turn" },
132
+ text15: { 'zh-CN': " [已准备]", en: " [Ready]" },
133
+ text16: { 'zh-CN': " [未准备]", en: " [Not ready]" },
134
+ text17: { 'zh-CN': " · 药水 {p0} · 金币 {p1}{p2}", en: " · Potions {p0} · Gold {p1}{p2}" },
135
+ text18: { 'zh-CN': "守层者", en: "Floor guardian" },
136
+ text19: { 'zh-CN': "敌人", en: "Enemy" },
137
+ text20: { 'zh-CN': "HP {p0}/{p1} · 攻击 {p2}", en: "HP {p0}/{p1} · Attack {p2}" },
138
+ text21: { 'zh-CN': "最近事件:", en: "Recent events:" },
139
+ text22: { 'zh-CN': "远征胜利,地牢已被征服。", en: "Expedition victory! The dungeon is conquered." },
140
+ text23: { 'zh-CN': "本次远征由队长结束。", en: "The leader ended this expedition." },
141
+ text24: { 'zh-CN': "远征失败,队伍全员倒下。", en: "Expedition failed. The entire party fell." },
142
+ text25: { 'zh-CN': "等待队员", en: "Waiting for players" },
143
+ text26: { 'zh-CN': "探索中", en: "Exploring" },
144
+ text27: { 'zh-CN': "战斗中", en: "In combat" },
145
+ text28: { 'zh-CN': "胜利", en: "Victory" },
146
+ text29: { 'zh-CN': "已结束", en: "Ended" },
147
+ text30: { 'zh-CN': "失败", en: "Defeat" },
148
+ });