@zhin.js/plugin-text-adventure 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.
- package/commands/adv/[[action]]/index.js +4 -4
- package/commands/adv/[[action]]/index.ts +4 -4
- package/lib/achievements.d.ts +4 -1
- package/lib/achievements.js +18 -17
- package/lib/achievements.js.map +1 -1
- package/lib/adv-command.d.ts +1 -0
- package/lib/adv-command.js +31 -20
- package/lib/adv-command.js.map +1 -1
- package/lib/game-flow.d.ts +1 -1
- package/lib/game-flow.js +50 -21
- 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/profile-format.d.ts +4 -3
- package/lib/profile-format.js +14 -13
- package/lib/profile-format.js.map +1 -1
- package/lib/scene-view.js +5 -3
- package/lib/scene-view.js.map +1 -1
- package/lib/session-service.js +1 -0
- package/lib/session-service.js.map +1 -1
- package/lib/story-catalog.d.ts +4 -2
- package/lib/story-catalog.js +59 -9
- package/lib/story-catalog.js.map +1 -1
- package/lib/story-items.d.ts +2 -1
- package/lib/story-items.js +19 -2
- package/lib/story-items.js.map +1 -1
- package/lib/story-scenes.d.ts +2 -1
- package/lib/story-scenes.js +1358 -464
- package/lib/story-scenes.js.map +1 -1
- package/lib/story.d.ts +4 -3
- package/lib/story.js +8 -8
- package/lib/story.js.map +1 -1
- package/middlewares/adv-alias/index.js +5 -3
- package/middlewares/adv-alias/index.ts +5 -3
- package/package.json +7 -7
- package/plugin.js +4 -0
- package/src/achievements.ts +21 -17
- package/src/adv-command.ts +35 -24
- package/src/game-flow.ts +51 -22
- package/src/models.ts +4 -2
- package/src/profile-format.ts +15 -13
- package/src/scene-view.ts +5 -3
- package/src/session-service.ts +1 -0
- package/src/story-catalog.ts +63 -10
- package/src/story-items.ts +21 -2
- package/src/story-scenes.ts +1103 -206
- package/src/story.ts +9 -8
package/src/story-scenes.ts
CHANGED
|
@@ -1,68 +1,70 @@
|
|
|
1
|
+
import { createMessages, type Locale } from 'zhin.js/i18n';
|
|
1
2
|
import type { GameState, Scene } from './story-types.js';
|
|
2
3
|
|
|
3
4
|
const T = (lines: string[]) => lines.join('\n');
|
|
4
5
|
|
|
5
6
|
/** 非终局场景 28 个 + 终局 12 个 */
|
|
6
|
-
|
|
7
|
+
function createScenes(locale: Locale): Record<string, Scene> {
|
|
8
|
+
return {
|
|
7
9
|
start: {
|
|
8
10
|
id: 'start',
|
|
9
11
|
text: (s) => {
|
|
10
12
|
const lines = [
|
|
11
|
-
|
|
13
|
+
text(locale, 'story1'),
|
|
12
14
|
'',
|
|
13
|
-
'
|
|
15
|
+
text(locale, 'story2'),
|
|
14
16
|
];
|
|
15
|
-
if (s.inventory.includes('torch')) lines.push('',
|
|
16
|
-
if (s.flags.spirit_met) lines.push('',
|
|
17
|
-
if (s.flags.saw_map) lines.push('',
|
|
17
|
+
if (s.inventory.includes('torch')) lines.push('', text(locale, 'story3'));
|
|
18
|
+
if (s.flags.spirit_met) lines.push('', text(locale, 'story4'));
|
|
19
|
+
if (s.flags.saw_map) lines.push('', text(locale, 'story5'));
|
|
18
20
|
return lines.join('\n');
|
|
19
21
|
},
|
|
20
22
|
choices: [
|
|
21
|
-
{ id: 'push_door', label:
|
|
22
|
-
{ id: 'search_rubble', label:
|
|
23
|
-
{ id: 'climb_tower', label:
|
|
24
|
-
{ id: 'vine_path', label:
|
|
25
|
-
{ id: 'leave', label:
|
|
23
|
+
{ id: 'push_door', label: text(locale, 'story6'), style: 'primary' },
|
|
24
|
+
{ id: 'search_rubble', label: text(locale, 'story7') },
|
|
25
|
+
{ id: 'climb_tower', label: text(locale, 'story8') },
|
|
26
|
+
{ id: 'vine_path', label: text(locale, 'story9'), requires: (s) => s.flags.spirit_met },
|
|
27
|
+
{ id: 'leave', label: text(locale, 'story10'), style: 'danger' },
|
|
26
28
|
],
|
|
27
29
|
},
|
|
28
30
|
|
|
29
31
|
rubble: {
|
|
30
32
|
id: 'rubble',
|
|
31
33
|
text: T([
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
+
text(locale, 'story11'),
|
|
35
|
+
text(locale, 'story12'),
|
|
34
36
|
]),
|
|
35
37
|
choices: [
|
|
36
|
-
{ id: 'take_torch', label:
|
|
37
|
-
{ id: 'take_blade', label:
|
|
38
|
-
{ id: 'back_entrance', label:
|
|
38
|
+
{ id: 'take_torch', label: text(locale, 'story13'), requires: (s) => !s.inventory.includes('torch') },
|
|
39
|
+
{ id: 'take_blade', label: text(locale, 'story14'), requires: (s) => !s.inventory.includes('rusted_blade') },
|
|
40
|
+
{ id: 'back_entrance', label: text(locale, 'story15') },
|
|
39
41
|
],
|
|
40
42
|
},
|
|
41
43
|
|
|
42
44
|
watchtower: {
|
|
43
45
|
id: 'watchtower',
|
|
44
46
|
text: (s) => T([
|
|
45
|
-
|
|
47
|
+
text(locale, 'story16'),
|
|
46
48
|
'',
|
|
47
49
|
s.flags.saw_map
|
|
48
|
-
? '
|
|
49
|
-
: '
|
|
50
|
-
'
|
|
50
|
+
? text(locale, 'story17')
|
|
51
|
+
: text(locale, 'story18'),
|
|
52
|
+
text(locale, 'story19'),
|
|
51
53
|
]),
|
|
52
54
|
choices: [
|
|
53
|
-
{ id: 'survey_map', label:
|
|
54
|
-
{ id: 'take_chart_fragment', label:
|
|
55
|
-
{ id: 'enter_observatory', label:
|
|
56
|
-
{ id: 'descend_tower', label:
|
|
55
|
+
{ id: 'survey_map', label: text(locale, 'story20'), requires: (s) => !s.flags.saw_map },
|
|
56
|
+
{ id: 'take_chart_fragment', label: text(locale, 'story21'), requires: (s) => !s.inventory.includes('star_chart') },
|
|
57
|
+
{ id: 'enter_observatory', label: text(locale, 'story22'), requires: (s) => s.flags.saw_map },
|
|
58
|
+
{ id: 'descend_tower', label: text(locale, 'story23') },
|
|
57
59
|
],
|
|
58
60
|
},
|
|
59
61
|
|
|
60
62
|
vine_path: {
|
|
61
63
|
id: 'vine_path',
|
|
62
|
-
text: T([
|
|
64
|
+
text: T([text(locale, 'story24'), '', text(locale, 'story25')]),
|
|
63
65
|
choices: [
|
|
64
|
-
{ id: 'enter_garden', label:
|
|
65
|
-
{ id: 'back_entrance', label:
|
|
66
|
+
{ id: 'enter_garden', label: text(locale, 'story26') },
|
|
67
|
+
{ id: 'back_entrance', label: text(locale, 'story15') },
|
|
66
68
|
],
|
|
67
69
|
},
|
|
68
70
|
|
|
@@ -71,392 +73,392 @@ export const SCENES: Record<string, Scene> = {
|
|
|
71
73
|
text: (s) => {
|
|
72
74
|
const lit = s.inventory.includes('torch');
|
|
73
75
|
const lines = [
|
|
74
|
-
lit ?
|
|
75
|
-
'
|
|
76
|
+
lit ? text(locale, 'story27') : text(locale, 'story28'),
|
|
77
|
+
text(locale, 'story29'),
|
|
76
78
|
];
|
|
77
|
-
if (s.flags.knows_sequence) lines.push('',
|
|
79
|
+
if (s.flags.knows_sequence) lines.push('', text(locale, 'story30'));
|
|
78
80
|
return lines.join('\n');
|
|
79
81
|
},
|
|
80
82
|
choices: [
|
|
81
|
-
{ id: 'go_blue', label:
|
|
82
|
-
{ id: 'go_stairs', label:
|
|
83
|
-
{ id: 'go_flooded', label:
|
|
84
|
-
{ id: 'study_mural', label:
|
|
85
|
-
{ id: 'enter_bell_tower', label:
|
|
86
|
-
{ id: 'go_back', label:
|
|
83
|
+
{ id: 'go_blue', label: text(locale, 'story31') },
|
|
84
|
+
{ id: 'go_stairs', label: text(locale, 'story32') },
|
|
85
|
+
{ id: 'go_flooded', label: text(locale, 'story33') },
|
|
86
|
+
{ id: 'study_mural', label: text(locale, 'story34'), requires: (s) => s.inventory.includes('torch') },
|
|
87
|
+
{ id: 'enter_bell_tower', label: text(locale, 'story35'), requires: (s) => s.flags.spirit_met },
|
|
88
|
+
{ id: 'go_back', label: text(locale, 'story36') },
|
|
87
89
|
],
|
|
88
90
|
},
|
|
89
91
|
|
|
90
92
|
mural_room: {
|
|
91
93
|
id: 'mural_room',
|
|
92
94
|
text: T([
|
|
93
|
-
|
|
95
|
+
text(locale, 'story37'),
|
|
94
96
|
'',
|
|
95
|
-
|
|
96
|
-
'
|
|
97
|
+
text(locale, 'story38'),
|
|
98
|
+
text(locale, 'story39'),
|
|
97
99
|
]),
|
|
98
100
|
choices: [
|
|
99
|
-
{ id: 'memorize', label:
|
|
100
|
-
{ id: 'enter_whisper', label:
|
|
101
|
-
{ id: 'back_corridor', label:
|
|
101
|
+
{ id: 'memorize', label: text(locale, 'story40') },
|
|
102
|
+
{ id: 'enter_whisper', label: text(locale, 'story41'), requires: (s) => s.flags.knows_sequence },
|
|
103
|
+
{ id: 'back_corridor', label: text(locale, 'story42') },
|
|
102
104
|
],
|
|
103
105
|
},
|
|
104
106
|
|
|
105
107
|
whisper_gallery: {
|
|
106
108
|
id: 'whisper_gallery',
|
|
107
109
|
text: T([
|
|
108
|
-
|
|
110
|
+
text(locale, 'story43'),
|
|
109
111
|
'',
|
|
110
|
-
'
|
|
111
|
-
'
|
|
112
|
+
text(locale, 'story44'),
|
|
113
|
+
text(locale, 'story45'),
|
|
112
114
|
]),
|
|
113
115
|
choices: [
|
|
114
|
-
{ id: 'listen_deep', label:
|
|
115
|
-
{ id: 'back_mural', label:
|
|
116
|
+
{ id: 'listen_deep', label: text(locale, 'story46'), requires: (s) => !s.flags.whisper_lore },
|
|
117
|
+
{ id: 'back_mural', label: text(locale, 'story47') },
|
|
116
118
|
],
|
|
117
119
|
},
|
|
118
120
|
|
|
119
121
|
spring: {
|
|
120
122
|
id: 'spring',
|
|
121
123
|
text: (s) => T([
|
|
122
|
-
|
|
124
|
+
text(locale, 'story48'),
|
|
123
125
|
'',
|
|
124
|
-
s.flags.spirit_met ? '
|
|
125
|
-
!s.flags.healed ? '
|
|
126
|
+
s.flags.spirit_met ? text(locale, 'story49') : text(locale, 'story50'),
|
|
127
|
+
!s.flags.healed ? text(locale, 'story51') : text(locale, 'story52'),
|
|
126
128
|
]),
|
|
127
129
|
choices: [
|
|
128
|
-
{ id: 'drink', label:
|
|
129
|
-
{ id: 'take_gem', label:
|
|
130
|
-
{ id: 'talk_spirit', label:
|
|
131
|
-
{ id: 'offer_gem', label:
|
|
132
|
-
{ id: 'leave_spring', label:
|
|
130
|
+
{ id: 'drink', label: text(locale, 'story53'), requires: (s) => !s.flags.healed },
|
|
131
|
+
{ id: 'take_gem', label: text(locale, 'story54'), requires: (s) => !s.inventory.includes('gem') },
|
|
132
|
+
{ id: 'talk_spirit', label: text(locale, 'story55'), requires: (s) => !s.flags.spirit_met },
|
|
133
|
+
{ id: 'offer_gem', label: text(locale, 'story56'), requires: (s) => s.inventory.includes('gem') && !s.inventory.includes('amulet') },
|
|
134
|
+
{ id: 'leave_spring', label: text(locale, 'story57') },
|
|
133
135
|
],
|
|
134
136
|
},
|
|
135
137
|
|
|
136
138
|
flooded_hall: {
|
|
137
139
|
id: 'flooded_hall',
|
|
138
140
|
text: (s) => T([
|
|
139
|
-
|
|
141
|
+
text(locale, 'story58'),
|
|
140
142
|
'',
|
|
141
|
-
'
|
|
142
|
-
s.inventory.includes('elf_feather') ? '
|
|
143
|
+
text(locale, 'story59'),
|
|
144
|
+
s.inventory.includes('elf_feather') ? text(locale, 'story60') : text(locale, 'story61'),
|
|
143
145
|
]),
|
|
144
146
|
choices: [
|
|
145
|
-
{ id: 'wade_market', label:
|
|
146
|
-
{ id: 'use_feather_wade', label:
|
|
147
|
-
{ id: 'drink_elixir_warm', label:
|
|
148
|
-
{ id: 'back_corridor', label:
|
|
147
|
+
{ id: 'wade_market', label: text(locale, 'story62') },
|
|
148
|
+
{ id: 'use_feather_wade', label: text(locale, 'story63'), requires: (s) => s.inventory.includes('elf_feather') },
|
|
149
|
+
{ id: 'drink_elixir_warm', label: text(locale, 'story64'), requires: (s) => s.inventory.includes('elixir') },
|
|
150
|
+
{ id: 'back_corridor', label: text(locale, 'story42') },
|
|
149
151
|
],
|
|
150
152
|
},
|
|
151
153
|
|
|
152
154
|
market_ruins: {
|
|
153
155
|
id: 'market_ruins',
|
|
154
156
|
text: T([
|
|
155
|
-
|
|
157
|
+
text(locale, 'story65'),
|
|
156
158
|
'',
|
|
157
|
-
'
|
|
159
|
+
text(locale, 'story66'),
|
|
158
160
|
]),
|
|
159
161
|
choices: [
|
|
160
|
-
{ id: 'buy_mask_coin', label:
|
|
161
|
-
{ id: 'trade_gem_coin', label:
|
|
162
|
-
{ id: 'go_bridge', label:
|
|
163
|
-
{ id: 'leave_market', label:
|
|
162
|
+
{ id: 'buy_mask_coin', label: text(locale, 'story67'), requires: (s) => s.inventory.includes('silver_coin') && !s.inventory.includes('masquerade_mask') },
|
|
163
|
+
{ id: 'trade_gem_coin', label: text(locale, 'story68'), requires: (s) => s.inventory.includes('gem') },
|
|
164
|
+
{ id: 'go_bridge', label: text(locale, 'story69') },
|
|
165
|
+
{ id: 'leave_market', label: text(locale, 'story70') },
|
|
164
166
|
],
|
|
165
167
|
},
|
|
166
168
|
|
|
167
169
|
garden: {
|
|
168
170
|
id: 'garden',
|
|
169
171
|
text: (s) => T([
|
|
170
|
-
|
|
172
|
+
text(locale, 'story71'),
|
|
171
173
|
'',
|
|
172
|
-
'
|
|
173
|
-
s.inventory.includes('herb') ? '
|
|
174
|
+
text(locale, 'story72'),
|
|
175
|
+
s.inventory.includes('herb') ? text(locale, 'story73') : text(locale, 'story74'),
|
|
174
176
|
]),
|
|
175
177
|
choices: [
|
|
176
|
-
{ id: 'pick_herb', label:
|
|
177
|
-
{ id: 'rest_tree', label:
|
|
178
|
-
{ id: 'enter_greenhouse', label:
|
|
179
|
-
{ id: 'open_iron_door', label:
|
|
180
|
-
{ id: 'stay_forever', label:
|
|
181
|
-
{ id: 'back_corridor', label:
|
|
178
|
+
{ id: 'pick_herb', label: text(locale, 'story75'), requires: (s) => !s.inventory.includes('herb') },
|
|
179
|
+
{ id: 'rest_tree', label: text(locale, 'story76'), requires: (s) => !s.flags.rested },
|
|
180
|
+
{ id: 'enter_greenhouse', label: text(locale, 'story77') },
|
|
181
|
+
{ id: 'open_iron_door', label: text(locale, 'story78'), requires: (s) => s.inventory.includes('key') },
|
|
182
|
+
{ id: 'stay_forever', label: text(locale, 'story79'), requires: (s) => s.flags.rested && s.flags.spirit_met },
|
|
183
|
+
{ id: 'back_corridor', label: text(locale, 'story42') },
|
|
182
184
|
],
|
|
183
185
|
},
|
|
184
186
|
|
|
185
187
|
greenhouse: {
|
|
186
188
|
id: 'greenhouse',
|
|
187
189
|
text: T([
|
|
188
|
-
|
|
190
|
+
text(locale, 'story80'),
|
|
189
191
|
'',
|
|
190
|
-
'
|
|
192
|
+
text(locale, 'story81'),
|
|
191
193
|
]),
|
|
192
194
|
choices: [
|
|
193
|
-
{ id: 'brew_elixir', label:
|
|
194
|
-
{ id: 'back_garden', label:
|
|
195
|
+
{ id: 'brew_elixir', label: text(locale, 'story82'), requires: (s) => s.inventory.includes('herb') && !s.inventory.includes('elixir') },
|
|
196
|
+
{ id: 'back_garden', label: text(locale, 'story83') },
|
|
195
197
|
],
|
|
196
198
|
},
|
|
197
199
|
|
|
198
200
|
library: {
|
|
199
201
|
id: 'library',
|
|
200
202
|
text: (s) => T([
|
|
201
|
-
|
|
203
|
+
text(locale, 'story84'),
|
|
202
204
|
'',
|
|
203
|
-
'
|
|
204
|
-
s.flags.read_archive ? '
|
|
205
|
+
text(locale, 'story85'),
|
|
206
|
+
s.flags.read_archive ? text(locale, 'story86') : text(locale, 'story87'),
|
|
205
207
|
]),
|
|
206
208
|
choices: [
|
|
207
|
-
{ id: 'take_scroll', label:
|
|
208
|
-
{ id: 'take_key', label:
|
|
209
|
-
{ id: 'read_archive', label:
|
|
210
|
-
{ id: 'enter_forge', label:
|
|
211
|
-
{ id: 'back_garden', label:
|
|
209
|
+
{ id: 'take_scroll', label: text(locale, 'story88'), requires: (s) => !s.inventory.includes('scroll') },
|
|
210
|
+
{ id: 'take_key', label: text(locale, 'story89'), requires: (s) => !s.inventory.includes('key') },
|
|
211
|
+
{ id: 'read_archive', label: text(locale, 'story90'), requires: (s) => !s.flags.read_archive },
|
|
212
|
+
{ id: 'enter_forge', label: text(locale, 'story91'), requires: (s) => s.inventory.includes('scroll') },
|
|
213
|
+
{ id: 'back_garden', label: text(locale, 'story83') },
|
|
212
214
|
],
|
|
213
215
|
},
|
|
214
216
|
|
|
215
217
|
ember_forge: {
|
|
216
218
|
id: 'ember_forge',
|
|
217
219
|
text: (s) => T([
|
|
218
|
-
|
|
220
|
+
text(locale, 'story92'),
|
|
219
221
|
'',
|
|
220
|
-
'
|
|
221
|
-
s.flags.forged_blade ? '
|
|
222
|
+
text(locale, 'story93'),
|
|
223
|
+
s.flags.forged_blade ? text(locale, 'story94') : text(locale, 'story95'),
|
|
222
224
|
]),
|
|
223
225
|
choices: [
|
|
224
|
-
{ id: 'forge_blade', label:
|
|
225
|
-
{ id: 'upgrade_amulet', label:
|
|
226
|
-
{ id: 'back_library', label:
|
|
226
|
+
{ id: 'forge_blade', label: text(locale, 'story96'), requires: (s) => s.inventory.includes('rusted_blade') && !s.flags.forged_blade },
|
|
227
|
+
{ id: 'upgrade_amulet', label: text(locale, 'story97'), requires: (s) => s.inventory.includes('amulet') && s.inventory.includes('moon_shard') && !s.flags.amulet_upgraded },
|
|
228
|
+
{ id: 'back_library', label: text(locale, 'story98') },
|
|
227
229
|
],
|
|
228
230
|
},
|
|
229
231
|
|
|
230
232
|
bell_tower: {
|
|
231
233
|
id: 'bell_tower',
|
|
232
234
|
text: T([
|
|
233
|
-
|
|
235
|
+
text(locale, 'story99'),
|
|
234
236
|
'',
|
|
235
|
-
'
|
|
237
|
+
text(locale, 'story100'),
|
|
236
238
|
]),
|
|
237
239
|
choices: [
|
|
238
|
-
{ id: 'ring_bell', label:
|
|
239
|
-
{ id: 'back_corridor', label:
|
|
240
|
+
{ id: 'ring_bell', label: text(locale, 'story101'), requires: (s) => !s.inventory.includes('spirit_bell') },
|
|
241
|
+
{ id: 'back_corridor', label: text(locale, 'story42') },
|
|
240
242
|
],
|
|
241
243
|
},
|
|
242
244
|
|
|
243
245
|
depths: {
|
|
244
246
|
id: 'depths',
|
|
245
247
|
text: T([
|
|
246
|
-
|
|
248
|
+
text(locale, 'story102'),
|
|
247
249
|
'',
|
|
248
|
-
'
|
|
250
|
+
text(locale, 'story103'),
|
|
249
251
|
]),
|
|
250
252
|
choices: [
|
|
251
|
-
{ id: 'fight', label:
|
|
252
|
-
{ id: 'fight_blade', label:
|
|
253
|
-
{ id: 'use_torch', label:
|
|
254
|
-
{ id: 'use_herb', label:
|
|
255
|
-
{ id: 'flee', label:
|
|
253
|
+
{ id: 'fight', label: text(locale, 'story104'), style: 'danger' },
|
|
254
|
+
{ id: 'fight_blade', label: text(locale, 'story105'), requires: (s) => s.flags.forged_blade },
|
|
255
|
+
{ id: 'use_torch', label: text(locale, 'story106'), requires: (s) => s.inventory.includes('torch') },
|
|
256
|
+
{ id: 'use_herb', label: text(locale, 'story107'), requires: (s) => s.inventory.includes('herb') },
|
|
257
|
+
{ id: 'flee', label: text(locale, 'story108') },
|
|
256
258
|
],
|
|
257
259
|
},
|
|
258
260
|
|
|
259
261
|
crypt_entry: {
|
|
260
262
|
id: 'crypt_entry',
|
|
261
263
|
text: T([
|
|
262
|
-
|
|
264
|
+
text(locale, 'story109'),
|
|
263
265
|
'',
|
|
264
|
-
'
|
|
266
|
+
text(locale, 'story110'),
|
|
265
267
|
]),
|
|
266
268
|
choices: [
|
|
267
|
-
{ id: 'go_vault', label:
|
|
268
|
-
{ id: 'go_catacombs', label:
|
|
269
|
-
{ id: 'go_spider', label:
|
|
270
|
-
{ id: 'go_sealed', label:
|
|
271
|
-
{ id: 'back_corridor', label:
|
|
269
|
+
{ id: 'go_vault', label: text(locale, 'story111') },
|
|
270
|
+
{ id: 'go_catacombs', label: text(locale, 'story112') },
|
|
271
|
+
{ id: 'go_spider', label: text(locale, 'story113') },
|
|
272
|
+
{ id: 'go_sealed', label: text(locale, 'story114'), requires: (s) => s.inventory.includes('spirit_bell') && s.inventory.includes('compass') },
|
|
273
|
+
{ id: 'back_corridor', label: text(locale, 'story42') },
|
|
272
274
|
],
|
|
273
275
|
},
|
|
274
276
|
|
|
275
277
|
spider_nest: {
|
|
276
278
|
id: 'spider_nest',
|
|
277
279
|
text: T([
|
|
278
|
-
|
|
280
|
+
text(locale, 'story115'),
|
|
279
281
|
'',
|
|
280
|
-
'
|
|
282
|
+
text(locale, 'story116'),
|
|
281
283
|
]),
|
|
282
284
|
choices: [
|
|
283
|
-
{ id: 'cut_web_blade', label:
|
|
284
|
-
{ id: 'burn_web', label:
|
|
285
|
-
{ id: 'flee_spider', label:
|
|
285
|
+
{ id: 'cut_web_blade', label: text(locale, 'story117'), requires: (s) => s.flags.forged_blade },
|
|
286
|
+
{ id: 'burn_web', label: text(locale, 'story118'), requires: (s) => s.inventory.includes('torch') },
|
|
287
|
+
{ id: 'flee_spider', label: text(locale, 'story119'), style: 'danger' },
|
|
286
288
|
],
|
|
287
289
|
},
|
|
288
290
|
|
|
289
291
|
shadow_maze: {
|
|
290
292
|
id: 'shadow_maze',
|
|
291
293
|
text: T([
|
|
292
|
-
|
|
294
|
+
text(locale, 'story120'),
|
|
293
295
|
'',
|
|
294
|
-
'
|
|
296
|
+
text(locale, 'story121'),
|
|
295
297
|
]),
|
|
296
298
|
choices: [
|
|
297
|
-
{ id: 'navigate_compass', label:
|
|
298
|
-
{ id: 'wander_maze', label:
|
|
299
|
-
{ id: 'back_spider', label:
|
|
299
|
+
{ id: 'navigate_compass', label: text(locale, 'story122'), requires: (s) => s.inventory.includes('compass') },
|
|
300
|
+
{ id: 'wander_maze', label: text(locale, 'story123'), style: 'danger' },
|
|
301
|
+
{ id: 'back_spider', label: text(locale, 'story124') },
|
|
300
302
|
],
|
|
301
303
|
},
|
|
302
304
|
|
|
303
305
|
catacombs: {
|
|
304
306
|
id: 'catacombs',
|
|
305
307
|
text: T([
|
|
306
|
-
|
|
308
|
+
text(locale, 'story125'),
|
|
307
309
|
'',
|
|
308
|
-
'
|
|
309
|
-
'
|
|
310
|
+
text(locale, 'story126'),
|
|
311
|
+
text(locale, 'story127'),
|
|
310
312
|
]),
|
|
311
313
|
choices: [
|
|
312
|
-
{ id: 'read_scroll', label:
|
|
313
|
-
{ id: 'dash_trap', label:
|
|
314
|
-
{ id: 'enter_prison', label:
|
|
315
|
-
{ id: 'take_key_skeleton', label:
|
|
316
|
-
{ id: 'back_crypt', label:
|
|
314
|
+
{ id: 'read_scroll', label: text(locale, 'story128'), requires: (s) => s.inventory.includes('scroll') },
|
|
315
|
+
{ id: 'dash_trap', label: text(locale, 'story129'), style: 'danger' },
|
|
316
|
+
{ id: 'enter_prison', label: text(locale, 'story130') },
|
|
317
|
+
{ id: 'take_key_skeleton', label: text(locale, 'story131'), requires: (s) => !s.inventory.includes('key') },
|
|
318
|
+
{ id: 'back_crypt', label: text(locale, 'story132') },
|
|
317
319
|
],
|
|
318
320
|
},
|
|
319
321
|
|
|
320
322
|
prison_cell: {
|
|
321
323
|
id: 'prison_cell',
|
|
322
324
|
text: T([
|
|
323
|
-
|
|
325
|
+
text(locale, 'story133'),
|
|
324
326
|
'',
|
|
325
|
-
'
|
|
326
|
-
'
|
|
327
|
+
text(locale, 'story134'),
|
|
328
|
+
text(locale, 'story135'),
|
|
327
329
|
]),
|
|
328
330
|
choices: [
|
|
329
|
-
{ id: 'take_coin', label:
|
|
330
|
-
{ id: 'free_ghost', label:
|
|
331
|
-
{ id: 'back_catacombs', label:
|
|
331
|
+
{ id: 'take_coin', label: text(locale, 'story136'), requires: (s) => !s.inventory.includes('silver_coin') },
|
|
332
|
+
{ id: 'free_ghost', label: text(locale, 'story137'), requires: (s) => s.inventory.includes('elf_feather') },
|
|
333
|
+
{ id: 'back_catacombs', label: text(locale, 'story138') },
|
|
332
334
|
],
|
|
333
335
|
},
|
|
334
336
|
|
|
335
337
|
ossuary: {
|
|
336
338
|
id: 'ossuary',
|
|
337
339
|
text: T([
|
|
338
|
-
|
|
340
|
+
text(locale, 'story139'),
|
|
339
341
|
'',
|
|
340
|
-
'
|
|
342
|
+
text(locale, 'story140'),
|
|
341
343
|
]),
|
|
342
344
|
choices: [
|
|
343
|
-
{ id: 'answer_greed', label: '
|
|
344
|
-
{ id: 'answer_flood', label: '
|
|
345
|
-
{ id: 'answer_star', label: '
|
|
346
|
-
{ id: 'back_catacombs', label:
|
|
345
|
+
{ id: 'answer_greed', label: text(locale, 'story141') },
|
|
346
|
+
{ id: 'answer_flood', label: text(locale, 'story142') },
|
|
347
|
+
{ id: 'answer_star', label: text(locale, 'story143'), style: 'primary' },
|
|
348
|
+
{ id: 'back_catacombs', label: text(locale, 'story138') },
|
|
347
349
|
],
|
|
348
350
|
},
|
|
349
351
|
|
|
350
352
|
ghost_bridge: {
|
|
351
353
|
id: 'ghost_bridge',
|
|
352
354
|
text: T([
|
|
353
|
-
|
|
355
|
+
text(locale, 'story144'),
|
|
354
356
|
'',
|
|
355
|
-
'
|
|
357
|
+
text(locale, 'story145'),
|
|
356
358
|
]),
|
|
357
359
|
choices: [
|
|
358
|
-
{ id: 'pay_coin', label:
|
|
359
|
-
{ id: 'cross_feather', label:
|
|
360
|
-
{ id: 'back_market', label:
|
|
360
|
+
{ id: 'pay_coin', label: text(locale, 'story146'), requires: (s) => s.inventory.includes('silver_coin') },
|
|
361
|
+
{ id: 'cross_feather', label: text(locale, 'story147'), requires: (s) => s.inventory.includes('elf_feather') },
|
|
362
|
+
{ id: 'back_market', label: text(locale, 'story148') },
|
|
361
363
|
],
|
|
362
364
|
},
|
|
363
365
|
|
|
364
366
|
crystal_cave: {
|
|
365
367
|
id: 'crystal_cave',
|
|
366
368
|
text: T([
|
|
367
|
-
|
|
369
|
+
text(locale, 'story149'),
|
|
368
370
|
'',
|
|
369
|
-
'
|
|
371
|
+
text(locale, 'story150'),
|
|
370
372
|
]),
|
|
371
373
|
choices: [
|
|
372
|
-
{ id: 'take_moon_shard', label:
|
|
373
|
-
{ id: 'take_feather', label:
|
|
374
|
-
{ id: 'enter_moon_pool', label:
|
|
375
|
-
{ id: 'back_bridge', label:
|
|
374
|
+
{ id: 'take_moon_shard', label: text(locale, 'story151'), requires: (s) => !s.inventory.includes('moon_shard') },
|
|
375
|
+
{ id: 'take_feather', label: text(locale, 'story152'), requires: (s) => !s.inventory.includes('elf_feather') },
|
|
376
|
+
{ id: 'enter_moon_pool', label: text(locale, 'story153') },
|
|
377
|
+
{ id: 'back_bridge', label: text(locale, 'story154') },
|
|
376
378
|
],
|
|
377
379
|
},
|
|
378
380
|
|
|
379
381
|
moon_pool: {
|
|
380
382
|
id: 'moon_pool',
|
|
381
383
|
text: (s) => T([
|
|
382
|
-
|
|
384
|
+
text(locale, 'story155'),
|
|
383
385
|
'',
|
|
384
|
-
'
|
|
385
|
-
s.flags.moon_blessed ? '
|
|
386
|
+
text(locale, 'story156'),
|
|
387
|
+
s.flags.moon_blessed ? text(locale, 'story157') : text(locale, 'story158'),
|
|
386
388
|
]),
|
|
387
389
|
choices: [
|
|
388
|
-
{ id: 'align_chart', label:
|
|
389
|
-
{ id: 'dive_shrine', label:
|
|
390
|
-
{ id: 'back_crystal', label:
|
|
390
|
+
{ id: 'align_chart', label: text(locale, 'story159'), requires: (s) => s.inventory.includes('star_chart') && !s.flags.moon_blessed },
|
|
391
|
+
{ id: 'dive_shrine', label: text(locale, 'story160'), requires: (s) => s.flags.moon_blessed },
|
|
392
|
+
{ id: 'back_crystal', label: text(locale, 'story161') },
|
|
391
393
|
],
|
|
392
394
|
},
|
|
393
395
|
|
|
394
396
|
sunken_shrine: {
|
|
395
397
|
id: 'sunken_shrine',
|
|
396
398
|
text: T([
|
|
397
|
-
|
|
399
|
+
text(locale, 'story162'),
|
|
398
400
|
'',
|
|
399
|
-
'
|
|
401
|
+
text(locale, 'story163'),
|
|
400
402
|
]),
|
|
401
403
|
choices: [
|
|
402
|
-
{ id: 'ritual_star_keeper', label:
|
|
403
|
-
{ id: 'back_moon_pool', label:
|
|
404
|
+
{ id: 'ritual_star_keeper', label: text(locale, 'story164'), requires: (s) => s.inventory.includes('moon_shard') && s.inventory.includes('star_chart') && s.flags.spirit_met },
|
|
405
|
+
{ id: 'back_moon_pool', label: text(locale, 'story165') },
|
|
404
406
|
],
|
|
405
407
|
},
|
|
406
408
|
|
|
407
409
|
observatory: {
|
|
408
410
|
id: 'observatory',
|
|
409
411
|
text: T([
|
|
410
|
-
|
|
412
|
+
text(locale, 'story166'),
|
|
411
413
|
'',
|
|
412
|
-
'
|
|
414
|
+
text(locale, 'story167'),
|
|
413
415
|
]),
|
|
414
416
|
choices: [
|
|
415
|
-
{ id: 'craft_compass', label:
|
|
416
|
-
{ id: 'back_tower', label:
|
|
417
|
+
{ id: 'craft_compass', label: text(locale, 'story168'), requires: (s) => !s.inventory.includes('compass') },
|
|
418
|
+
{ id: 'back_tower', label: text(locale, 'story23') },
|
|
417
419
|
],
|
|
418
420
|
},
|
|
419
421
|
|
|
420
422
|
sealed_gates: {
|
|
421
423
|
id: 'sealed_gates',
|
|
422
424
|
text: T([
|
|
423
|
-
|
|
425
|
+
text(locale, 'story169'),
|
|
424
426
|
'',
|
|
425
|
-
'
|
|
427
|
+
text(locale, 'story170'),
|
|
426
428
|
]),
|
|
427
429
|
choices: [
|
|
428
|
-
{ id: 'open_gates', label:
|
|
429
|
-
{ id: 'back_crypt', label:
|
|
430
|
+
{ id: 'open_gates', label: text(locale, 'story171'), requires: (s) => s.inventory.includes('spirit_bell') && s.inventory.includes('compass') && s.inventory.includes('key') },
|
|
431
|
+
{ id: 'back_crypt', label: text(locale, 'story132') },
|
|
430
432
|
],
|
|
431
433
|
},
|
|
432
434
|
|
|
433
435
|
vault: {
|
|
434
436
|
id: 'vault',
|
|
435
437
|
text: (s) => T([
|
|
436
|
-
|
|
438
|
+
text(locale, 'story172'),
|
|
437
439
|
'',
|
|
438
|
-
'
|
|
439
|
-
s.flags.knows_sequence ?
|
|
440
|
+
text(locale, 'story173'),
|
|
441
|
+
s.flags.knows_sequence ? text(locale, 'story174') : text(locale, 'story175'),
|
|
440
442
|
]),
|
|
441
443
|
choices: [
|
|
442
|
-
{ id: 'seq_light_shadow_door', label: '
|
|
443
|
-
{ id: 'seq_door_light_shadow', label: '
|
|
444
|
-
{ id: 'seq_shadow_door_light', label: '
|
|
445
|
-
{ id: 'back_crypt', label:
|
|
444
|
+
{ id: 'seq_light_shadow_door', label: text(locale, 'story176'), style: 'primary' },
|
|
445
|
+
{ id: 'seq_door_light_shadow', label: text(locale, 'story177') },
|
|
446
|
+
{ id: 'seq_shadow_door_light', label: text(locale, 'story178') },
|
|
447
|
+
{ id: 'back_crypt', label: text(locale, 'story132') },
|
|
446
448
|
],
|
|
447
449
|
},
|
|
448
450
|
|
|
449
451
|
vault_open: {
|
|
450
452
|
id: 'vault_open',
|
|
451
453
|
text: (s) => T([
|
|
452
|
-
|
|
454
|
+
text(locale, 'story179'),
|
|
453
455
|
'',
|
|
454
|
-
s.flags.amulet_upgraded ? '
|
|
456
|
+
s.flags.amulet_upgraded ? text(locale, 'story180') : text(locale, 'story181'),
|
|
455
457
|
]),
|
|
456
458
|
choices: [
|
|
457
|
-
{ id: 'descend_throne', label:
|
|
458
|
-
{ id: 'take_treasure_now', label:
|
|
459
|
-
{ id: 'back_crypt', label:
|
|
459
|
+
{ id: 'descend_throne', label: text(locale, 'story182') },
|
|
460
|
+
{ id: 'take_treasure_now', label: text(locale, 'story183') },
|
|
461
|
+
{ id: 'back_crypt', label: text(locale, 'story132') },
|
|
460
462
|
],
|
|
461
463
|
},
|
|
462
464
|
|
|
@@ -465,41 +467,936 @@ export const SCENES: Record<string, Scene> = {
|
|
|
465
467
|
text: (s) => {
|
|
466
468
|
const ready = s.flags.whisper_lore && s.flags.amulet_upgraded && s.flags.spirit_met;
|
|
467
469
|
return T([
|
|
468
|
-
|
|
470
|
+
text(locale, 'story184'),
|
|
469
471
|
'',
|
|
470
|
-
ready ? '
|
|
472
|
+
ready ? text(locale, 'story185') : text(locale, 'story186'),
|
|
471
473
|
]);
|
|
472
474
|
},
|
|
473
475
|
choices: [
|
|
474
476
|
{
|
|
475
477
|
id: 'ascend',
|
|
476
|
-
label:
|
|
478
|
+
label: text(locale, 'story187'),
|
|
477
479
|
style: 'primary',
|
|
478
480
|
requires: (s) => s.flags.whisper_lore && s.flags.amulet_upgraded && s.flags.spirit_met && s.inventory.includes('scroll'),
|
|
479
481
|
},
|
|
480
|
-
{ id: 'ascend_mask', label:
|
|
481
|
-
{ id: 'claim_crown', label:
|
|
482
|
-
{ id: 'retreat_throne', label:
|
|
482
|
+
{ id: 'ascend_mask', label: text(locale, 'story188'), requires: (s) => s.inventory.includes('masquerade_mask') },
|
|
483
|
+
{ id: 'claim_crown', label: text(locale, 'story189'), style: 'danger' },
|
|
484
|
+
{ id: 'retreat_throne', label: text(locale, 'story190') },
|
|
483
485
|
],
|
|
484
486
|
},
|
|
485
487
|
|
|
486
488
|
// —— 终局 ——
|
|
487
|
-
treasure: { id: 'treasure', terminal: true, text: T([
|
|
488
|
-
ascension: { id: 'ascension', terminal: true, text: T([
|
|
489
|
-
wisdom: { id: 'wisdom', terminal: true, text: T([
|
|
490
|
-
curse: { id: 'curse', terminal: true, text: T([
|
|
491
|
-
escape: { id: 'escape', terminal: true, text: T([
|
|
492
|
-
defeat: { id: 'defeat', terminal: true, text: T([
|
|
493
|
-
coward: { id: 'coward', terminal: true, text: T([
|
|
494
|
-
hermit: { id: 'hermit', terminal: true, text: T([
|
|
495
|
-
redemption: { id: 'redemption', terminal: true, text: T([
|
|
496
|
-
drowned: { id: 'drowned', terminal: true, text: T([
|
|
497
|
-
spider: { id: 'spider', terminal: true, text: T([
|
|
498
|
-
labyrinth: { id: 'labyrinth', terminal: true, text: T([
|
|
499
|
-
star_keeper: { id: 'star_keeper', terminal: true, text: T([
|
|
500
|
-
mask_king: { id: 'mask_king', terminal: true, text: T([
|
|
501
|
-
merchant: { id: 'merchant', terminal: true, text: T([
|
|
502
|
-
};
|
|
489
|
+
treasure: { id: 'treasure', terminal: true, text: T([text(locale, 'story191'), '', text(locale, 'story192')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
490
|
+
ascension: { id: 'ascension', terminal: true, text: T([text(locale, 'story194'), '', text(locale, 'story195')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
491
|
+
wisdom: { id: 'wisdom', terminal: true, text: T([text(locale, 'story196'), '', text(locale, 'story197')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
492
|
+
curse: { id: 'curse', terminal: true, text: T([text(locale, 'story198'), '', text(locale, 'story199')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
493
|
+
escape: { id: 'escape', terminal: true, text: T([text(locale, 'story200'), '', text(locale, 'story201')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
494
|
+
defeat: { id: 'defeat', terminal: true, text: T([text(locale, 'story202'), '', text(locale, 'story203')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
495
|
+
coward: { id: 'coward', terminal: true, text: T([text(locale, 'story204'), '', text(locale, 'story205')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
496
|
+
hermit: { id: 'hermit', terminal: true, text: T([text(locale, 'story206'), '', text(locale, 'story207')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
497
|
+
redemption: { id: 'redemption', terminal: true, text: T([text(locale, 'story208'), '', text(locale, 'story209')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
498
|
+
drowned: { id: 'drowned', terminal: true, text: T([text(locale, 'story210'), '', text(locale, 'story211')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
499
|
+
spider: { id: 'spider', terminal: true, text: T([text(locale, 'story212'), '', text(locale, 'story213')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
500
|
+
labyrinth: { id: 'labyrinth', terminal: true, text: T([text(locale, 'story214'), '', text(locale, 'story215')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
501
|
+
star_keeper: { id: 'star_keeper', terminal: true, text: T([text(locale, 'story216'), '', text(locale, 'story217')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
502
|
+
mask_king: { id: 'mask_king', terminal: true, text: T([text(locale, 'story218'), '', text(locale, 'story219')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
503
|
+
merchant: { id: 'merchant', terminal: true, text: T([text(locale, 'story220'), '', text(locale, 'story221')]), choices: [{ id: 'restart', label: text(locale, 'story193'), style: 'primary' }] },
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const text = createMessages({
|
|
508
|
+
"story1": {
|
|
509
|
+
"zh-CN": "🌫️ **秘境入口**",
|
|
510
|
+
"en": "🌫️ **Entrance to the Ruins**"
|
|
511
|
+
},
|
|
512
|
+
"story2": {
|
|
513
|
+
"zh-CN": "浓雾散去,你站在古老石门前。左侧是坍塌廊柱,右侧藤蔓小径,远处石塔刺破雾霭。",
|
|
514
|
+
"en": "The mist clears before an ancient stone gate. Fallen columns lie to your left, a vine-covered path to your right, and a stone tower rises in the distance."
|
|
515
|
+
},
|
|
516
|
+
"story3": {
|
|
517
|
+
"zh-CN": "🔥 火把照亮门缝间的幽蓝微光。",
|
|
518
|
+
"en": "🔥 Your torch reveals a blue glow through the gap in the gate."
|
|
519
|
+
},
|
|
520
|
+
"story4": {
|
|
521
|
+
"zh-CN": "💧 泉灵低语:「庭院与星塔皆藏路。」",
|
|
522
|
+
"en": "💧 The spring spirit whispers: “Both the garden and the star tower hide a path.”"
|
|
523
|
+
},
|
|
524
|
+
"story5": {
|
|
525
|
+
"zh-CN": "🗺️ 你记得塔顶俯瞰的全貌:泉、庭、墓、门。",
|
|
526
|
+
"en": "🗺️ You recall the view from the tower: spring, garden, tomb, and gate."
|
|
527
|
+
},
|
|
528
|
+
"story6": {
|
|
529
|
+
"zh-CN": "🚪 推门而入",
|
|
530
|
+
"en": "🚪 Push open the gate"
|
|
531
|
+
},
|
|
532
|
+
"story7": {
|
|
533
|
+
"zh-CN": "🔍 翻找碎石",
|
|
534
|
+
"en": "🔍 Search the rubble"
|
|
535
|
+
},
|
|
536
|
+
"story8": {
|
|
537
|
+
"zh-CN": "🗼 攀登石塔",
|
|
538
|
+
"en": "🗼 Climb the tower"
|
|
539
|
+
},
|
|
540
|
+
"story9": {
|
|
541
|
+
"zh-CN": "🌿 拨开藤蔓",
|
|
542
|
+
"en": "🌿 Clear the vines"
|
|
543
|
+
},
|
|
544
|
+
"story10": {
|
|
545
|
+
"zh-CN": "🏃 转身离开",
|
|
546
|
+
"en": "🏃 Turn back"
|
|
547
|
+
},
|
|
548
|
+
"story11": {
|
|
549
|
+
"zh-CN": "你在坍塌廊柱间翻找,指尖触到冰冷金属。",
|
|
550
|
+
"en": "Searching among the fallen columns, your fingers brush cold metal."
|
|
551
|
+
},
|
|
552
|
+
"story12": {
|
|
553
|
+
"zh-CN": "一把**火把**躺在尘土里;石缝深处还有生锈短剑。",
|
|
554
|
+
"en": "A **torch** lies in the dust; a rusty blade rests deeper in a crack."
|
|
555
|
+
},
|
|
556
|
+
"story13": {
|
|
557
|
+
"zh-CN": "🔥 拾取火把",
|
|
558
|
+
"en": "🔥 Take the torch"
|
|
559
|
+
},
|
|
560
|
+
"story14": {
|
|
561
|
+
"zh-CN": "⚔️ 拾取短剑",
|
|
562
|
+
"en": "⚔️ Take the blade"
|
|
563
|
+
},
|
|
564
|
+
"story15": {
|
|
565
|
+
"zh-CN": "↩️ 返回入口",
|
|
566
|
+
"en": "↩️ Return to the entrance"
|
|
567
|
+
},
|
|
568
|
+
"story16": {
|
|
569
|
+
"zh-CN": "🗼 **瞭望石塔**",
|
|
570
|
+
"en": "🗼 **Watchtower**"
|
|
571
|
+
},
|
|
572
|
+
"story17": {
|
|
573
|
+
"zh-CN": "塔顶风声呼啸,你已记下遗迹布局。",
|
|
574
|
+
"en": "Wind howls at the summit. You have already mapped the ruins."
|
|
575
|
+
},
|
|
576
|
+
"story18": {
|
|
577
|
+
"zh-CN": "螺旋阶梯通向塔顶,视野开阔处或能看清秘境结构。",
|
|
578
|
+
"en": "Spiral stairs lead upward. From the top you might learn the layout of the ruins."
|
|
579
|
+
},
|
|
580
|
+
"story19": {
|
|
581
|
+
"zh-CN": "塔身裂缝中卡着一页星图残角。",
|
|
582
|
+
"en": "A fragment of a star chart is caught in a crack in the tower."
|
|
583
|
+
},
|
|
584
|
+
"story20": {
|
|
585
|
+
"zh-CN": "🗺️ 登高测绘",
|
|
586
|
+
"en": "🗺️ Survey the ruins"
|
|
587
|
+
},
|
|
588
|
+
"story21": {
|
|
589
|
+
"zh-CN": "📄 取星图残页",
|
|
590
|
+
"en": "📄 Take the star chart"
|
|
591
|
+
},
|
|
592
|
+
"story22": {
|
|
593
|
+
"zh-CN": "🔭 进入星象台",
|
|
594
|
+
"en": "🔭 Enter the observatory"
|
|
595
|
+
},
|
|
596
|
+
"story23": {
|
|
597
|
+
"zh-CN": "↩️ 下塔",
|
|
598
|
+
"en": "↩️ Descend the tower"
|
|
599
|
+
},
|
|
600
|
+
"story24": {
|
|
601
|
+
"zh-CN": "🌿 **秘径**",
|
|
602
|
+
"en": "🌿 **Hidden Path**"
|
|
603
|
+
},
|
|
604
|
+
"story25": {
|
|
605
|
+
"zh-CN": "青苔石阶向下,药香与湿土气息交织。",
|
|
606
|
+
"en": "Mossy steps descend through the scent of herbs and damp earth."
|
|
607
|
+
},
|
|
608
|
+
"story26": {
|
|
609
|
+
"zh-CN": "🏡 进入庭院",
|
|
610
|
+
"en": "🏡 Enter the garden"
|
|
611
|
+
},
|
|
612
|
+
"story27": {
|
|
613
|
+
"zh-CN": "🕯️ 火把照亮狭长走廊。",
|
|
614
|
+
"en": "🕯️ Your torch lights a narrow corridor."
|
|
615
|
+
},
|
|
616
|
+
"story28": {
|
|
617
|
+
"zh-CN": "🌑 走廊漆黑,你贴墙摸索。",
|
|
618
|
+
"en": "🌑 The corridor is dark. You feel your way along the wall."
|
|
619
|
+
},
|
|
620
|
+
"story29": {
|
|
621
|
+
"zh-CN": "左侧蓝光(泉)、右侧石阶(墓)、前方积水(淹)、壁画需火光细读。",
|
|
622
|
+
"en": "Blue light marks a spring to the left, steps lead to tombs on the right, and water floods the hall ahead. The mural needs torchlight."
|
|
623
|
+
},
|
|
624
|
+
"story30": {
|
|
625
|
+
"zh-CN": "📜 壁画铭文:光 → 影 → 门。",
|
|
626
|
+
"en": "📜 The mural reads: Light → Shadow → Gate."
|
|
627
|
+
},
|
|
628
|
+
"story31": {
|
|
629
|
+
"zh-CN": "💧 走向蓝光",
|
|
630
|
+
"en": "💧 Follow the blue light"
|
|
631
|
+
},
|
|
632
|
+
"story32": {
|
|
633
|
+
"zh-CN": "⬇️ 走下石阶",
|
|
634
|
+
"en": "⬇️ Descend the steps"
|
|
635
|
+
},
|
|
636
|
+
"story33": {
|
|
637
|
+
"zh-CN": "🌊 踏入积水厅",
|
|
638
|
+
"en": "🌊 Enter the flooded hall"
|
|
639
|
+
},
|
|
640
|
+
"story34": {
|
|
641
|
+
"zh-CN": "🖼️ 研读壁画",
|
|
642
|
+
"en": "🖼️ Study the mural"
|
|
643
|
+
},
|
|
644
|
+
"story35": {
|
|
645
|
+
"zh-CN": "🔔 进入钟楼",
|
|
646
|
+
"en": "🔔 Enter the bell tower"
|
|
647
|
+
},
|
|
648
|
+
"story36": {
|
|
649
|
+
"zh-CN": "↩️ 退回入口",
|
|
650
|
+
"en": "↩️ Retreat to the entrance"
|
|
651
|
+
},
|
|
652
|
+
"story37": {
|
|
653
|
+
"zh-CN": "🖼️ **铭文壁画**",
|
|
654
|
+
"en": "🖼️ **Inscribed Mural**"
|
|
655
|
+
},
|
|
656
|
+
"story38": {
|
|
657
|
+
"zh-CN": "三联画:光、影、门。下角刻序:**光 → 影 → 门**。",
|
|
658
|
+
"en": "Three panels show Light, Shadow, and Gate. An inscription gives the order: **Light → Shadow → Gate**."
|
|
659
|
+
},
|
|
660
|
+
"story39": {
|
|
661
|
+
"zh-CN": "壁画后有一条狭窄画廊,低语声如风穿隙。",
|
|
662
|
+
"en": "Behind the mural, a narrow gallery carries whispers like wind through cracks."
|
|
663
|
+
},
|
|
664
|
+
"story40": {
|
|
665
|
+
"zh-CN": "📝 记下顺序",
|
|
666
|
+
"en": "📝 Remember the sequence"
|
|
667
|
+
},
|
|
668
|
+
"story41": {
|
|
669
|
+
"zh-CN": "👂 进入低语画廊",
|
|
670
|
+
"en": "👂 Enter the whispering gallery"
|
|
671
|
+
},
|
|
672
|
+
"story42": {
|
|
673
|
+
"zh-CN": "↩️ 返回走廊",
|
|
674
|
+
"en": "↩️ Return to the corridor"
|
|
675
|
+
},
|
|
676
|
+
"story43": {
|
|
677
|
+
"zh-CN": "👂 **低语画廊**",
|
|
678
|
+
"en": "👂 **Whispering Gallery**"
|
|
679
|
+
},
|
|
680
|
+
"story44": {
|
|
681
|
+
"zh-CN": "亿万精灵名讳在墙间回响。你听见:「星坠之日,门为封印,非为宝藏。」",
|
|
682
|
+
"en": "Countless elven names echo between the walls. You hear: “When the stars fell, the gate sealed something away. It did not guard treasure.”"
|
|
683
|
+
},
|
|
684
|
+
"story45": {
|
|
685
|
+
"zh-CN": "「守忆者需集月华、星图、泉心三证。」",
|
|
686
|
+
"en": "“A keeper of memory needs three proofs: moonlight, a star chart, and the heart of the spring.”"
|
|
687
|
+
},
|
|
688
|
+
"story46": {
|
|
689
|
+
"zh-CN": "🧘 静心聆听",
|
|
690
|
+
"en": "🧘 Listen closely"
|
|
691
|
+
},
|
|
692
|
+
"story47": {
|
|
693
|
+
"zh-CN": "↩️ 返回壁画室",
|
|
694
|
+
"en": "↩️ Return to the mural room"
|
|
695
|
+
},
|
|
696
|
+
"story48": {
|
|
697
|
+
"zh-CN": "💧 **精灵泉**",
|
|
698
|
+
"en": "💧 **Spirit Spring**"
|
|
699
|
+
},
|
|
700
|
+
"story49": {
|
|
701
|
+
"zh-CN": "泉灵光影朝你颔首。",
|
|
702
|
+
"en": "The spring spirit nods to you."
|
|
703
|
+
},
|
|
704
|
+
"story50": {
|
|
705
|
+
"zh-CN": "水光凝聚为精灵形貌,注视着你。",
|
|
706
|
+
"en": "The shimmering water forms an elven figure, watching you."
|
|
707
|
+
},
|
|
708
|
+
"story51": {
|
|
709
|
+
"zh-CN": "泉水可治愈一次。",
|
|
710
|
+
"en": "The spring can heal you once."
|
|
711
|
+
},
|
|
712
|
+
"story52": {
|
|
713
|
+
"zh-CN": "泉水已无先前效力。",
|
|
714
|
+
"en": "The spring has lost its healing power."
|
|
715
|
+
},
|
|
716
|
+
"story53": {
|
|
717
|
+
"zh-CN": "🍶 饮用泉水",
|
|
718
|
+
"en": "🍶 Drink from the spring"
|
|
719
|
+
},
|
|
720
|
+
"story54": {
|
|
721
|
+
"zh-CN": "💎 取走宝石",
|
|
722
|
+
"en": "💎 Take the gem"
|
|
723
|
+
},
|
|
724
|
+
"story55": {
|
|
725
|
+
"zh-CN": "💬 与泉灵交谈",
|
|
726
|
+
"en": "💬 Talk to the spirit"
|
|
727
|
+
},
|
|
728
|
+
"story56": {
|
|
729
|
+
"zh-CN": "🙏 献宝石换护符",
|
|
730
|
+
"en": "🙏 Trade the gem for an amulet"
|
|
731
|
+
},
|
|
732
|
+
"story57": {
|
|
733
|
+
"zh-CN": "↩️ 离开",
|
|
734
|
+
"en": "↩️ Leave"
|
|
735
|
+
},
|
|
736
|
+
"story58": {
|
|
737
|
+
"zh-CN": "🌊 **积水前厅**",
|
|
738
|
+
"en": "🌊 **Flooded Hall**"
|
|
739
|
+
},
|
|
740
|
+
"story59": {
|
|
741
|
+
"zh-CN": "及膝冷水没过石板,远处有坍塌市集拱门。",
|
|
742
|
+
"en": "Knee-deep cold water covers the slabs. A ruined market arch stands in the distance."
|
|
743
|
+
},
|
|
744
|
+
"story60": {
|
|
745
|
+
"zh-CN": "银羽护体,寒气难侵。",
|
|
746
|
+
"en": "The silver feather shields you from the cold."
|
|
747
|
+
},
|
|
748
|
+
"story61": {
|
|
749
|
+
"zh-CN": "寒意刺骨,久留恐失温。",
|
|
750
|
+
"en": "The chill bites deep. Staying too long risks hypothermia."
|
|
751
|
+
},
|
|
752
|
+
"story62": {
|
|
753
|
+
"zh-CN": "🏚️ 前往废墟市集",
|
|
754
|
+
"en": "🏚️ Head to the ruined market"
|
|
755
|
+
},
|
|
756
|
+
"story63": {
|
|
757
|
+
"zh-CN": "🪶 银羽护体涉水",
|
|
758
|
+
"en": "🪶 Wade with the silver feather"
|
|
759
|
+
},
|
|
760
|
+
"story64": {
|
|
761
|
+
"zh-CN": "🍶 饮灵药暖身",
|
|
762
|
+
"en": "🍶 Drink elixir for warmth"
|
|
763
|
+
},
|
|
764
|
+
"story65": {
|
|
765
|
+
"zh-CN": "🏚️ **废墟市集**",
|
|
766
|
+
"en": "🏚️ **Ruined Market**"
|
|
767
|
+
},
|
|
768
|
+
"story66": {
|
|
769
|
+
"zh-CN": "幽灵摊主陈列面具与古币。「一物换一物,或银币亦可。」",
|
|
770
|
+
"en": "A ghostly merchant displays masks and ancient coins. “An item for an item, or a silver coin.”"
|
|
771
|
+
},
|
|
772
|
+
"story67": {
|
|
773
|
+
"zh-CN": "🎭 银币换面具",
|
|
774
|
+
"en": "🎭 Trade a coin for a mask"
|
|
775
|
+
},
|
|
776
|
+
"story68": {
|
|
777
|
+
"zh-CN": "💎 宝石换银币",
|
|
778
|
+
"en": "💎 Trade the gem for a coin"
|
|
779
|
+
},
|
|
780
|
+
"story69": {
|
|
781
|
+
"zh-CN": "🌉 前往冥河石桥",
|
|
782
|
+
"en": "🌉 Head to the ghost bridge"
|
|
783
|
+
},
|
|
784
|
+
"story70": {
|
|
785
|
+
"zh-CN": "↩️ 离开市集",
|
|
786
|
+
"en": "↩️ Leave the market"
|
|
787
|
+
},
|
|
788
|
+
"story71": {
|
|
789
|
+
"zh-CN": "🏡 **遗忘庭院**",
|
|
790
|
+
"en": "🏡 **Forgotten Garden**"
|
|
791
|
+
},
|
|
792
|
+
"story72": {
|
|
793
|
+
"zh-CN": "银叶古树、紧锁铁门、侧翼温室玻璃碎裂。",
|
|
794
|
+
"en": "An ancient silver-leaved tree, a locked iron gate, and a greenhouse with shattered windows surround you."
|
|
795
|
+
},
|
|
796
|
+
"story73": {
|
|
797
|
+
"zh-CN": "花坛已采过药草。",
|
|
798
|
+
"en": "You have already gathered the herb from the flowerbed."
|
|
799
|
+
},
|
|
800
|
+
"story74": {
|
|
801
|
+
"zh-CN": "花坛闪烁荧光草药。",
|
|
802
|
+
"en": "A luminous herb glimmers in the flowerbed."
|
|
803
|
+
},
|
|
804
|
+
"story75": {
|
|
805
|
+
"zh-CN": "🌿 采集草药",
|
|
806
|
+
"en": "🌿 Gather the herb"
|
|
807
|
+
},
|
|
808
|
+
"story76": {
|
|
809
|
+
"zh-CN": "🌳 树下休息",
|
|
810
|
+
"en": "🌳 Rest under the tree"
|
|
811
|
+
},
|
|
812
|
+
"story77": {
|
|
813
|
+
"zh-CN": "🪴 进入温室",
|
|
814
|
+
"en": "🪴 Enter the greenhouse"
|
|
815
|
+
},
|
|
816
|
+
"story78": {
|
|
817
|
+
"zh-CN": "🔑 打开铁门",
|
|
818
|
+
"en": "🔑 Unlock the iron gate"
|
|
819
|
+
},
|
|
820
|
+
"story79": {
|
|
821
|
+
"zh-CN": "🏠 定居庭院",
|
|
822
|
+
"en": "🏠 Settle in the garden"
|
|
823
|
+
},
|
|
824
|
+
"story80": {
|
|
825
|
+
"zh-CN": "🪴 **破碎温室**",
|
|
826
|
+
"en": "🪴 **Shattered Greenhouse**"
|
|
827
|
+
},
|
|
828
|
+
"story81": {
|
|
829
|
+
"zh-CN": "枯藤缠绕蒸馏器,可萃取草药为灵药。",
|
|
830
|
+
"en": "Dead vines wrap around a still that can distill herbs into elixir."
|
|
831
|
+
},
|
|
832
|
+
"story82": {
|
|
833
|
+
"zh-CN": "⚗️ 萃取灵药",
|
|
834
|
+
"en": "⚗️ Brew elixir"
|
|
835
|
+
},
|
|
836
|
+
"story83": {
|
|
837
|
+
"zh-CN": "↩️ 返回庭院",
|
|
838
|
+
"en": "↩️ Return to the garden"
|
|
839
|
+
},
|
|
840
|
+
"story84": {
|
|
841
|
+
"zh-CN": "📚 **尘封书库**",
|
|
842
|
+
"en": "📚 **Dusty Library**"
|
|
843
|
+
},
|
|
844
|
+
"story85": {
|
|
845
|
+
"zh-CN": "残卷、墙钥、暗门后传来锻炉热气。",
|
|
846
|
+
"en": "Torn scrolls and a wall-mounted key lie nearby. Heat from a forge seeps through a hidden door."
|
|
847
|
+
},
|
|
848
|
+
"story86": {
|
|
849
|
+
"zh-CN": "你已读过秘档。",
|
|
850
|
+
"en": "You have read the secret archive."
|
|
851
|
+
},
|
|
852
|
+
"story87": {
|
|
853
|
+
"zh-CN": "古籍区尚有未读档案。",
|
|
854
|
+
"en": "Unread records remain among the ancient books."
|
|
855
|
+
},
|
|
856
|
+
"story88": {
|
|
857
|
+
"zh-CN": "📜 取卷轴",
|
|
858
|
+
"en": "📜 Take the scroll"
|
|
859
|
+
},
|
|
860
|
+
"story89": {
|
|
861
|
+
"zh-CN": "🔑 取钥匙",
|
|
862
|
+
"en": "🔑 Take the key"
|
|
863
|
+
},
|
|
864
|
+
"story90": {
|
|
865
|
+
"zh-CN": "📖 研读秘档",
|
|
866
|
+
"en": "📖 Read the archive"
|
|
867
|
+
},
|
|
868
|
+
"story91": {
|
|
869
|
+
"zh-CN": "🔥 进入锻炉间",
|
|
870
|
+
"en": "🔥 Enter the forge"
|
|
871
|
+
},
|
|
872
|
+
"story92": {
|
|
873
|
+
"zh-CN": "🔥 **余烬锻炉**",
|
|
874
|
+
"en": "🔥 **Ember Forge**"
|
|
875
|
+
},
|
|
876
|
+
"story93": {
|
|
877
|
+
"zh-CN": "精灵余火仍燃。可淬炼短剑,或升华护符。",
|
|
878
|
+
"en": "Elven embers still burn. They can temper a blade or empower an amulet."
|
|
879
|
+
},
|
|
880
|
+
"story94": {
|
|
881
|
+
"zh-CN": "短剑已淬炼。",
|
|
882
|
+
"en": "The blade is already tempered."
|
|
883
|
+
},
|
|
884
|
+
"story95": {
|
|
885
|
+
"zh-CN": "短剑可淬炼。",
|
|
886
|
+
"en": "The blade can be tempered here."
|
|
887
|
+
},
|
|
888
|
+
"story96": {
|
|
889
|
+
"zh-CN": "⚔️ 淬炼短剑",
|
|
890
|
+
"en": "⚔️ Temper the blade"
|
|
891
|
+
},
|
|
892
|
+
"story97": {
|
|
893
|
+
"zh-CN": "✨ 升华护符",
|
|
894
|
+
"en": "✨ Empower the amulet"
|
|
895
|
+
},
|
|
896
|
+
"story98": {
|
|
897
|
+
"zh-CN": "↩️ 返回书库",
|
|
898
|
+
"en": "↩️ Return to the library"
|
|
899
|
+
},
|
|
900
|
+
"story99": {
|
|
901
|
+
"zh-CN": "🔔 **回音钟楼**",
|
|
902
|
+
"en": "🔔 **Echoing Bell Tower**"
|
|
903
|
+
},
|
|
904
|
+
"story100": {
|
|
905
|
+
"zh-CN": "悬空铜钟布满符纹。钟舌缺失,旁有铸台。",
|
|
906
|
+
"en": "Runes cover a suspended bronze bell. Its clapper is missing; a casting bench stands nearby."
|
|
907
|
+
},
|
|
908
|
+
"story101": {
|
|
909
|
+
"zh-CN": "🔔 敲响铜钟",
|
|
910
|
+
"en": "🔔 Ring the bell"
|
|
911
|
+
},
|
|
912
|
+
"story102": {
|
|
913
|
+
"zh-CN": "⬇️ **地下墓穴**",
|
|
914
|
+
"en": "⬇️ **Underground Tomb**"
|
|
915
|
+
},
|
|
916
|
+
"story103": {
|
|
917
|
+
"zh-CN": "石棺半开,**守墓幽影**凝形扑来!",
|
|
918
|
+
"en": "A sarcophagus stands half-open. A **tomb guardian shade** takes shape and lunges!"
|
|
919
|
+
},
|
|
920
|
+
"story104": {
|
|
921
|
+
"zh-CN": "⚔️ 正面迎战",
|
|
922
|
+
"en": "⚔️ Face it head-on"
|
|
923
|
+
},
|
|
924
|
+
"story105": {
|
|
925
|
+
"zh-CN": "🗡️ 挥剑迎击",
|
|
926
|
+
"en": "🗡️ Strike with the blade"
|
|
927
|
+
},
|
|
928
|
+
"story106": {
|
|
929
|
+
"zh-CN": "🔥 火把驱散",
|
|
930
|
+
"en": "🔥 Drive it off with fire"
|
|
931
|
+
},
|
|
932
|
+
"story107": {
|
|
933
|
+
"zh-CN": "🌿 草药麻痹",
|
|
934
|
+
"en": "🌿 Stun it with the herb"
|
|
935
|
+
},
|
|
936
|
+
"story108": {
|
|
937
|
+
"zh-CN": "🏃 逃跑",
|
|
938
|
+
"en": "🏃 Flee"
|
|
939
|
+
},
|
|
940
|
+
"story109": {
|
|
941
|
+
"zh-CN": "⚰️ **墓道岔口**",
|
|
942
|
+
"en": "⚰️ **Tomb Crossroads**"
|
|
943
|
+
},
|
|
944
|
+
"story110": {
|
|
945
|
+
"zh-CN": "左:封印密室|右:骸骨甬道|下:蛛巢暗道",
|
|
946
|
+
"en": "Left: sealed vault | Right: catacombs | Below: spider passage"
|
|
947
|
+
},
|
|
948
|
+
"story111": {
|
|
949
|
+
"zh-CN": "🔐 封印密室",
|
|
950
|
+
"en": "🔐 Sealed vault"
|
|
951
|
+
},
|
|
952
|
+
"story112": {
|
|
953
|
+
"zh-CN": "💀 骸骨甬道",
|
|
954
|
+
"en": "💀 Catacombs"
|
|
955
|
+
},
|
|
956
|
+
"story113": {
|
|
957
|
+
"zh-CN": "🕷️ 蛛巢暗道",
|
|
958
|
+
"en": "🕷️ Spider passage"
|
|
959
|
+
},
|
|
960
|
+
"story114": {
|
|
961
|
+
"zh-CN": "🚪 回音巨门",
|
|
962
|
+
"en": "🚪 Echoing gates"
|
|
963
|
+
},
|
|
964
|
+
"story115": {
|
|
965
|
+
"zh-CN": "🕷️ **蛛巢暗道**",
|
|
966
|
+
"en": "🕷️ **Spider Passage**"
|
|
967
|
+
},
|
|
968
|
+
"story116": {
|
|
969
|
+
"zh-CN": "巨网横亘,蛛眼如灯笼。后方似通暗影迷宫。",
|
|
970
|
+
"en": "A giant web blocks the way. Spider eyes glow like lanterns. Beyond it lies a shadow maze."
|
|
971
|
+
},
|
|
972
|
+
"story117": {
|
|
973
|
+
"zh-CN": "🗡️ 斩网前行",
|
|
974
|
+
"en": "🗡️ Cut through the web"
|
|
975
|
+
},
|
|
976
|
+
"story118": {
|
|
977
|
+
"zh-CN": "🔥 火烧蛛网",
|
|
978
|
+
"en": "🔥 Burn the web"
|
|
979
|
+
},
|
|
980
|
+
"story119": {
|
|
981
|
+
"zh-CN": "🏃 撤退",
|
|
982
|
+
"en": "🏃 Retreat"
|
|
983
|
+
},
|
|
984
|
+
"story120": {
|
|
985
|
+
"zh-CN": "🌑 **暗影迷宫**",
|
|
986
|
+
"en": "🌑 **Shadow Maze**"
|
|
987
|
+
},
|
|
988
|
+
"story121": {
|
|
989
|
+
"zh-CN": "墙壁流动如墨,路径每秒变幻。",
|
|
990
|
+
"en": "Walls flow like ink, and paths shift every second."
|
|
991
|
+
},
|
|
992
|
+
"story122": {
|
|
993
|
+
"zh-CN": "🧭 罗盘定向",
|
|
994
|
+
"en": "🧭 Navigate by compass"
|
|
995
|
+
},
|
|
996
|
+
"story123": {
|
|
997
|
+
"zh-CN": "🚶 随意乱走",
|
|
998
|
+
"en": "🚶 Wander at random"
|
|
999
|
+
},
|
|
1000
|
+
"story124": {
|
|
1001
|
+
"zh-CN": "↩️ 返回蛛巢",
|
|
1002
|
+
"en": "↩️ Return to the spider nest"
|
|
1003
|
+
},
|
|
1004
|
+
"story125": {
|
|
1005
|
+
"zh-CN": "💀 **骸骨甬道**",
|
|
1006
|
+
"en": "💀 **Catacombs**"
|
|
1007
|
+
},
|
|
1008
|
+
"story126": {
|
|
1009
|
+
"zh-CN": "压力机关铭刻:诵卷轴真言。侧室铁链锁着幽魂。",
|
|
1010
|
+
"en": "An inscription on a pressure trap says: recite the scroll. Chains bind a ghost in a side chamber."
|
|
1011
|
+
},
|
|
1012
|
+
"story127": {
|
|
1013
|
+
"zh-CN": "骸骨手中铜钥闪光。",
|
|
1014
|
+
"en": "A bronze key gleams in a skeleton's hand."
|
|
1015
|
+
},
|
|
1016
|
+
"story128": {
|
|
1017
|
+
"zh-CN": "📜 展开卷轴",
|
|
1018
|
+
"en": "📜 Unroll the scroll"
|
|
1019
|
+
},
|
|
1020
|
+
"story129": {
|
|
1021
|
+
"zh-CN": "🏃 硬闯机关",
|
|
1022
|
+
"en": "🏃 Rush through the trap"
|
|
1023
|
+
},
|
|
1024
|
+
"story130": {
|
|
1025
|
+
"zh-CN": "⛓️ 进入囚室",
|
|
1026
|
+
"en": "⛓️ Enter the cell"
|
|
1027
|
+
},
|
|
1028
|
+
"story131": {
|
|
1029
|
+
"zh-CN": "🔑 取铜钥",
|
|
1030
|
+
"en": "🔑 Take the bronze key"
|
|
1031
|
+
},
|
|
1032
|
+
"story132": {
|
|
1033
|
+
"zh-CN": "↩️ 返回岔口",
|
|
1034
|
+
"en": "↩️ Return to the crossroads"
|
|
1035
|
+
},
|
|
1036
|
+
"story133": {
|
|
1037
|
+
"zh-CN": "⛓️ **幽囚石室**",
|
|
1038
|
+
"en": "⛓️ **Ghost Prison**"
|
|
1039
|
+
},
|
|
1040
|
+
"story134": {
|
|
1041
|
+
"zh-CN": "幽魂哀求:「银币可买通行,羽毛可渡冥河。」",
|
|
1042
|
+
"en": "The ghost begs: “Silver buys passage. A feather crosses the river of the dead.”"
|
|
1043
|
+
},
|
|
1044
|
+
"story135": {
|
|
1045
|
+
"zh-CN": "墙角埋着古银币。",
|
|
1046
|
+
"en": "An ancient silver coin is buried in a corner."
|
|
1047
|
+
},
|
|
1048
|
+
"story136": {
|
|
1049
|
+
"zh-CN": "🪙 取古银币",
|
|
1050
|
+
"en": "🪙 Take the ancient coin"
|
|
1051
|
+
},
|
|
1052
|
+
"story137": {
|
|
1053
|
+
"zh-CN": "🕊️ 释放幽魂",
|
|
1054
|
+
"en": "🕊️ Free the ghost"
|
|
1055
|
+
},
|
|
1056
|
+
"story138": {
|
|
1057
|
+
"zh-CN": "↩️ 返回甬道",
|
|
1058
|
+
"en": "↩️ Return to the catacombs"
|
|
1059
|
+
},
|
|
1060
|
+
"story139": {
|
|
1061
|
+
"zh-CN": "🪦 **骨灰龛室**",
|
|
1062
|
+
"en": "🪦 **Ossuary**"
|
|
1063
|
+
},
|
|
1064
|
+
"story140": {
|
|
1065
|
+
"zh-CN": "悬浮护符。幽魂问:「精灵遗迹为何陨落?」",
|
|
1066
|
+
"en": "An amulet floats in the air. A ghost asks: “What brought down the elven ruins?”"
|
|
1067
|
+
},
|
|
1068
|
+
"story141": {
|
|
1069
|
+
"zh-CN": "「贪婪与战争」",
|
|
1070
|
+
"en": "“Greed and war”"
|
|
1071
|
+
},
|
|
1072
|
+
"story142": {
|
|
1073
|
+
"zh-CN": "「大洪水」",
|
|
1074
|
+
"en": "“The great flood”"
|
|
1075
|
+
},
|
|
1076
|
+
"story143": {
|
|
1077
|
+
"zh-CN": "「星辰坠落」",
|
|
1078
|
+
"en": "“The falling stars”"
|
|
1079
|
+
},
|
|
1080
|
+
"story144": {
|
|
1081
|
+
"zh-CN": "🌉 **冥河石桥**",
|
|
1082
|
+
"en": "🌉 **Ghost Bridge**"
|
|
1083
|
+
},
|
|
1084
|
+
"story145": {
|
|
1085
|
+
"zh-CN": "无栏石桥横跨黑水。守桥者伸手要通行费。",
|
|
1086
|
+
"en": "A bare stone bridge spans black water. Its guardian demands a toll."
|
|
1087
|
+
},
|
|
1088
|
+
"story146": {
|
|
1089
|
+
"zh-CN": "🪙 付银币过桥",
|
|
1090
|
+
"en": "🪙 Pay a silver coin"
|
|
1091
|
+
},
|
|
1092
|
+
"story147": {
|
|
1093
|
+
"zh-CN": "🪶 银羽渡桥",
|
|
1094
|
+
"en": "🪶 Cross with the silver feather"
|
|
1095
|
+
},
|
|
1096
|
+
"story148": {
|
|
1097
|
+
"zh-CN": "↩️ 返回市集",
|
|
1098
|
+
"en": "↩️ Return to the market"
|
|
1099
|
+
},
|
|
1100
|
+
"story149": {
|
|
1101
|
+
"zh-CN": "💎 **晶洞**",
|
|
1102
|
+
"en": "💎 **Crystal Cave**"
|
|
1103
|
+
},
|
|
1104
|
+
"story150": {
|
|
1105
|
+
"zh-CN": "月华凝于石笋。洞顶飘落银羽。",
|
|
1106
|
+
"en": "Moonlight gathers in the stalagmites. A silver feather drifts from the ceiling."
|
|
1107
|
+
},
|
|
1108
|
+
"story151": {
|
|
1109
|
+
"zh-CN": "🌙 取月华碎片",
|
|
1110
|
+
"en": "🌙 Take the moon shard"
|
|
1111
|
+
},
|
|
1112
|
+
"story152": {
|
|
1113
|
+
"zh-CN": "🪶 拾银羽",
|
|
1114
|
+
"en": "🪶 Take the silver feather"
|
|
1115
|
+
},
|
|
1116
|
+
"story153": {
|
|
1117
|
+
"zh-CN": "💧 前往月池",
|
|
1118
|
+
"en": "💧 Head to the moon pool"
|
|
1119
|
+
},
|
|
1120
|
+
"story154": {
|
|
1121
|
+
"zh-CN": "↩️ 返回石桥",
|
|
1122
|
+
"en": "↩️ Return to the bridge"
|
|
1123
|
+
},
|
|
1124
|
+
"story155": {
|
|
1125
|
+
"zh-CN": "🌙 **月影池**",
|
|
1126
|
+
"en": "🌙 **Moon Pool**"
|
|
1127
|
+
},
|
|
1128
|
+
"story156": {
|
|
1129
|
+
"zh-CN": "池水映月。星图残页可与之共鸣。",
|
|
1130
|
+
"en": "The pool reflects the moon. A star chart fragment might resonate with it."
|
|
1131
|
+
},
|
|
1132
|
+
"story157": {
|
|
1133
|
+
"zh-CN": "月华已赐福。",
|
|
1134
|
+
"en": "You have received the moon's blessing."
|
|
1135
|
+
},
|
|
1136
|
+
"story158": {
|
|
1137
|
+
"zh-CN": "池底似有水下沉殿。",
|
|
1138
|
+
"en": "A submerged shrine seems to lie below."
|
|
1139
|
+
},
|
|
1140
|
+
"story159": {
|
|
1141
|
+
"zh-CN": "📄 星图共鸣",
|
|
1142
|
+
"en": "📄 Align the star chart"
|
|
1143
|
+
},
|
|
1144
|
+
"story160": {
|
|
1145
|
+
"zh-CN": "🤿 潜入沉殿",
|
|
1146
|
+
"en": "🤿 Dive to the shrine"
|
|
1147
|
+
},
|
|
1148
|
+
"story161": {
|
|
1149
|
+
"zh-CN": "↩️ 返回晶洞",
|
|
1150
|
+
"en": "↩️ Return to the crystal cave"
|
|
1151
|
+
},
|
|
1152
|
+
"story162": {
|
|
1153
|
+
"zh-CN": "🛕 **水下沉殿**",
|
|
1154
|
+
"en": "🛕 **Sunken Shrine**"
|
|
1155
|
+
},
|
|
1156
|
+
"story163": {
|
|
1157
|
+
"zh-CN": "三证石台:月华、星图、泉心印记。缺一则门不开。",
|
|
1158
|
+
"en": "The altar requires three proofs: moonlight, a star chart, and the spring's mark. Without all three, the gate stays shut."
|
|
1159
|
+
},
|
|
1160
|
+
"story164": {
|
|
1161
|
+
"zh-CN": "✨ 完成星守仪式",
|
|
1162
|
+
"en": "✨ Complete the star keeper ritual"
|
|
1163
|
+
},
|
|
1164
|
+
"story165": {
|
|
1165
|
+
"zh-CN": "↩️ 浮上水面",
|
|
1166
|
+
"en": "↩️ Return to the surface"
|
|
1167
|
+
},
|
|
1168
|
+
"story166": {
|
|
1169
|
+
"zh-CN": "🔭 **星象台**",
|
|
1170
|
+
"en": "🔭 **Observatory**"
|
|
1171
|
+
},
|
|
1172
|
+
"story167": {
|
|
1173
|
+
"zh-CN": "铜制浑天仪缺损。可校准罗盘。",
|
|
1174
|
+
"en": "The bronze armillary sphere is damaged. You can calibrate a compass here."
|
|
1175
|
+
},
|
|
1176
|
+
"story168": {
|
|
1177
|
+
"zh-CN": "🧭 校准罗盘",
|
|
1178
|
+
"en": "🧭 Calibrate the compass"
|
|
1179
|
+
},
|
|
1180
|
+
"story169": {
|
|
1181
|
+
"zh-CN": "🚪 **回音巨门**",
|
|
1182
|
+
"en": "🚪 **Echoing Gates**"
|
|
1183
|
+
},
|
|
1184
|
+
"story170": {
|
|
1185
|
+
"zh-CN": "铃、罗盘、钥三缺一时铭文闪烁。门后是封印内庭捷径。",
|
|
1186
|
+
"en": "The inscription flashes unless bell, compass, and key are all present. A shortcut to the sealed inner court lies beyond."
|
|
1187
|
+
},
|
|
1188
|
+
"story171": {
|
|
1189
|
+
"zh-CN": "🔓 开启巨门",
|
|
1190
|
+
"en": "🔓 Open the gates"
|
|
1191
|
+
},
|
|
1192
|
+
"story172": {
|
|
1193
|
+
"zh-CN": "🔐 **封印密室**",
|
|
1194
|
+
"en": "🔐 **Sealed Vault**"
|
|
1195
|
+
},
|
|
1196
|
+
"story173": {
|
|
1197
|
+
"zh-CN": "三雕像:光、影、门。",
|
|
1198
|
+
"en": "Three statues: Light, Shadow, and Gate."
|
|
1199
|
+
},
|
|
1200
|
+
"story174": {
|
|
1201
|
+
"zh-CN": "顺序:光 → 影 → 门。",
|
|
1202
|
+
"en": "The order is Light → Shadow → Gate."
|
|
1203
|
+
},
|
|
1204
|
+
"story175": {
|
|
1205
|
+
"zh-CN": "顺序未知。",
|
|
1206
|
+
"en": "The sequence is unknown."
|
|
1207
|
+
},
|
|
1208
|
+
"story176": {
|
|
1209
|
+
"zh-CN": "光→影→门",
|
|
1210
|
+
"en": "Light → Shadow → Gate"
|
|
1211
|
+
},
|
|
1212
|
+
"story177": {
|
|
1213
|
+
"zh-CN": "门→光→影",
|
|
1214
|
+
"en": "Gate → Light → Shadow"
|
|
1215
|
+
},
|
|
1216
|
+
"story178": {
|
|
1217
|
+
"zh-CN": "影→门→光",
|
|
1218
|
+
"en": "Shadow → Gate → Light"
|
|
1219
|
+
},
|
|
1220
|
+
"story179": {
|
|
1221
|
+
"zh-CN": "✨ **封印已解**",
|
|
1222
|
+
"en": "✨ **Seal Broken**"
|
|
1223
|
+
},
|
|
1224
|
+
"story180": {
|
|
1225
|
+
"zh-CN": "升华护符引路,王座厅近在咫尺。",
|
|
1226
|
+
"en": "The empowered amulet guides you. The throne room is close."
|
|
1227
|
+
},
|
|
1228
|
+
"story181": {
|
|
1229
|
+
"zh-CN": "螺旋阶梯通向王座厅。",
|
|
1230
|
+
"en": "Spiral stairs lead to the throne room."
|
|
1231
|
+
},
|
|
1232
|
+
"story182": {
|
|
1233
|
+
"zh-CN": "⬇️ 王座厅",
|
|
1234
|
+
"en": "⬇️ Enter the throne room"
|
|
1235
|
+
},
|
|
1236
|
+
"story183": {
|
|
1237
|
+
"zh-CN": "💰 取宝离开",
|
|
1238
|
+
"en": "💰 Take treasure and leave"
|
|
1239
|
+
},
|
|
1240
|
+
"story184": {
|
|
1241
|
+
"zh-CN": "👑 **精灵王座厅**",
|
|
1242
|
+
"en": "👑 **Elven Throne Room**"
|
|
1243
|
+
},
|
|
1244
|
+
"story185": {
|
|
1245
|
+
"zh-CN": "三证齐聚,王座虚影恭迎守忆者。",
|
|
1246
|
+
"en": "The three proofs are gathered. A spectral figure welcomes the keeper of memory."
|
|
1247
|
+
},
|
|
1248
|
+
"story186": {
|
|
1249
|
+
"zh-CN": "王座冷光闪烁,贸然落座恐遭反噬。",
|
|
1250
|
+
"en": "Cold light flickers on the throne. Sitting down unprepared may be disastrous."
|
|
1251
|
+
},
|
|
1252
|
+
"story187": {
|
|
1253
|
+
"zh-CN": "✨ 星辉归位",
|
|
1254
|
+
"en": "✨ Restore the starlight"
|
|
1255
|
+
},
|
|
1256
|
+
"story188": {
|
|
1257
|
+
"zh-CN": "🎭 面具加冕",
|
|
1258
|
+
"en": "🎭 Claim the masked crown"
|
|
1259
|
+
},
|
|
1260
|
+
"story189": {
|
|
1261
|
+
"zh-CN": "👑 坐上王座",
|
|
1262
|
+
"en": "👑 Sit on the throne"
|
|
1263
|
+
},
|
|
1264
|
+
"story190": {
|
|
1265
|
+
"zh-CN": "🏃 取宝离开",
|
|
1266
|
+
"en": "🏃 Take treasure and leave"
|
|
1267
|
+
},
|
|
1268
|
+
"story191": {
|
|
1269
|
+
"zh-CN": "🏆 **遗迹宝藏**",
|
|
1270
|
+
"en": "🏆 **Treasure of the Ruins**"
|
|
1271
|
+
},
|
|
1272
|
+
"story192": {
|
|
1273
|
+
"zh-CN": "琥珀星光入袋,你成为传说。",
|
|
1274
|
+
"en": "With amber starlight in your pack, you become a legend."
|
|
1275
|
+
},
|
|
1276
|
+
"story193": {
|
|
1277
|
+
"zh-CN": "🔄 再玩一次",
|
|
1278
|
+
"en": "🔄 Play again"
|
|
1279
|
+
},
|
|
1280
|
+
"story194": {
|
|
1281
|
+
"zh-CN": "🌟 **星辉归位**",
|
|
1282
|
+
"en": "🌟 **Starlight Restored**"
|
|
1283
|
+
},
|
|
1284
|
+
"story195": {
|
|
1285
|
+
"zh-CN": "你成为守忆者,历史因你而不朽。",
|
|
1286
|
+
"en": "You become the keeper of memory. Through you, history endures."
|
|
1287
|
+
},
|
|
1288
|
+
"story196": {
|
|
1289
|
+
"zh-CN": "📜 **智者归途**",
|
|
1290
|
+
"en": "📜 **A Scholar's Return**"
|
|
1291
|
+
},
|
|
1292
|
+
"story197": {
|
|
1293
|
+
"zh-CN": "你携记忆离去,无宝亦足。",
|
|
1294
|
+
"en": "You leave with memories. Treasure is unnecessary."
|
|
1295
|
+
},
|
|
1296
|
+
"story198": {
|
|
1297
|
+
"zh-CN": "☠️ **贪婪代价**",
|
|
1298
|
+
"en": "☠️ **The Price of Greed**"
|
|
1299
|
+
},
|
|
1300
|
+
"story199": {
|
|
1301
|
+
"zh-CN": "王座吞噬了你。",
|
|
1302
|
+
"en": "The throne consumes you."
|
|
1303
|
+
},
|
|
1304
|
+
"story200": {
|
|
1305
|
+
"zh-CN": "🌅 **生还**",
|
|
1306
|
+
"en": "🌅 **Survival**"
|
|
1307
|
+
},
|
|
1308
|
+
"story201": {
|
|
1309
|
+
"zh-CN": "遗迹坍塌,你活着出来。",
|
|
1310
|
+
"en": "The ruins collapse, but you escape alive."
|
|
1311
|
+
},
|
|
1312
|
+
"story202": {
|
|
1313
|
+
"zh-CN": "💀 **陨落**",
|
|
1314
|
+
"en": "💀 **Fallen**"
|
|
1315
|
+
},
|
|
1316
|
+
"story203": {
|
|
1317
|
+
"zh-CN": "秘境再添无名骸骨。",
|
|
1318
|
+
"en": "The ruins gain another nameless skeleton."
|
|
1319
|
+
},
|
|
1320
|
+
"story204": {
|
|
1321
|
+
"zh-CN": "🏠 **怯懦归途**",
|
|
1322
|
+
"en": "🏠 **A Coward's Return**"
|
|
1323
|
+
},
|
|
1324
|
+
"story205": {
|
|
1325
|
+
"zh-CN": "你从未入门。",
|
|
1326
|
+
"en": "You never crossed the threshold."
|
|
1327
|
+
},
|
|
1328
|
+
"story206": {
|
|
1329
|
+
"zh-CN": "🌳 **庭院隐者**",
|
|
1330
|
+
"en": "🌳 **Garden Hermit**"
|
|
1331
|
+
},
|
|
1332
|
+
"story207": {
|
|
1333
|
+
"zh-CN": "你在古树下定居,与遗迹共生。",
|
|
1334
|
+
"en": "You settle beneath the ancient tree and live alongside the ruins."
|
|
1335
|
+
},
|
|
1336
|
+
"story208": {
|
|
1337
|
+
"zh-CN": "🕊️ **幽魂解脱**",
|
|
1338
|
+
"en": "🕊️ **A Spirit Set Free**"
|
|
1339
|
+
},
|
|
1340
|
+
"story209": {
|
|
1341
|
+
"zh-CN": "你渡魂过桥,获冥府祝福。",
|
|
1342
|
+
"en": "You guide a soul across the bridge and earn the underworld's blessing."
|
|
1343
|
+
},
|
|
1344
|
+
"story210": {
|
|
1345
|
+
"zh-CN": "🌊 **寒水沉眠**",
|
|
1346
|
+
"en": "🌊 **Cold-Water Slumber**"
|
|
1347
|
+
},
|
|
1348
|
+
"story211": {
|
|
1349
|
+
"zh-CN": "积水厅吞没意识。",
|
|
1350
|
+
"en": "The flooded hall swallows your consciousness."
|
|
1351
|
+
},
|
|
1352
|
+
"story212": {
|
|
1353
|
+
"zh-CN": "🕷️ **茧中亡魂**",
|
|
1354
|
+
"en": "🕷️ **Soul in a Cocoon**"
|
|
1355
|
+
},
|
|
1356
|
+
"story213": {
|
|
1357
|
+
"zh-CN": "巨蛛将你制成茧。",
|
|
1358
|
+
"en": "The giant spider wraps you in silk."
|
|
1359
|
+
},
|
|
1360
|
+
"story214": {
|
|
1361
|
+
"zh-CN": "🌑 **迷宫迷失**",
|
|
1362
|
+
"en": "🌑 **Lost in the Maze**"
|
|
1363
|
+
},
|
|
1364
|
+
"story215": {
|
|
1365
|
+
"zh-CN": "暗影吞没方向感。",
|
|
1366
|
+
"en": "The shadows swallow your sense of direction."
|
|
1367
|
+
},
|
|
1368
|
+
"story216": {
|
|
1369
|
+
"zh-CN": "🌙 **星守誓约**",
|
|
1370
|
+
"en": "🌙 **Star Keeper's Oath**"
|
|
1371
|
+
},
|
|
1372
|
+
"story217": {
|
|
1373
|
+
"zh-CN": "你镇守月池,成为精灵最后的灯塔。",
|
|
1374
|
+
"en": "You guard the moon pool, the last beacon of the elves."
|
|
1375
|
+
},
|
|
1376
|
+
"story218": {
|
|
1377
|
+
"zh-CN": "🎭 **面具之王**",
|
|
1378
|
+
"en": "🎭 **King of Masks**"
|
|
1379
|
+
},
|
|
1380
|
+
"story219": {
|
|
1381
|
+
"zh-CN": "面具与王座融合,你统治空城。",
|
|
1382
|
+
"en": "Mask and throne merge. You rule an empty city."
|
|
1383
|
+
},
|
|
1384
|
+
"story220": {
|
|
1385
|
+
"zh-CN": "💰 **行商结局**",
|
|
1386
|
+
"en": "💰 **The Merchant's Ending**"
|
|
1387
|
+
},
|
|
1388
|
+
"story221": {
|
|
1389
|
+
"zh-CN": "你满载银币离开,遗迹不过集市。",
|
|
1390
|
+
"en": "You leave laden with silver. The ruins were merely a market."
|
|
1391
|
+
}
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1394
|
+
export const SCENES = createScenes('zh-CN');
|
|
1395
|
+
const EN_SCENES = createScenes('en');
|
|
1396
|
+
|
|
1397
|
+
export function sceneCatalog(locale: Locale = 'zh-CN'): Readonly<Record<string, Scene>> {
|
|
1398
|
+
return locale === 'en' ? EN_SCENES : SCENES;
|
|
1399
|
+
}
|
|
503
1400
|
|
|
504
1401
|
export function countScenes(): { total: number; playable: number; terminals: number } {
|
|
505
1402
|
const all = Object.values(SCENES);
|