@2025-6-19/clawfight 1.2.0 → 1.5.0
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/dist/index.js +1383 -181
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32,6 +32,13 @@ async function writeLobster(lobster) {
|
|
|
32
32
|
await ensureDir(MEMORY_DIR);
|
|
33
33
|
await writeFile(getPath("lobster.json"), JSON.stringify(lobster, null, 2), "utf-8");
|
|
34
34
|
}
|
|
35
|
+
async function readSoul() {
|
|
36
|
+
try {
|
|
37
|
+
return await readFile(getPath("soul.md"), "utf-8");
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
35
42
|
async function writeSoul(content) {
|
|
36
43
|
await ensureDir(MEMORY_DIR);
|
|
37
44
|
await writeFile(getPath("soul.md"), content, "utf-8");
|
|
@@ -141,6 +148,29 @@ ${archetype.values}
|
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
// src/lib/types.ts
|
|
151
|
+
var EQUIP_RARITY_WEIGHTS = {
|
|
152
|
+
common: 60,
|
|
153
|
+
rare: 25,
|
|
154
|
+
epic: 12,
|
|
155
|
+
legendary: 3
|
|
156
|
+
};
|
|
157
|
+
var EQUIP_RARITY_LABELS = {
|
|
158
|
+
common: "\u666E\u901A",
|
|
159
|
+
rare: "\u7A00\u6709",
|
|
160
|
+
epic: "\u53F2\u8BD7",
|
|
161
|
+
legendary: "\u4F20\u8BF4"
|
|
162
|
+
};
|
|
163
|
+
var SLOT_LABELS = {
|
|
164
|
+
claw: "\u94B3",
|
|
165
|
+
shell: "\u58F3",
|
|
166
|
+
charm: "\u9970"
|
|
167
|
+
};
|
|
168
|
+
var SLOT_ICONS = {
|
|
169
|
+
claw: "\u2694\uFE0F",
|
|
170
|
+
shell: "\u{1F6E1}\uFE0F",
|
|
171
|
+
charm: "\u{1F48E}"
|
|
172
|
+
};
|
|
173
|
+
var MAX_INVENTORY = 6;
|
|
144
174
|
var RARITY_WEIGHTS = {
|
|
145
175
|
common: 70,
|
|
146
176
|
calico: 20,
|
|
@@ -161,6 +191,413 @@ function calcExpToNext(level) {
|
|
|
161
191
|
return Math.floor(100 * Math.pow(1.2, level - 1));
|
|
162
192
|
}
|
|
163
193
|
|
|
194
|
+
// src/lib/i18n.ts
|
|
195
|
+
var zh = {
|
|
196
|
+
no_lobster: "\u{1F95A} \u8FD8\u6CA1\u6709\u9F99\u867E\u3002\u8FD0\u884C npx clawfight hatch \u6765\u5B75\u5316\u4E00\u53EA\uFF01",
|
|
197
|
+
status_cant_fight: "\u26A0\uFE0F {name} \u5F53\u524D\u72B6\u6001\u4E3A {status}\uFF0C\u65E0\u6CD5\u6218\u6597\u3002",
|
|
198
|
+
status_cant_patrol_molt: "\u{1F7E1} {name} \u6B63\u5728\u8715\u58F3\u4E2D\uFF0C\u65E0\u6CD5\u5DE1\u903B\u3002",
|
|
199
|
+
status_cant_patrol_hibernate: "\u{1F4A4} {name} \u6B63\u5728\u51AC\u7720\u4E2D\uFF0C\u65E0\u6CD5\u5DE1\u903B\u3002",
|
|
200
|
+
patrol_start: "\u{1F99E} {name} \u5F00\u59CB\u5DE1\u903B...",
|
|
201
|
+
patrol_checkin: "\u{1F4CD} \u5DE1\u903B\u7B7E\u5230 \u2192 \u7ECF\u9A8C +{exp}",
|
|
202
|
+
patrol_connecting: "\u{1F4E1} \u8FDE\u63A5\u670D\u52A1\u5668...",
|
|
203
|
+
patrol_cooldown: "\u23F3 \u5DE1\u903B\u51B7\u5374\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\uFF08\u95F4\u9694\u81F3\u5C11 30 \u5206\u949F\uFF09",
|
|
204
|
+
patrol_encounter: "\u2694\uFE0F \u906D\u9047 {name} (Lv.{level})\uFF01",
|
|
205
|
+
patrol_result_win: " \u6218\u6597\u7ED3\u679C: \u{1F3C6} \u80DC\u5229 ({rounds} \u56DE\u5408)",
|
|
206
|
+
patrol_result_loss: " \u6218\u6597\u7ED3\u679C: \u{1F480} \u5931\u8D25 ({rounds} \u56DE\u5408)",
|
|
207
|
+
patrol_result_draw: " \u6218\u6597\u7ED3\u679C: \u{1F91D} \u5E73\u5C40 ({rounds} \u56DE\u5408)",
|
|
208
|
+
patrol_exp_stats: " \u7ECF\u9A8C +{exp} | \u6218\u7EE9: {wins}\u80DC {losses}\u8D1F | \u8FDE\u80DC: {streak}",
|
|
209
|
+
patrol_no_battle: "\u2694\uFE0F \u906D\u9047 {name} (Lv.{level})\uFF0C\u4F46\u672A\u80FD\u5B8C\u6210\u6218\u6597",
|
|
210
|
+
patrol_done: "\u2705 \u5DE1\u903B\u5B8C\u6210\uFF0C\u5339\u914D\u6C60: {pool} \u53EA\u9F99\u867E",
|
|
211
|
+
patrol_offline: "\u26A0\uFE0F \u670D\u52A1\u5668\u4E0D\u53EF\u8FBE\uFF0C\u8DF3\u8FC7\u5728\u7EBF\u7B7E\u5230",
|
|
212
|
+
patrol_summary: "\u{1F4CA} \u5F53\u524D: Lv.{level} | EXP: {exp}/{next} | \u4ECA\u65E5EXP: {today}/{cap}",
|
|
213
|
+
battle_no_code: "\u26A0\uFE0F \u8BF7\u6307\u5B9A\u5BF9\u624B\u7684\u6218\u6597\u7801\u3002",
|
|
214
|
+
battle_usage: " \u7528\u6CD5: npx clawfight battle <\u6218\u6597\u7801>",
|
|
215
|
+
battle_hint: " \u6218\u6597\u7801\u53EF\u4ECE\u6392\u884C\u699C\u4E2D\u83B7\u53D6: npx clawfight leaderboard",
|
|
216
|
+
battle_connecting: "\u{1F4E1} \u5411\u670D\u52A1\u5668\u53D1\u8D77\u6311\u6218 [{code}]...",
|
|
217
|
+
battle_server_down: "\u26A0\uFE0F \u670D\u52A1\u5668\u4E0D\u53EF\u8FBE\uFF0C\u65E0\u6CD5\u8FDB\u884C\u6218\u6597\u3002",
|
|
218
|
+
battle_win: "\u{1F3C6} \u80DC\u5229\uFF01{name} \u5728 {rounds} \u56DE\u5408\u540E\u51FB\u8D25\u4E86 {opponent}\uFF01",
|
|
219
|
+
battle_loss: "\u{1F480} \u5931\u8D25\u2026{name} \u5728 {rounds} \u56DE\u5408\u540E\u88AB {opponent} \u51FB\u8D25\u3002",
|
|
220
|
+
battle_draw: "\u{1F91D} \u5E73\u5C40\uFF01{rounds} \u56DE\u5408\u540E\u53CC\u65B9\u7CBE\u75B2\u529B\u7AED",
|
|
221
|
+
battle_exp: "\u7ECF\u9A8C +{exp} | \u6218\u7EE9: {wins}\u80DC {losses}\u8D1F | \u8FDE\u80DC: {streak}",
|
|
222
|
+
lb_loading: "\u{1F4E1} \u83B7\u53D6\u5168\u7403\u6392\u884C\u699C...",
|
|
223
|
+
lb_offline: "\u26A0\uFE0F \u670D\u52A1\u5668\u4E0D\u53EF\u8FBE\uFF0C\u65E0\u6CD5\u83B7\u53D6\u6392\u884C\u699C\u3002",
|
|
224
|
+
lb_empty: "\u{1F99E} \u8FD8\u6CA1\u6709\u9F99\u867E\u4E0A\u699C\u3002\u6210\u4E3A\u7B2C\u4E00\u4E2A\u5427\uFF01",
|
|
225
|
+
lb_title: " \u{1F99E} ClawFight \u5168\u7403\u6392\u884C\u699C",
|
|
226
|
+
lb_header: " \u6392\u540D \u540D\u79F0 \u7B49\u7EA7 \u80DC\u573A \u80DC\u7387 \u6218\u6597\u7801",
|
|
227
|
+
lb_total: " \u603B\u9F99\u867E: {total} | \u6D3B\u8DC3: {active}",
|
|
228
|
+
lb_hint: " \u{1F4A1} \u4F7F\u7528 npx clawfight battle <\u6218\u6597\u7801> \u6311\u6218\u6307\u5B9A\u5BF9\u624B",
|
|
229
|
+
status_battle_code: "\u{1F3AF} \u6218\u6597\u7801: {code}",
|
|
230
|
+
event_prefix: "\u{1F3B2} [{category}] {id}",
|
|
231
|
+
event_effects: " \u6548\u679C: {changes}",
|
|
232
|
+
level_up: "\u{1F389} \u5347\u7EA7\uFF01Lv.{level}! [{gains}]",
|
|
233
|
+
molt_trigger: "\u{1F41A} \u89E6\u53D1\u8715\u58F3\u4E8B\u4EF6\uFF01\u9F99\u867E\u8FDB\u5165\u8715\u58F3\u72B6\u6001...",
|
|
234
|
+
hatch_exists: "\u{1F99E} \u4F60\u5DF2\u7ECF\u6709\u4E00\u53EA\u9F99\u867E\u4E86\uFF1A{name}\uFF08Lv.{level}\uFF09",
|
|
235
|
+
hatch_one_only: "\u4E00\u4EBA\u4E00\u867E\uFF0C\u4E0D\u53EF\u66FF\u4EE3\u3002",
|
|
236
|
+
hatch_success: " \u{1F95A} \u2192 \u{1F99E} \u5B75 \u5316 \u6210 \u529F \uFF01",
|
|
237
|
+
hatch_env: " \u73AF\u5883: \u6CBF\u6D77\u6D45\u6EE9",
|
|
238
|
+
hatch_ready: "\u4F60\u7684\u9F99\u867E\u5DF2\u7ECF\u51C6\u5907\u597D\u63A2\u7D22\u6D77\u6D0B\u4E86\uFF01",
|
|
239
|
+
hatch_next: "\u8FD0\u884C npx clawfight patrol \u5F00\u59CB\u7B2C\u4E00\u6B21\u5DE1\u903B\u3002",
|
|
240
|
+
feed_menu_title: "\u{1F37D}\uFE0F \u53EF\u7528\u98DF\u7269\u7C7B\u578B:",
|
|
241
|
+
feed_menu_usage: "\u7528\u6CD5: npx clawfight feed <food_type>",
|
|
242
|
+
feed_full: "\u26A0\uFE0F {name} \u4ECA\u5929\u5DF2\u7ECF\u5403\u9971\u4E86\uFF08\u6BCF\u65E5\u7ECF\u9A8C\u4E0A\u9650 {cap}\uFF09",
|
|
243
|
+
feed_ate: "\u{1F37D}\uFE0F {name} \u5403\u4E86 {food}\uFF01",
|
|
244
|
+
feed_exp: " \u7ECF\u9A8C +{exp}",
|
|
245
|
+
feed_exp_stat: " \u7ECF\u9A8C +{exp} | {stat} +{bonus}",
|
|
246
|
+
feed_today: " \u4ECA\u65E5\u7ECF\u9A8C: {today}/{cap}",
|
|
247
|
+
food_protein: "\u9AD8\u86CB\u767D\u98DF\u7269",
|
|
248
|
+
food_algae: "\u85FB\u7C7B\u98DF\u7269",
|
|
249
|
+
food_mineral: "\u77FF\u7269\u8D28",
|
|
250
|
+
rest_already: "\u{1F4A4} {name} \u5DF2\u7ECF\u5728\u4F11\u7720\u4E2D\u4E86\u3002\u8FD0\u884C npx clawfight wake \u6765\u5524\u9192\u5B83\u3002",
|
|
251
|
+
rest_molting: "\u{1F7E1} {name} \u6B63\u5728\u8715\u58F3\uFF0C\u4E0D\u80FD\u4F11\u7720\u3002\u7B49\u8715\u58F3\u7ED3\u675F\u518D\u6765\u3002",
|
|
252
|
+
rest_desc1: "\u{1F4A4} {name} \u7F13\u7F13\u6C89\u5165\u6D77\u5E95\u6C99\u5730...",
|
|
253
|
+
rest_desc2: " \u9F99\u867E\u8737\u7F29\u8D77\u89E6\u987B\uFF0C\u5B89\u9759\u5730\u4F11\u606F\u3002",
|
|
254
|
+
rest_desc3: " \u4F11\u7720\u671F\u95F4\u4E0D\u4F1A\u53C2\u4E0E\u5DE1\u903B\u548C\u6218\u6597\u3002",
|
|
255
|
+
rest_desc4: " \u9192\u6765\u540E\u4F1A\u83B7\u5F97\u6062\u590D\u52A0\u6210\uFF01",
|
|
256
|
+
rest_wake_hint: "\u8FD0\u884C npx clawfight wake \u6765\u5524\u9192\u5B83\u3002",
|
|
257
|
+
wake_not_sleeping: "\u{1F7E2} {name} \u6CA1\u6709\u5728\u4F11\u7720\u3002\u5B83\u5DF2\u7ECF\u662F\u6D3B\u8DC3\u72B6\u6001\u4E86\uFF01",
|
|
258
|
+
wake_desc: "\u2600\uFE0F {name} \u4ECE\u6C99\u5730\u4E2D\u7F13\u7F13\u82CF\u9192...",
|
|
259
|
+
wake_duration: " \u4F11\u7720\u65F6\u957F: {duration}",
|
|
260
|
+
wake_bonus: " \u6062\u590D\u52A0\u6210: {bonus}",
|
|
261
|
+
wake_no_bonus: "\uFF08\u4F11\u7720\u4E0D\u8DB3 4 \u5C0F\u65F6\uFF0C\u65E0\u52A0\u6210\uFF09",
|
|
262
|
+
wake_ready: "\u{1F7E2} {name} \u7CBE\u795E\u7115\u53D1\uFF0C\u51C6\u5907\u597D\u518D\u6B21\u51FA\u51FB\uFF01",
|
|
263
|
+
duration_minutes: "{n} \u5206\u949F",
|
|
264
|
+
duration_hours: "{n} \u5C0F\u65F6",
|
|
265
|
+
depth_display: "\u6DF1\u5EA6:{depth}",
|
|
266
|
+
soul_trait: " \u6027\u683C\u7279\u8D28: [{trait}]",
|
|
267
|
+
equip_drop: "\u{1F381} \u83B7\u5F97: {item}",
|
|
268
|
+
auto_equip: "\u{1F99E} {name}\uFF08{reason}\uFF09\u2192 \u81EA\u52A8\u88C5\u5907 {item}",
|
|
269
|
+
auto_swap: "\u{1F99E} {name}\uFF08{reason}\uFF09\u2192 \u6362\u4E0B {old}\uFF0C\u88C5\u5907 {item}",
|
|
270
|
+
auto_discard: "\u{1F99E} {name} \u4E22\u5F03\u4E86 {item}\uFF08{reason}\uFF09",
|
|
271
|
+
equip_degrade: "\u{1F527} \u78E8\u635F: {items}",
|
|
272
|
+
equip_broken: "\u{1F4A5} \u635F\u574F: {items}",
|
|
273
|
+
equip_inv_full: "\u{1F4E6} \u80CC\u5305\u5DF2\u6EE1({max})\uFF0C\u4E22\u5F03\u4E86 {item}",
|
|
274
|
+
equip_title: "\u{1F392} \u88C5\u5907\u7BA1\u7406",
|
|
275
|
+
equip_slot_empty: " {icon} {slot}: (\u7A7A)",
|
|
276
|
+
equip_slot_item: " {icon} {slot}: {item}",
|
|
277
|
+
equip_inv_title: "\u{1F4E6} \u80CC\u5305 ({count}/{max}):",
|
|
278
|
+
equip_inv_item: " [{index}] {item}",
|
|
279
|
+
equip_inv_empty: " (\u7A7A)",
|
|
280
|
+
equip_equipped: "\u2705 \u5DF2\u88C5\u5907 {item} \u2192 {slot}",
|
|
281
|
+
equip_swapped: "\u{1F504} \u66FF\u6362 {old} \u2192 {item}",
|
|
282
|
+
equip_dropped: "\u{1F5D1}\uFE0F \u5DF2\u4E22\u5F03 {item}",
|
|
283
|
+
equip_unequipped: "\u{1F4E4} \u5DF2\u5378\u4E0B {item}",
|
|
284
|
+
equip_bad_index: "\u26A0\uFE0F \u65E0\u6548\u7F16\u53F7\u3002\u67E5\u770B\u80CC\u5305: npx clawfight equip",
|
|
285
|
+
equip_usage: "\u7528\u6CD5: equip / equip <\u7F16\u53F7> / equip drop <\u7F16\u53F7> / equip unequip <\u69FD\u4F4D>",
|
|
286
|
+
achieve_unlock: "\u{1F3C6} \u6210\u5C31\u89E3\u9501: {name} \u2014 {desc}",
|
|
287
|
+
achieve_title: "\u{1F3C6} \u6210\u5C31 ({count}/{total}):",
|
|
288
|
+
achieve_item: " \u2705 {name} \u2014 {desc}",
|
|
289
|
+
achieve_locked: " \u{1F512} {name} \u2014 {desc}",
|
|
290
|
+
achieve_none: " \u8FD8\u6CA1\u6709\u89E3\u9501\u4EFB\u4F55\u6210\u5C31\u3002\u7EE7\u7EED\u5192\u9669\u5427\uFF01",
|
|
291
|
+
patrol_depth: "\u{1F4CA} Lv.{level} | EXP:{exp}/{next} | \u4ECA\u65E5:{today}/{cap} | \u6DF1\u5EA6:{depth} | \u80CC\u5305:{inv}/{inv_max}",
|
|
292
|
+
depth_reset: "\u{1F4A4} \u6DF1\u5EA6\u5DF2\u91CD\u7F6E",
|
|
293
|
+
dg_connecting: "\u{1F4E1} \u8FDE\u63A5\u5730\u4E0B\u57CE\u670D\u52A1\u5668...",
|
|
294
|
+
dg_resume: "\u{1F3F0} \u68C0\u6D4B\u5230\u8FDB\u884C\u4E2D\u7684\u5730\u4E0B\u57CE\u63A2\u7D22\uFF1A",
|
|
295
|
+
dg_no_maps: "\u{1F5FA}\uFE0F \u6CA1\u6709\u5730\u4E0B\u57CE\u5730\u56FE\u3002\u7EE7\u7EED\u5DE1\u903B\u83B7\u53D6\u5730\u56FE\uFF01",
|
|
296
|
+
dg_bad_map_index: "\u26A0\uFE0F \u65E0\u6548\u5730\u56FE\u7F16\u53F7\uFF08\u5171{count}\u5F20\uFF09",
|
|
297
|
+
dg_entering: "\u{1F3F0} \u8FDB\u5165\u5730\u4E0B\u57CE: {theme} | {rooms}\u623F\u95F4 | {diff}",
|
|
298
|
+
dg_no_active: "\u26A0\uFE0F \u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u5730\u4E0B\u57CE\u3002\u5148\u7528 explore \u8FDB\u5165\u4E00\u4E2A\u3002",
|
|
299
|
+
dg_complete: "\u{1F389} \u5730\u4E0B\u57CE\u901A\u5173\uFF01",
|
|
300
|
+
dg_failed: "\u{1F480} \u5730\u4E0B\u57CE\u63A2\u7D22\u5931\u8D25\u2026HP\u5F52\u96F6",
|
|
301
|
+
dg_rewards_exp: "\u{1F4CA} \u5730\u4E0B\u57CE\u7ECF\u9A8C: +{exp}",
|
|
302
|
+
dg_abandoning: "\u{1F3F3}\uFE0F \u653E\u5F03\u5730\u4E0B\u57CE\u63A2\u7D22...",
|
|
303
|
+
dg_abandoned: "\u{1F3F3}\uFE0F \u5DF2\u64A4\u9000 | EXP+{exp} | \u6218\u5229\u54C1\xD7{loot} | \u6DF1\u5EA6\u2192{depth}",
|
|
304
|
+
dg_maps_title: "\u{1F5FA}\uFE0F \u5730\u4E0B\u57CE\u5730\u56FE\uFF08{count}\u5F20\uFF09:",
|
|
305
|
+
dg_rooms: "\u623F\u95F4",
|
|
306
|
+
dg_maps_hint: " \u{1F4A1} \u7528\u6CD5: explore <\u7F16\u53F7> \u8FDB\u5165 | explore maps \u67E5\u770B",
|
|
307
|
+
dg_map_found: "\u{1F5FA}\uFE0F \u53D1\u73B0\u5730\u4E0B\u57CE\u5730\u56FE: {theme} ({rooms}\u623F\u95F4, {diff})",
|
|
308
|
+
dg_summary: "\u{1F4CA} Lv.{level} | EXP:{exp}/{next} | \u4ECA\u65E5:{today}/{cap}",
|
|
309
|
+
dg_theme_coral_maze: "\u73CA\u745A\u8FF7\u5BAB",
|
|
310
|
+
dg_theme_deep_rift: "\u6DF1\u6D77\u88C2\u9699",
|
|
311
|
+
dg_theme_thermal_vent: "\u70ED\u6CC9\u55B7\u53E3",
|
|
312
|
+
dg_theme_ice_cavern: "\u51B0\u6676\u6D1E\u7A74",
|
|
313
|
+
dg_theme_shipwreck: "\u6C89\u8239\u9057\u8FF9",
|
|
314
|
+
dg_theme_abyss_trench: "\u6DF1\u6E0A\u6D77\u6C9F",
|
|
315
|
+
dg_theme_tide_pool: "\u6F6E\u6C50\u6D45\u6EE9",
|
|
316
|
+
dg_theme_void_rift: "\u865A\u7A7A\u88C2\u7F1D",
|
|
317
|
+
dg_risk_low: "\u4F4E\u98CE\u9669",
|
|
318
|
+
dg_risk_mid: "\u4E2D\u98CE\u9669",
|
|
319
|
+
dg_risk_high: "\u9AD8\u98CE\u9669",
|
|
320
|
+
dg_diff_easy: "\u7B80\u5355",
|
|
321
|
+
dg_diff_normal: "\u666E\u901A",
|
|
322
|
+
dg_diff_hard: "\u56F0\u96BE",
|
|
323
|
+
dg_diff_nightmare: "\u5669\u68A6",
|
|
324
|
+
dg_charge_attack: "\u731B\u529B\u51B2\u51FB",
|
|
325
|
+
dg_defensive_stance: "\u9632\u5FA1\u59FF\u6001",
|
|
326
|
+
dg_rush_strike: "\u95EA\u7535\u7A81\u88AD",
|
|
327
|
+
dg_counter_wait: "\u4F3A\u673A\u53CD\u51FB",
|
|
328
|
+
dg_open_golden_chest: "\u6253\u5F00\u91D1\u8272\u5B9D\u7BB1",
|
|
329
|
+
dg_open_stone_chest: "\u6253\u5F00\u77F3\u8D28\u5B9D\u7BB1",
|
|
330
|
+
dg_reach_deep_cache: "\u63A2\u7D22\u6DF1\u5C42\u5B9D\u85CF",
|
|
331
|
+
dg_take_surface_loot: "\u62FE\u53D6\u8868\u5C42\u6218\u5229\u54C1",
|
|
332
|
+
dg_disarm_mechanism: "\u62C6\u89E3\u673A\u5173",
|
|
333
|
+
dg_dodge_through: "\u7075\u5DE7\u95EA\u907F",
|
|
334
|
+
dg_brute_force: "\u86EE\u529B\u7A81\u7834",
|
|
335
|
+
dg_careful_bypass: "\u5C0F\u5FC3\u7ED5\u884C",
|
|
336
|
+
dg_deep_rest: "\u6DF1\u5EA6\u4F11\u606F",
|
|
337
|
+
dg_search_hidden: "\u641C\u7D22\u9690\u85CF\u7269",
|
|
338
|
+
dg_investigate: "\u8C03\u67E5\u7EBF\u7D22",
|
|
339
|
+
dg_proceed_cautiously: "\u8C28\u614E\u524D\u884C",
|
|
340
|
+
dg_touch_artifact: "\u89E6\u78B0\u795E\u5668",
|
|
341
|
+
dg_observe_only: "\u4EC5\u89C2\u5BDF",
|
|
342
|
+
dg_all_out_assault: "\u5168\u529B\u8FDB\u653B",
|
|
343
|
+
dg_tactical_approach: "\u7B56\u7565\u63A5\u8FD1",
|
|
344
|
+
dg_bravery_bonus: "\u52C7\u6C14\u52A0\u6210: ATK+20%",
|
|
345
|
+
dg_curiosity_bonus: "\u597D\u5947\u5FC3\u52A0\u6210: \u53D1\u73B0\u7387\u2191",
|
|
346
|
+
dg_temper_bonus: "\u66B4\u6012\u52A0\u6210: \u62C6\u89E3\u529B\u2191",
|
|
347
|
+
dg_charge_attack_success: "\u731B\u529B\u51B2\u51FB\u547D\u4E2D\uFF01",
|
|
348
|
+
dg_charge_attack_fail: "\u731B\u529B\u51B2\u51FB\u843D\u7A7A\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
349
|
+
dg_defensive_stance_success: "\u9632\u5FA1\u59FF\u6001\u6210\u529F\uFF01\u5B89\u5168\u5EA6\u8FC7",
|
|
350
|
+
dg_defensive_stance_fail: "\u9632\u5FA1\u59FF\u6001\u88AB\u7A81\u7834\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
351
|
+
dg_rush_strike_success: "\u95EA\u7535\u7A81\u88AD\u5F97\u624B\uFF01",
|
|
352
|
+
dg_rush_strike_fail: "\u7A81\u88AD\u5931\u8D25\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
353
|
+
dg_counter_wait_success: "\u53CD\u51FB\u6210\u529F\uFF01",
|
|
354
|
+
dg_counter_wait_fail: "\u53CD\u51FB\u65F6\u673A\u5931\u8BEF\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
355
|
+
dg_open_golden_chest_success: "\u91D1\u8272\u5B9D\u7BB1\u5F00\u542F\uFF01\u5B9D\u7269\u95EA\u8000",
|
|
356
|
+
dg_open_golden_chest_fail: "\u9677\u9631\u89E6\u53D1\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
357
|
+
dg_open_stone_chest_success: "\u77F3\u8D28\u5B9D\u7BB1\u5F00\u542F\uFF01\u83B7\u5F97\u7269\u54C1",
|
|
358
|
+
dg_open_stone_chest_fail: "\u5B9D\u7BB1\u662F\u7A7A\u7684...",
|
|
359
|
+
dg_reach_deep_cache_success: "\u53D1\u73B0\u6DF1\u5C42\u5B9D\u85CF\uFF01",
|
|
360
|
+
dg_reach_deep_cache_fail: "\u6DF1\u5C42\u641C\u7D22\u65E0\u679C",
|
|
361
|
+
dg_take_surface_loot_success: "\u62FE\u53D6\u8868\u5C42\u6218\u5229\u54C1\uFF01",
|
|
362
|
+
dg_take_surface_loot_fail: "\u4EC0\u4E48\u90FD\u6CA1\u627E\u5230",
|
|
363
|
+
dg_disarm_mechanism_success: "\u673A\u5173\u62C6\u89E3\u6210\u529F\uFF01",
|
|
364
|
+
dg_disarm_mechanism_fail: "\u673A\u5173\u89E6\u53D1\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
365
|
+
dg_dodge_through_success: "\u7075\u5DE7\u5730\u95EA\u907F\u4E86\u673A\u5173\uFF01",
|
|
366
|
+
dg_dodge_through_fail: "\u95EA\u907F\u5931\u8D25\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
367
|
+
dg_brute_force_success: "\u86EE\u529B\u7A81\u7834\u6210\u529F\uFF01",
|
|
368
|
+
dg_brute_force_fail: "\u86EE\u529B\u7A81\u7834\u5931\u8D25\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
369
|
+
dg_careful_bypass_success: "\u5C0F\u5FC3\u7ED5\u884C\u6210\u529F\uFF01",
|
|
370
|
+
dg_careful_bypass_fail: "\u7ED5\u884C\u5931\u8D25\u2026",
|
|
371
|
+
dg_rest_healed: "\u4F11\u606F\u6062\u590D HP+{heal}",
|
|
372
|
+
dg_search_hidden_success: "\u641C\u7D22\u5230\u9690\u85CF\u7269\u54C1\uFF01",
|
|
373
|
+
dg_search_hidden_fail: "\u641C\u7D22\u672A\u679C",
|
|
374
|
+
dg_investigate_success: "\u8C03\u67E5\u53D1\u73B0\u4E86\u79D8\u5BC6\uFF01",
|
|
375
|
+
dg_investigate_fail: "\u8C03\u67E5\u65E0\u679C",
|
|
376
|
+
dg_proceed_cautiously_success: "\u8C28\u614E\u524D\u884C\uFF0C\u5B89\u5168\u901A\u8FC7",
|
|
377
|
+
dg_proceed_cautiously_fail: "\u610F\u5916\u906D\u9047\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
378
|
+
dg_touch_artifact_success: "\u795E\u5668\u91CA\u653E\u4E86\u529B\u91CF\uFF01",
|
|
379
|
+
dg_touch_artifact_fail: "\u795E\u5668\u53CD\u566C\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
380
|
+
dg_observe_only_success: "\u89C2\u5BDF\u5230\u4E86\u6709\u7528\u7684\u7EBF\u7D22",
|
|
381
|
+
dg_observe_only_fail: "\u4EC0\u4E48\u4E5F\u6CA1\u53D1\u73B0",
|
|
382
|
+
dg_all_out_assault_success: "\u5168\u529B\u8FDB\u653B\u594F\u6548\uFF01Boss\u53D7\u5230\u91CD\u521B",
|
|
383
|
+
dg_all_out_assault_fail: "Boss\u53CD\u51FB\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3",
|
|
384
|
+
dg_tactical_approach_success: "\u7B56\u7565\u63A5\u8FD1\u6210\u529F\uFF01\u627E\u5230\u5F31\u70B9",
|
|
385
|
+
dg_tactical_approach_fail: "Boss\u8BC6\u7834\u7B56\u7565\uFF01\u53D7\u5230{damage}\u70B9\u4F24\u5BB3"
|
|
386
|
+
};
|
|
387
|
+
var en = {
|
|
388
|
+
no_lobster: "\u{1F95A} No lobster yet. Run npx clawfight hatch to hatch one!",
|
|
389
|
+
status_cant_fight: "\u26A0\uFE0F {name} is currently {status}, can't battle.",
|
|
390
|
+
status_cant_patrol_molt: "\u{1F7E1} {name} is molting, can't patrol.",
|
|
391
|
+
status_cant_patrol_hibernate: "\u{1F4A4} {name} is hibernating, can't patrol.",
|
|
392
|
+
patrol_start: "\u{1F99E} {name} starts patrolling...",
|
|
393
|
+
patrol_checkin: "\u{1F4CD} Patrol check-in \u2192 EXP +{exp}",
|
|
394
|
+
patrol_connecting: "\u{1F4E1} Connecting to server...",
|
|
395
|
+
patrol_cooldown: "\u23F3 Patrol on cooldown, try again later (30 min interval)",
|
|
396
|
+
patrol_encounter: "\u2694\uFE0F Encounter: {name} (Lv.{level})!",
|
|
397
|
+
patrol_result_win: " Result: \u{1F3C6} Victory ({rounds} rounds)",
|
|
398
|
+
patrol_result_loss: " Result: \u{1F480} Defeat ({rounds} rounds)",
|
|
399
|
+
patrol_result_draw: " Result: \u{1F91D} Draw ({rounds} rounds)",
|
|
400
|
+
patrol_exp_stats: " EXP +{exp} | Record: {wins}W {losses}L | Streak: {streak}",
|
|
401
|
+
patrol_no_battle: "\u2694\uFE0F Encountered {name} (Lv.{level}), but battle could not complete",
|
|
402
|
+
patrol_done: "\u2705 Patrol done, pool: {pool} lobsters",
|
|
403
|
+
patrol_offline: "\u26A0\uFE0F Server unreachable, skipping online check-in",
|
|
404
|
+
patrol_summary: "\u{1F4CA} Current: Lv.{level} | EXP: {exp}/{next} | Today: {today}/{cap}",
|
|
405
|
+
battle_no_code: "\u26A0\uFE0F Please provide opponent's battle code.",
|
|
406
|
+
battle_usage: " Usage: npx clawfight battle <code>",
|
|
407
|
+
battle_hint: " Find codes on the leaderboard: npx clawfight leaderboard",
|
|
408
|
+
battle_connecting: "\u{1F4E1} Challenging [{code}]...",
|
|
409
|
+
battle_server_down: "\u26A0\uFE0F Server unreachable, can't battle.",
|
|
410
|
+
battle_win: "\u{1F3C6} Victory! {name} defeated {opponent} in {rounds} rounds!",
|
|
411
|
+
battle_loss: "\u{1F480} Defeat\u2026 {name} was beaten by {opponent} in {rounds} rounds.",
|
|
412
|
+
battle_draw: "\u{1F91D} Draw! Both exhausted after {rounds} rounds",
|
|
413
|
+
battle_exp: "EXP +{exp} | Record: {wins}W {losses}L | Streak: {streak}",
|
|
414
|
+
lb_loading: "\u{1F4E1} Fetching global leaderboard...",
|
|
415
|
+
lb_offline: "\u26A0\uFE0F Server unreachable, can't load leaderboard.",
|
|
416
|
+
lb_empty: "\u{1F99E} No lobsters on the board yet. Be the first!",
|
|
417
|
+
lb_title: " \u{1F99E} ClawFight Global Leaderboard",
|
|
418
|
+
lb_header: " Rank Name Level Wins WR Code",
|
|
419
|
+
lb_total: " Total: {total} | Active: {active}",
|
|
420
|
+
lb_hint: " \u{1F4A1} Use npx clawfight battle <code> to challenge an opponent",
|
|
421
|
+
status_battle_code: "\u{1F3AF} Battle code: {code}",
|
|
422
|
+
event_prefix: "\u{1F3B2} [{category}] {id}",
|
|
423
|
+
event_effects: " Effects: {changes}",
|
|
424
|
+
level_up: "\u{1F389} Level up! Lv.{level}! [{gains}]",
|
|
425
|
+
molt_trigger: "\u{1F41A} Molt triggered! Lobster enters molting state...",
|
|
426
|
+
hatch_exists: "\u{1F99E} You already have a lobster: {name} (Lv.{level})",
|
|
427
|
+
hatch_one_only: "One per person, irreplaceable.",
|
|
428
|
+
hatch_success: " \u{1F95A} \u2192 \u{1F99E} HATCH SUCCESS!",
|
|
429
|
+
hatch_env: " Environment: Coastal Shallows",
|
|
430
|
+
hatch_ready: "Your lobster is ready to explore the ocean!",
|
|
431
|
+
hatch_next: "Run npx clawfight patrol to start your first patrol.",
|
|
432
|
+
feed_menu_title: "\u{1F37D}\uFE0F Available food types:",
|
|
433
|
+
feed_menu_usage: "Usage: npx clawfight feed <food_type>",
|
|
434
|
+
feed_full: "\u26A0\uFE0F {name} is full today (daily EXP cap {cap})",
|
|
435
|
+
feed_ate: "\u{1F37D}\uFE0F {name} ate {food}!",
|
|
436
|
+
feed_exp: " EXP +{exp}",
|
|
437
|
+
feed_exp_stat: " EXP +{exp} | {stat} +{bonus}",
|
|
438
|
+
feed_today: " Today EXP: {today}/{cap}",
|
|
439
|
+
food_protein: "High Protein",
|
|
440
|
+
food_algae: "Algae",
|
|
441
|
+
food_mineral: "Minerals",
|
|
442
|
+
rest_already: "\u{1F4A4} {name} is already hibernating. Run npx clawfight wake to wake it.",
|
|
443
|
+
rest_molting: "\u{1F7E1} {name} is molting, can't hibernate now.",
|
|
444
|
+
rest_desc1: "\u{1F4A4} {name} sinks into the sandy seabed...",
|
|
445
|
+
rest_desc2: " The lobster curls its antennae and rests quietly.",
|
|
446
|
+
rest_desc3: " No patrols or battles during hibernation.",
|
|
447
|
+
rest_desc4: " Wake bonuses await!",
|
|
448
|
+
rest_wake_hint: "Run npx clawfight wake to wake it up.",
|
|
449
|
+
wake_not_sleeping: "\u{1F7E2} {name} is not hibernating. Already active!",
|
|
450
|
+
wake_desc: "\u2600\uFE0F {name} slowly wakes from the sandy seabed...",
|
|
451
|
+
wake_duration: " Sleep duration: {duration}",
|
|
452
|
+
wake_bonus: " Recovery bonus: {bonus}",
|
|
453
|
+
wake_no_bonus: "(Less than 4 hours, no bonus)",
|
|
454
|
+
wake_ready: "\u{1F7E2} {name} is refreshed and ready to go!",
|
|
455
|
+
duration_minutes: "{n} min",
|
|
456
|
+
duration_hours: "{n} hours",
|
|
457
|
+
depth_display: "Depth:{depth}",
|
|
458
|
+
soul_trait: " Traits: [{trait}]",
|
|
459
|
+
equip_drop: "\u{1F381} Loot: {item}",
|
|
460
|
+
auto_equip: "\u{1F99E} {name} ({reason}) \u2192 auto-equipped {item}",
|
|
461
|
+
auto_swap: "\u{1F99E} {name} ({reason}) \u2192 swapped out {old} for {item}",
|
|
462
|
+
auto_discard: "\u{1F99E} {name} discarded {item} ({reason})",
|
|
463
|
+
equip_degrade: "\u{1F527} Worn: {items}",
|
|
464
|
+
equip_broken: "\u{1F4A5} Broken: {items}",
|
|
465
|
+
equip_inv_full: "\u{1F4E6} Inventory full({max}), discarded {item}",
|
|
466
|
+
equip_title: "\u{1F392} Equipment",
|
|
467
|
+
equip_slot_empty: " {icon} {slot}: (empty)",
|
|
468
|
+
equip_slot_item: " {icon} {slot}: {item}",
|
|
469
|
+
equip_inv_title: "\u{1F4E6} Inventory ({count}/{max}):",
|
|
470
|
+
equip_inv_item: " [{index}] {item}",
|
|
471
|
+
equip_inv_empty: " (empty)",
|
|
472
|
+
equip_equipped: "\u2705 Equipped {item} \u2192 {slot}",
|
|
473
|
+
equip_swapped: "\u{1F504} Swapped {old} \u2192 {item}",
|
|
474
|
+
equip_dropped: "\u{1F5D1}\uFE0F Discarded {item}",
|
|
475
|
+
equip_unequipped: "\u{1F4E4} Unequipped {item}",
|
|
476
|
+
equip_bad_index: "\u26A0\uFE0F Invalid index. Check: npx clawfight equip",
|
|
477
|
+
equip_usage: "Usage: equip / equip <index> / equip drop <index> / equip unequip <slot>",
|
|
478
|
+
achieve_unlock: "\u{1F3C6} Achievement: {name} \u2014 {desc}",
|
|
479
|
+
achieve_title: "\u{1F3C6} Achievements ({count}/{total}):",
|
|
480
|
+
achieve_item: " \u2705 {name} \u2014 {desc}",
|
|
481
|
+
achieve_locked: " \u{1F512} {name} \u2014 {desc}",
|
|
482
|
+
achieve_none: " No achievements yet. Keep exploring!",
|
|
483
|
+
patrol_depth: "\u{1F4CA} Lv.{level} | EXP:{exp}/{next} | Today:{today}/{cap} | Depth:{depth} | Bag:{inv}/{inv_max}",
|
|
484
|
+
depth_reset: "\u{1F4A4} Depth reset",
|
|
485
|
+
dg_connecting: "\u{1F4E1} Connecting to dungeon server...",
|
|
486
|
+
dg_resume: "\u{1F3F0} Active dungeon detected:",
|
|
487
|
+
dg_no_maps: "\u{1F5FA}\uFE0F No dungeon maps. Keep patrolling to find some!",
|
|
488
|
+
dg_bad_map_index: "\u26A0\uFE0F Invalid map index (have {count})",
|
|
489
|
+
dg_entering: "\u{1F3F0} Entering dungeon: {theme} | {rooms} rooms | {diff}",
|
|
490
|
+
dg_no_active: "\u26A0\uFE0F No active dungeon. Use explore to enter one.",
|
|
491
|
+
dg_complete: "\u{1F389} Dungeon cleared!",
|
|
492
|
+
dg_failed: "\u{1F480} Dungeon failed\u2026 HP reached zero",
|
|
493
|
+
dg_rewards_exp: "\u{1F4CA} Dungeon EXP: +{exp}",
|
|
494
|
+
dg_abandoning: "\u{1F3F3}\uFE0F Abandoning dungeon...",
|
|
495
|
+
dg_abandoned: "\u{1F3F3}\uFE0F Retreated | EXP+{exp} | Loot\xD7{loot} | Depth\u2192{depth}",
|
|
496
|
+
dg_maps_title: "\u{1F5FA}\uFE0F Dungeon maps ({count}):",
|
|
497
|
+
dg_rooms: " rooms",
|
|
498
|
+
dg_maps_hint: " \u{1F4A1} Usage: explore <index> to enter | explore maps to view",
|
|
499
|
+
dg_map_found: "\u{1F5FA}\uFE0F Found dungeon map: {theme} ({rooms} rooms, {diff})",
|
|
500
|
+
dg_summary: "\u{1F4CA} Lv.{level} | EXP:{exp}/{next} | Today:{today}/{cap}",
|
|
501
|
+
dg_theme_coral_maze: "Coral Maze",
|
|
502
|
+
dg_theme_deep_rift: "Deep Rift",
|
|
503
|
+
dg_theme_thermal_vent: "Thermal Vent",
|
|
504
|
+
dg_theme_ice_cavern: "Ice Cavern",
|
|
505
|
+
dg_theme_shipwreck: "Shipwreck",
|
|
506
|
+
dg_theme_abyss_trench: "Abyss Trench",
|
|
507
|
+
dg_theme_tide_pool: "Tide Pool",
|
|
508
|
+
dg_theme_void_rift: "Void Rift",
|
|
509
|
+
dg_risk_low: "Low",
|
|
510
|
+
dg_risk_mid: "Mid",
|
|
511
|
+
dg_risk_high: "High",
|
|
512
|
+
dg_diff_easy: "Easy",
|
|
513
|
+
dg_diff_normal: "Normal",
|
|
514
|
+
dg_diff_hard: "Hard",
|
|
515
|
+
dg_diff_nightmare: "Nightmare",
|
|
516
|
+
dg_charge_attack: "Charge Attack",
|
|
517
|
+
dg_defensive_stance: "Defensive Stance",
|
|
518
|
+
dg_rush_strike: "Rush Strike",
|
|
519
|
+
dg_counter_wait: "Counter Wait",
|
|
520
|
+
dg_open_golden_chest: "Open Golden Chest",
|
|
521
|
+
dg_open_stone_chest: "Open Stone Chest",
|
|
522
|
+
dg_reach_deep_cache: "Reach Deep Cache",
|
|
523
|
+
dg_take_surface_loot: "Take Surface Loot",
|
|
524
|
+
dg_disarm_mechanism: "Disarm Mechanism",
|
|
525
|
+
dg_dodge_through: "Dodge Through",
|
|
526
|
+
dg_brute_force: "Brute Force",
|
|
527
|
+
dg_careful_bypass: "Careful Bypass",
|
|
528
|
+
dg_deep_rest: "Deep Rest",
|
|
529
|
+
dg_search_hidden: "Search Hidden",
|
|
530
|
+
dg_investigate: "Investigate",
|
|
531
|
+
dg_proceed_cautiously: "Proceed Cautiously",
|
|
532
|
+
dg_touch_artifact: "Touch Artifact",
|
|
533
|
+
dg_observe_only: "Observe Only",
|
|
534
|
+
dg_all_out_assault: "All-Out Assault",
|
|
535
|
+
dg_tactical_approach: "Tactical Approach",
|
|
536
|
+
dg_bravery_bonus: "Bravery bonus: ATK+20%",
|
|
537
|
+
dg_curiosity_bonus: "Curiosity bonus: Discovery\u2191",
|
|
538
|
+
dg_temper_bonus: "Temper bonus: Disarm\u2191",
|
|
539
|
+
dg_charge_attack_success: "Charge hit!",
|
|
540
|
+
dg_charge_attack_fail: "Charge missed! Took {damage} damage",
|
|
541
|
+
dg_defensive_stance_success: "Defense held!",
|
|
542
|
+
dg_defensive_stance_fail: "Defense breached! Took {damage} damage",
|
|
543
|
+
dg_rush_strike_success: "Rush strike landed!",
|
|
544
|
+
dg_rush_strike_fail: "Rush failed! Took {damage} damage",
|
|
545
|
+
dg_counter_wait_success: "Counter hit!",
|
|
546
|
+
dg_counter_wait_fail: "Counter mistimed! Took {damage} damage",
|
|
547
|
+
dg_open_golden_chest_success: "Golden chest opened! Treasure shines",
|
|
548
|
+
dg_open_golden_chest_fail: "Trap triggered! Took {damage} damage",
|
|
549
|
+
dg_open_stone_chest_success: "Stone chest opened! Item found",
|
|
550
|
+
dg_open_stone_chest_fail: "Chest was empty...",
|
|
551
|
+
dg_reach_deep_cache_success: "Deep cache found!",
|
|
552
|
+
dg_reach_deep_cache_fail: "Deep search failed",
|
|
553
|
+
dg_take_surface_loot_success: "Surface loot collected!",
|
|
554
|
+
dg_take_surface_loot_fail: "Nothing found",
|
|
555
|
+
dg_disarm_mechanism_success: "Mechanism disarmed!",
|
|
556
|
+
dg_disarm_mechanism_fail: "Trap triggered! Took {damage} damage",
|
|
557
|
+
dg_dodge_through_success: "Dodged through the trap!",
|
|
558
|
+
dg_dodge_through_fail: "Dodge failed! Took {damage} damage",
|
|
559
|
+
dg_brute_force_success: "Brute force worked!",
|
|
560
|
+
dg_brute_force_fail: "Brute force failed! Took {damage} damage",
|
|
561
|
+
dg_careful_bypass_success: "Bypassed safely!",
|
|
562
|
+
dg_careful_bypass_fail: "Bypass failed\u2026",
|
|
563
|
+
dg_rest_healed: "Rested. HP+{heal}",
|
|
564
|
+
dg_search_hidden_success: "Found hidden item!",
|
|
565
|
+
dg_search_hidden_fail: "Search found nothing",
|
|
566
|
+
dg_investigate_success: "Investigation uncovered a secret!",
|
|
567
|
+
dg_investigate_fail: "Investigation found nothing",
|
|
568
|
+
dg_proceed_cautiously_success: "Proceeded safely",
|
|
569
|
+
dg_proceed_cautiously_fail: "Unexpected encounter! Took {damage} damage",
|
|
570
|
+
dg_touch_artifact_success: "Artifact releases power!",
|
|
571
|
+
dg_touch_artifact_fail: "Artifact backlash! Took {damage} damage",
|
|
572
|
+
dg_observe_only_success: "Observed useful clue",
|
|
573
|
+
dg_observe_only_fail: "Nothing observed",
|
|
574
|
+
dg_all_out_assault_success: "All-out assault devastated the Boss!",
|
|
575
|
+
dg_all_out_assault_fail: "Boss counterattacked! Took {damage} damage",
|
|
576
|
+
dg_tactical_approach_success: "Tactical approach found weakness!",
|
|
577
|
+
dg_tactical_approach_fail: "Boss saw through the strategy! Took {damage} damage"
|
|
578
|
+
};
|
|
579
|
+
function detectLocale() {
|
|
580
|
+
const lang = process.env.LANG || process.env.LANGUAGE || process.env.LC_ALL || "";
|
|
581
|
+
if (lang.startsWith("zh")) return "zh";
|
|
582
|
+
try {
|
|
583
|
+
const sysLocale = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
584
|
+
if (sysLocale.startsWith("zh")) return "zh";
|
|
585
|
+
} catch {
|
|
586
|
+
}
|
|
587
|
+
return "en";
|
|
588
|
+
}
|
|
589
|
+
var locale = detectLocale();
|
|
590
|
+
var strings = locale === "zh" ? zh : en;
|
|
591
|
+
function t(key, params) {
|
|
592
|
+
let msg = strings[key] || zh[key] || key;
|
|
593
|
+
if (params) {
|
|
594
|
+
for (const [k, v] of Object.entries(params)) {
|
|
595
|
+
msg = msg.replace(new RegExp(`\\{${k}\\}`, "g"), String(v));
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return msg;
|
|
599
|
+
}
|
|
600
|
+
|
|
164
601
|
// src/commands/hatch.ts
|
|
165
602
|
function rollRarity() {
|
|
166
603
|
const roll = Math.random() * 100;
|
|
@@ -192,9 +629,8 @@ function randomName() {
|
|
|
192
629
|
async function hatch(name) {
|
|
193
630
|
const existing = await readLobster();
|
|
194
631
|
if (existing) {
|
|
195
|
-
console.log(
|
|
196
|
-
|
|
197
|
-
console.log("\u4E00\u4EBA\u4E00\u867E\uFF0C\u4E0D\u53EF\u66FF\u4EE3\u3002");
|
|
632
|
+
console.log("\n" + t("hatch_exists", { name: existing.name, level: existing.level }));
|
|
633
|
+
console.log(t("hatch_one_only"));
|
|
198
634
|
return;
|
|
199
635
|
}
|
|
200
636
|
const lobsterName = name || randomName();
|
|
@@ -223,32 +659,222 @@ async function hatch(name) {
|
|
|
223
659
|
last_patrol: "",
|
|
224
660
|
last_battle: "",
|
|
225
661
|
today_exp: 0,
|
|
226
|
-
daily_exp_cap: 100
|
|
662
|
+
daily_exp_cap: 100,
|
|
663
|
+
equipped: {},
|
|
664
|
+
inventory: [],
|
|
665
|
+
depth: 0,
|
|
666
|
+
achievements: [],
|
|
667
|
+
dungeon_maps: [],
|
|
668
|
+
dungeons_completed: 0,
|
|
669
|
+
boss_kills: 0,
|
|
670
|
+
dungeon_epics_found: 0
|
|
227
671
|
};
|
|
228
672
|
await writeLobster(lobster);
|
|
229
673
|
const soulMd = buildSoulMarkdown(lobsterName, soul, rarity, "coastal");
|
|
230
674
|
await writeSoul(soulMd);
|
|
231
|
-
await appendLog(`\u{1F95A} **${lobsterName}**
|
|
675
|
+
await appendLog(`\u{1F95A} **${lobsterName}** hatched! Rarity: ${RARITY_LABELS[rarity]}`);
|
|
232
676
|
console.log("\n" + "=".repeat(50));
|
|
233
|
-
console.log("
|
|
677
|
+
console.log(t("hatch_success"));
|
|
234
678
|
console.log("=".repeat(50));
|
|
235
679
|
console.log();
|
|
236
|
-
console.log(`
|
|
237
|
-
console.log(`
|
|
238
|
-
console.log(
|
|
239
|
-
console.log(
|
|
680
|
+
console.log(` ${lobsterName}`);
|
|
681
|
+
console.log(` ${RARITY_LABELS[rarity]} (${rarity})`);
|
|
682
|
+
console.log(" Lv.1");
|
|
683
|
+
console.log(t("hatch_env"));
|
|
240
684
|
console.log();
|
|
241
685
|
console.log(` \u2764\uFE0F HP: ${stats.hp} \u2694\uFE0F ATK: ${stats.attack} \u{1F6E1}\uFE0F DEF: ${stats.defense}`);
|
|
242
686
|
console.log(` \u{1F4A8} SPD: ${stats.speed} \u{1F441}\uFE0F INT: ${stats.intimidation} \u{1F340} LCK: ${stats.luck}`);
|
|
243
687
|
console.log();
|
|
244
|
-
console.log(` \u6027\u683C:`);
|
|
245
|
-
console.log(` \u52C7\u6C14 ${soul.bravery}/10 | \u597D\u5947 ${soul.curiosity}/10 | \u8BDD\u91CF ${soul.talkativeness}/10 | \u813E\u6C14 ${soul.temper}/10`);
|
|
246
|
-
console.log();
|
|
247
688
|
console.log(` ID: ${lobster.id}`);
|
|
248
689
|
console.log("=".repeat(50));
|
|
249
690
|
console.log();
|
|
250
|
-
console.log("
|
|
251
|
-
console.log("
|
|
691
|
+
console.log(t("hatch_ready"));
|
|
692
|
+
console.log(t("hatch_next"));
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// src/lib/equipment.ts
|
|
696
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
697
|
+
var SLOT_STATS = {
|
|
698
|
+
claw: ["attack", "speed"],
|
|
699
|
+
shell: ["hp", "defense"],
|
|
700
|
+
charm: ["luck", "intimidation"]
|
|
701
|
+
};
|
|
702
|
+
var NAMES = {
|
|
703
|
+
claw: {
|
|
704
|
+
common: ["\u94C1\u94B3\u5957", "\u77F3\u523A\u94B3", "\u78E8\u7259\u5957"],
|
|
705
|
+
rare: ["\u73CA\u745A\u523A\u94B3", "\u9CA8\u9F7F\u5957", "\u950B\u5203\u94B3"],
|
|
706
|
+
epic: ["\u6DF1\u6D77\u952F\u9F7F", "\u96F7\u9706\u4E4B\u94B3", "\u9F99\u9AA8\u94B3"],
|
|
707
|
+
legendary: ["\u6BC1\u706D\u4E4B\u94B3", "\u6D77\u795E\u4E4B\u63E1", "\u6DF7\u6C8C\u88C2\u722A"]
|
|
708
|
+
},
|
|
709
|
+
shell: {
|
|
710
|
+
common: ["\u77F3\u7532\u58F3", "\u786C\u76AE\u7532", "\u6CE5\u6C99\u76FE"],
|
|
711
|
+
rare: ["\u73CA\u745A\u94E0", "\u6D77\u85FB\u7EC7\u7532", "\u8D1D\u58F3\u76FE"],
|
|
712
|
+
epic: ["\u73CD\u73E0\u9F99\u94E0", "\u6DF1\u6E0A\u58F3\u7532", "\u51B0\u6676\u7532"],
|
|
713
|
+
legendary: ["\u4E0D\u706D\u7532\u58F3", "\u6D77\u795E\u4E4B\u94E0", "\u8679\u5149\u94E0"]
|
|
714
|
+
},
|
|
715
|
+
charm: {
|
|
716
|
+
common: ["\u5C0F\u6D77\u661F", "\u788E\u8D1D\u58F3", "\u6D77\u8349\u7ED3"],
|
|
717
|
+
rare: ["\u9CA8\u7259\u94FE", "\u73CA\u745A\u5760", "\u6F6E\u6C50\u73E0"],
|
|
718
|
+
epic: ["\u6DF1\u6D77\u4E4B\u773C", "\u96F7\u66B4\u6838", "\u5E7B\u6D77\u73E0"],
|
|
719
|
+
legendary: ["\u6D77\u795E\u4E4B\u5FC3", "\u547D\u8FD0\u4E4B\u73E0", "\u6DF7\u6C8C\u4E4B\u773C"]
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
var RARITY_MUL = { common: 1, rare: 2, epic: 3, legendary: 5 };
|
|
723
|
+
var RARITY_DUR = { common: 8, rare: 12, epic: 18, legendary: 30 };
|
|
724
|
+
var RARITY_POWER = { common: 1, rare: 1.5, epic: 2, legendary: 3 };
|
|
725
|
+
function pick(arr) {
|
|
726
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
727
|
+
}
|
|
728
|
+
function rollRarity2(depth, soul) {
|
|
729
|
+
const w = { ...EQUIP_RARITY_WEIGHTS };
|
|
730
|
+
w.rare += depth * 3;
|
|
731
|
+
w.epic += depth * 1.5;
|
|
732
|
+
w.legendary += depth * 0.5;
|
|
733
|
+
if (soul.talkativeness <= 3) {
|
|
734
|
+
w.rare += 5;
|
|
735
|
+
w.epic += 3;
|
|
736
|
+
w.legendary += 1;
|
|
737
|
+
}
|
|
738
|
+
const total = Object.values(w).reduce((a, b) => a + b, 0);
|
|
739
|
+
let roll = Math.random() * total;
|
|
740
|
+
for (const [r, weight] of Object.entries(w)) {
|
|
741
|
+
roll -= weight;
|
|
742
|
+
if (roll <= 0) return r;
|
|
743
|
+
}
|
|
744
|
+
return "common";
|
|
745
|
+
}
|
|
746
|
+
function rollLevel(depth, soul) {
|
|
747
|
+
let lv = Math.floor(depth / 3) + 1;
|
|
748
|
+
if (soul.curiosity >= 7) lv++;
|
|
749
|
+
return Math.min(5, Math.max(1, lv));
|
|
750
|
+
}
|
|
751
|
+
function generateEquipment(depth, soul) {
|
|
752
|
+
const slot = pick(["claw", "shell", "charm"]);
|
|
753
|
+
const rarity = rollRarity2(depth, soul);
|
|
754
|
+
const level = rollLevel(depth, soul);
|
|
755
|
+
const mul = RARITY_MUL[rarity];
|
|
756
|
+
const levelMul = 1 + (level - 1) * 0.3;
|
|
757
|
+
const keys = SLOT_STATS[slot];
|
|
758
|
+
let dur = RARITY_DUR[rarity];
|
|
759
|
+
if (soul.bravery <= 3) dur += 2;
|
|
760
|
+
const bonuses = {};
|
|
761
|
+
for (const k of keys) {
|
|
762
|
+
bonuses[k] = Math.ceil(Math.random() * 2 * mul * levelMul);
|
|
763
|
+
}
|
|
764
|
+
const allStats = ["hp", "attack", "defense", "speed", "intimidation", "luck"];
|
|
765
|
+
if (Math.random() < 0.2 * mul) {
|
|
766
|
+
const extra = allStats.filter((s) => !keys.includes(s));
|
|
767
|
+
if (extra.length) bonuses[pick(extra)] = Math.ceil(Math.random() * mul * levelMul);
|
|
768
|
+
}
|
|
769
|
+
return {
|
|
770
|
+
id: randomUUID2().slice(0, 8),
|
|
771
|
+
name: pick(NAMES[slot][rarity]),
|
|
772
|
+
slot,
|
|
773
|
+
rarity,
|
|
774
|
+
level,
|
|
775
|
+
bonuses,
|
|
776
|
+
durability: dur,
|
|
777
|
+
max_durability: dur
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
function powerScore(e) {
|
|
781
|
+
const sum = Object.values(e.bonuses).reduce((a, b) => a + (b ?? 0), 0);
|
|
782
|
+
const lv = e.level ?? 1;
|
|
783
|
+
return sum * RARITY_POWER[e.rarity] * lv * (e.durability / e.max_durability);
|
|
784
|
+
}
|
|
785
|
+
function shouldDrop(depth, soul) {
|
|
786
|
+
let chance = Math.min(0.8, 0.25 + depth * 0.05);
|
|
787
|
+
if (soul.bravery >= 7) chance += 0.1;
|
|
788
|
+
if (soul.bravery <= 3) chance -= 0.1;
|
|
789
|
+
return Math.random() < Math.max(0.05, chance);
|
|
790
|
+
}
|
|
791
|
+
function depthPenalty(soul) {
|
|
792
|
+
if (soul.temper >= 7) return 3;
|
|
793
|
+
if (soul.bravery >= 7) return 1;
|
|
794
|
+
return 2;
|
|
795
|
+
}
|
|
796
|
+
function winExpMultiplier(soul) {
|
|
797
|
+
if (soul.temper >= 7) return 1.2;
|
|
798
|
+
return 1;
|
|
799
|
+
}
|
|
800
|
+
function autoManageLoot(lobster, loot) {
|
|
801
|
+
const actions = [];
|
|
802
|
+
if (!lobster.equipped) lobster.equipped = {};
|
|
803
|
+
if (!lobster.inventory) lobster.inventory = [];
|
|
804
|
+
const current = lobster.equipped[loot.slot];
|
|
805
|
+
const lootPower = powerScore(loot);
|
|
806
|
+
if (!current) {
|
|
807
|
+
lobster.equipped[loot.slot] = loot;
|
|
808
|
+
actions.push({ type: "auto_equip", item: loot, reason: slotReason(lobster.soul, loot.slot) });
|
|
809
|
+
return actions;
|
|
810
|
+
}
|
|
811
|
+
const currentPower = powerScore(current);
|
|
812
|
+
if (lootPower > currentPower) {
|
|
813
|
+
lobster.equipped[loot.slot] = loot;
|
|
814
|
+
if (lobster.inventory.length < MAX_INVENTORY) {
|
|
815
|
+
lobster.inventory.push(current);
|
|
816
|
+
}
|
|
817
|
+
actions.push({ type: "auto_swap", item: loot, old: current, reason: slotReason(lobster.soul, loot.slot) });
|
|
818
|
+
return actions;
|
|
819
|
+
}
|
|
820
|
+
if (lobster.inventory.length < MAX_INVENTORY) {
|
|
821
|
+
lobster.inventory.push(loot);
|
|
822
|
+
return actions;
|
|
823
|
+
}
|
|
824
|
+
let worstIdx = -1;
|
|
825
|
+
let worstScore = Infinity;
|
|
826
|
+
for (let i = 0; i < lobster.inventory.length; i++) {
|
|
827
|
+
const s = powerScore(lobster.inventory[i]);
|
|
828
|
+
if (s < worstScore) {
|
|
829
|
+
worstScore = s;
|
|
830
|
+
worstIdx = i;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
if (worstIdx >= 0 && lootPower > worstScore) {
|
|
834
|
+
const discarded = lobster.inventory[worstIdx];
|
|
835
|
+
lobster.inventory[worstIdx] = loot;
|
|
836
|
+
actions.push({ type: "auto_discard", item: discarded, reason: "\u54C1\u8D28\u4E0D\u8DB3" });
|
|
837
|
+
} else {
|
|
838
|
+
actions.push({ type: "auto_discard", item: loot, reason: "\u54C1\u8D28\u4E0D\u8DB3" });
|
|
839
|
+
}
|
|
840
|
+
return actions;
|
|
841
|
+
}
|
|
842
|
+
function slotReason(soul, slot) {
|
|
843
|
+
if (slot === "claw" && soul.bravery >= 7) return "\u52C7\u731B\u672C\u80FD";
|
|
844
|
+
if (slot === "claw" && soul.temper >= 7) return "\u66B4\u8E81\u5929\u6027";
|
|
845
|
+
if (slot === "shell" && soul.bravery <= 3) return "\u8C28\u614E\u76F4\u89C9";
|
|
846
|
+
if (slot === "charm" && soul.curiosity >= 7) return "\u597D\u5947\u5FC3\u9A71\u4F7F";
|
|
847
|
+
return "\u81EA\u884C\u5224\u65AD";
|
|
848
|
+
}
|
|
849
|
+
function getEffectiveStats(lobster) {
|
|
850
|
+
const s = { ...lobster.stats };
|
|
851
|
+
if (!lobster.equipped) return s;
|
|
852
|
+
for (const eq of Object.values(lobster.equipped)) {
|
|
853
|
+
if (!eq || eq.durability <= 0) continue;
|
|
854
|
+
for (const [k, v] of Object.entries(eq.bonuses)) {
|
|
855
|
+
s[k] += v;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return s;
|
|
859
|
+
}
|
|
860
|
+
function degradeEquipment(lobster) {
|
|
861
|
+
const broken = [];
|
|
862
|
+
if (!lobster.equipped) return broken;
|
|
863
|
+
for (const [slot, eq] of Object.entries(lobster.equipped)) {
|
|
864
|
+
if (!eq) continue;
|
|
865
|
+
eq.durability--;
|
|
866
|
+
if (eq.durability <= 0) {
|
|
867
|
+
broken.push(eq.name);
|
|
868
|
+
delete lobster.equipped[slot];
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return broken;
|
|
872
|
+
}
|
|
873
|
+
function formatEquip(e) {
|
|
874
|
+
const lv = (e.level ?? 1) > 1 ? `+${e.level}` : "";
|
|
875
|
+
const label = EQUIP_RARITY_LABELS[e.rarity] || e.rarity;
|
|
876
|
+
const b = Object.entries(e.bonuses).map(([k, v]) => `${k}+${v}`).join(" ");
|
|
877
|
+
return `[${label}${lv}] ${e.name} ${b} (${e.durability}/${e.max_durability})`;
|
|
252
878
|
}
|
|
253
879
|
|
|
254
880
|
// src/commands/status.ts
|
|
@@ -259,12 +885,13 @@ function bar(current, max, width = 20) {
|
|
|
259
885
|
async function status() {
|
|
260
886
|
const lobster = await readLobster();
|
|
261
887
|
if (!lobster) {
|
|
262
|
-
console.log("\n
|
|
888
|
+
console.log("\n" + t("no_lobster"));
|
|
263
889
|
return;
|
|
264
890
|
}
|
|
265
891
|
const totalBattles = lobster.wins + lobster.losses;
|
|
266
892
|
const winRate = totalBattles > 0 ? Math.round(lobster.wins / totalBattles * 100) : 0;
|
|
267
893
|
const expPct = lobster.exp_to_next > 0 ? Math.round(lobster.exp / lobster.exp_to_next * 100) : 0;
|
|
894
|
+
const eff = getEffectiveStats(lobster);
|
|
268
895
|
const statusEmoji = {
|
|
269
896
|
active: "\u{1F7E2} \u6D3B\u8DC3",
|
|
270
897
|
molting: "\u{1F7E1} \u8715\u58F3\u4E2D",
|
|
@@ -275,28 +902,62 @@ async function status() {
|
|
|
275
902
|
console.log("\u251C" + "\u2500".repeat(44) + "\u2524");
|
|
276
903
|
console.log(`\u2502 \u7B49\u7EA7: Lv.${String(lobster.level).padEnd(5)} \u7A00\u6709\u5EA6: ${(RARITY_LABELS[lobster.rarity] || lobster.rarity).padEnd(15)}\u2502`);
|
|
277
904
|
console.log(`\u2502 \u72B6\u6001: ${(statusEmoji[lobster.status] || lobster.status).padEnd(36)}\u2502`);
|
|
278
|
-
console.log(`\u2502 \u73AF\u5883: ${lobster.environment.padEnd(
|
|
905
|
+
console.log(`\u2502 \u73AF\u5883: ${lobster.environment.padEnd(20)} \u6DF1\u5EA6: ${String(lobster.depth ?? 0).padEnd(13)}\u2502`);
|
|
279
906
|
console.log("\u251C" + "\u2500".repeat(44) + "\u2524");
|
|
280
907
|
console.log(`\u2502 EXP: ${bar(lobster.exp, lobster.exp_to_next)} ${String(expPct).padStart(3)}% \u2502`);
|
|
281
908
|
console.log(`\u2502 ${String(lobster.exp).padStart(5)} / ${String(lobster.exp_to_next).padEnd(28)}\u2502`);
|
|
282
909
|
console.log("\u251C" + "\u2500".repeat(44) + "\u2524");
|
|
283
|
-
console.log(`\u2502 \u2764\uFE0F HP: ${String(
|
|
284
|
-
console.log(`\u2502 \u{1F6E1}\uFE0F DEF: ${String(
|
|
285
|
-
console.log(`\u2502 \u{1F441}\uFE0F INT: ${String(
|
|
910
|
+
console.log(`\u2502 \u2764\uFE0F HP: ${String(eff.hp).padEnd(6)} \u2694\uFE0F ATK: ${String(eff.attack).padEnd(15)}\u2502`);
|
|
911
|
+
console.log(`\u2502 \u{1F6E1}\uFE0F DEF: ${String(eff.defense).padEnd(6)} \u{1F4A8} SPD: ${String(eff.speed).padEnd(15)}\u2502`);
|
|
912
|
+
console.log(`\u2502 \u{1F441}\uFE0F INT: ${String(eff.intimidation).padEnd(6)} \u{1F340} LCK: ${String(eff.luck).padEnd(15)}\u2502`);
|
|
286
913
|
console.log("\u251C" + "\u2500".repeat(44) + "\u2524");
|
|
287
914
|
console.log(`\u2502 \u6218\u7EE9: ${lobster.wins}\u80DC ${lobster.losses}\u8D1F (\u80DC\u7387${winRate}%)${" ".repeat(Math.max(0, 20 - String(lobster.wins).length - String(lobster.losses).length - String(winRate).length))}\u2502`);
|
|
288
915
|
console.log(`\u2502 \u8FDE\u80DC: ${lobster.streak} \u58F0\u671B: ${lobster.reputation} \u5DE1\u903B: ${lobster.patrol_count}${" ".repeat(Math.max(0, 15 - String(lobster.streak).length - String(lobster.reputation).length - String(lobster.patrol_count).length))}\u2502`);
|
|
916
|
+
const slots = ["claw", "shell", "charm"];
|
|
917
|
+
const hasEquip = slots.some((s) => lobster.equipped?.[s]);
|
|
918
|
+
if (hasEquip) {
|
|
919
|
+
console.log("\u251C" + "\u2500".repeat(44) + "\u2524");
|
|
920
|
+
for (const s of slots) {
|
|
921
|
+
const eq = lobster.equipped?.[s];
|
|
922
|
+
const label = `${SLOT_ICONS[s]} ${SLOT_LABELS[s]}`;
|
|
923
|
+
const lv = eq && (eq.level ?? 1) > 1 ? `+${eq.level}` : "";
|
|
924
|
+
const info = eq ? `${eq.name}${lv}(${eq.durability}/${eq.max_durability})` : "-";
|
|
925
|
+
console.log(`\u2502 ${label}: ${info.padEnd(36)}\u2502`);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
const invCount = lobster.inventory?.length ?? 0;
|
|
929
|
+
if (invCount > 0) {
|
|
930
|
+
console.log(`\u2502 \u{1F4E6} \u80CC\u5305: ${invCount}/${MAX_INVENTORY}${" ".repeat(31 - String(invCount).length - String(MAX_INVENTORY).length)}\u2502`);
|
|
931
|
+
}
|
|
289
932
|
console.log("\u251C" + "\u2500".repeat(44) + "\u2524");
|
|
290
933
|
console.log(`\u2502 \u6027\u683C: \u2502`);
|
|
291
934
|
console.log(`\u2502 \u52C7\u6C14 ${lobster.soul.bravery}/10 | \u597D\u5947 ${lobster.soul.curiosity}/10 | \u8BDD\u91CF ${lobster.soul.talkativeness}/10 | \u813E\u6C14 ${lobster.soul.temper}/10 \u2502`);
|
|
935
|
+
const mapCount = lobster.dungeon_maps?.length ?? 0;
|
|
936
|
+
const dgCompleted = lobster.dungeons_completed ?? 0;
|
|
937
|
+
if (mapCount > 0 || dgCompleted > 0) {
|
|
938
|
+
console.log(`\u2502 \u{1F3F0} \u5730\u4E0B\u57CE: ${dgCompleted}\u901A\u5173 \u{1F5FA}\uFE0F \u5730\u56FE: ${mapCount}${" ".repeat(Math.max(0, 19 - String(dgCompleted).length - String(mapCount).length))}\u2502`);
|
|
939
|
+
}
|
|
940
|
+
if (lobster.active_dungeon) {
|
|
941
|
+
console.log(`\u2502 \u26A1 \u8FDB\u884C\u4E2D\u5730\u4E0B\u57CE: \u6709${" ".repeat(24)}\u2502`);
|
|
942
|
+
}
|
|
943
|
+
const achieveCount = lobster.achievements?.length ?? 0;
|
|
944
|
+
if (achieveCount > 0) {
|
|
945
|
+
console.log(`\u2502 \u{1F3C6} \u6210\u5C31: ${achieveCount}${" ".repeat(33 - String(achieveCount).length)}\u2502`);
|
|
946
|
+
}
|
|
292
947
|
console.log("\u2514" + "\u2500".repeat(44) + "\u2518");
|
|
948
|
+
console.log("\n" + t("status_battle_code", { code: lobster.id.slice(0, 8) }));
|
|
949
|
+
const soulText = await readSoul();
|
|
950
|
+
if (soulText) {
|
|
951
|
+
const firstLine = soulText.split("\n").find((l) => l.trim() && !l.startsWith("#"));
|
|
952
|
+
if (firstLine) console.log(`\u{1F4DC} \u7075\u9B42: ${firstLine.trim().slice(0, 60)}`);
|
|
953
|
+
}
|
|
293
954
|
}
|
|
294
955
|
|
|
295
956
|
// src/lib/api.ts
|
|
296
957
|
import { createHash } from "crypto";
|
|
297
958
|
var API_BASE = "https://api.clawfight.online";
|
|
298
959
|
function statsHash(lobster) {
|
|
299
|
-
const raw = JSON.stringify(lobster
|
|
960
|
+
const raw = JSON.stringify(getEffectiveStats(lobster));
|
|
300
961
|
return createHash("sha256").update(raw).digest("hex");
|
|
301
962
|
}
|
|
302
963
|
function getProxyUrl() {
|
|
@@ -331,14 +992,11 @@ async function apiPatrol(lobster) {
|
|
|
331
992
|
lobster_id: lobster.id,
|
|
332
993
|
level: lobster.level,
|
|
333
994
|
stats_hash: statsHash(lobster),
|
|
995
|
+
stats: getEffectiveStats(lobster),
|
|
334
996
|
environment: lobster.environment,
|
|
335
997
|
name: lobster.name,
|
|
336
998
|
color: lobster.rarity,
|
|
337
999
|
rarity: lobster.rarity,
|
|
338
|
-
wins: lobster.wins,
|
|
339
|
-
losses: lobster.losses,
|
|
340
|
-
streak: lobster.streak,
|
|
341
|
-
reputation: lobster.reputation,
|
|
342
1000
|
is_molting: lobster.status === "molting",
|
|
343
1001
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
344
1002
|
}),
|
|
@@ -350,6 +1008,27 @@ async function apiPatrol(lobster) {
|
|
|
350
1008
|
return null;
|
|
351
1009
|
}
|
|
352
1010
|
}
|
|
1011
|
+
async function apiBattle(challengerId, opponentCode) {
|
|
1012
|
+
try {
|
|
1013
|
+
const pfetch = await getProxiedFetch();
|
|
1014
|
+
const res = await pfetch(`${API_BASE}/api/battle`, {
|
|
1015
|
+
method: "POST",
|
|
1016
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
1017
|
+
body: JSON.stringify({
|
|
1018
|
+
challenger_id: challengerId,
|
|
1019
|
+
opponent_code: opponentCode
|
|
1020
|
+
}),
|
|
1021
|
+
signal: AbortSignal.timeout(1e4)
|
|
1022
|
+
});
|
|
1023
|
+
if (!res.ok) {
|
|
1024
|
+
const err = await res.json();
|
|
1025
|
+
return { error: err.error || "Unknown error" };
|
|
1026
|
+
}
|
|
1027
|
+
return await res.json();
|
|
1028
|
+
} catch {
|
|
1029
|
+
return null;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
353
1032
|
async function apiLeaderboard(limit = 20) {
|
|
354
1033
|
try {
|
|
355
1034
|
const pfetch = await getProxiedFetch();
|
|
@@ -362,6 +1041,74 @@ async function apiLeaderboard(limit = 20) {
|
|
|
362
1041
|
return null;
|
|
363
1042
|
}
|
|
364
1043
|
}
|
|
1044
|
+
async function apiDungeonEnter(lobster, theme) {
|
|
1045
|
+
try {
|
|
1046
|
+
const pfetch = await getProxiedFetch();
|
|
1047
|
+
const res = await pfetch(`${API_BASE}/api/dungeon/enter`, {
|
|
1048
|
+
method: "POST",
|
|
1049
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
1050
|
+
body: JSON.stringify({
|
|
1051
|
+
lobster_id: lobster.id,
|
|
1052
|
+
level: lobster.level,
|
|
1053
|
+
stats: getEffectiveStats(lobster),
|
|
1054
|
+
soul: lobster.soul,
|
|
1055
|
+
depth: lobster.depth ?? 0,
|
|
1056
|
+
environment: lobster.environment,
|
|
1057
|
+
theme
|
|
1058
|
+
}),
|
|
1059
|
+
signal: AbortSignal.timeout(1e4)
|
|
1060
|
+
});
|
|
1061
|
+
if (!res.ok) {
|
|
1062
|
+
const err = await res.json();
|
|
1063
|
+
return { error: err.error };
|
|
1064
|
+
}
|
|
1065
|
+
return await res.json();
|
|
1066
|
+
} catch {
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
async function apiDungeonAct(dungeonId, lobsterId, choice) {
|
|
1071
|
+
try {
|
|
1072
|
+
const pfetch = await getProxiedFetch();
|
|
1073
|
+
const res = await pfetch(`${API_BASE}/api/dungeon/act`, {
|
|
1074
|
+
method: "POST",
|
|
1075
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
1076
|
+
body: JSON.stringify({ dungeon_id: dungeonId, lobster_id: lobsterId, choice }),
|
|
1077
|
+
signal: AbortSignal.timeout(1e4)
|
|
1078
|
+
});
|
|
1079
|
+
if (!res.ok) return null;
|
|
1080
|
+
return await res.json();
|
|
1081
|
+
} catch {
|
|
1082
|
+
return null;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
async function apiDungeonState(lobsterId) {
|
|
1086
|
+
try {
|
|
1087
|
+
const pfetch = await getProxiedFetch();
|
|
1088
|
+
const res = await pfetch(`${API_BASE}/api/dungeon/state?lobster_id=${lobsterId}`, {
|
|
1089
|
+
signal: AbortSignal.timeout(1e4)
|
|
1090
|
+
});
|
|
1091
|
+
if (!res.ok) return null;
|
|
1092
|
+
return await res.json();
|
|
1093
|
+
} catch {
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
async function apiDungeonAbandon(lobsterId) {
|
|
1098
|
+
try {
|
|
1099
|
+
const pfetch = await getProxiedFetch();
|
|
1100
|
+
const res = await pfetch(`${API_BASE}/api/dungeon/abandon`, {
|
|
1101
|
+
method: "POST",
|
|
1102
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
1103
|
+
body: JSON.stringify({ lobster_id: lobsterId }),
|
|
1104
|
+
signal: AbortSignal.timeout(1e4)
|
|
1105
|
+
});
|
|
1106
|
+
if (!res.ok) return null;
|
|
1107
|
+
return await res.json();
|
|
1108
|
+
} catch {
|
|
1109
|
+
return null;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
365
1112
|
|
|
366
1113
|
// src/lib/events.ts
|
|
367
1114
|
import { readFile as readFile2 } from "fs/promises";
|
|
@@ -401,11 +1148,11 @@ async function rollEvent(lobster) {
|
|
|
401
1148
|
});
|
|
402
1149
|
if (candidates.length === 0) return null;
|
|
403
1150
|
const totalWeight = candidates.reduce((s, c) => s + c.probability, 0);
|
|
404
|
-
let
|
|
1151
|
+
let pick2 = Math.random() * totalWeight;
|
|
405
1152
|
let chosen = null;
|
|
406
1153
|
for (const c of candidates) {
|
|
407
|
-
|
|
408
|
-
if (
|
|
1154
|
+
pick2 -= c.probability;
|
|
1155
|
+
if (pick2 <= 0) {
|
|
409
1156
|
chosen = c;
|
|
410
1157
|
break;
|
|
411
1158
|
}
|
|
@@ -436,69 +1183,208 @@ function applyEventEffects(lobster, effects) {
|
|
|
436
1183
|
return changes;
|
|
437
1184
|
}
|
|
438
1185
|
|
|
1186
|
+
// src/lib/achievements.ts
|
|
1187
|
+
var ACHIEVEMENTS = {
|
|
1188
|
+
first_blood: { name: "\u521D\u6218\u544A\u6377", desc: "\u8D62\u5F97\u9996\u80DC", check: (l) => l.wins >= 1 },
|
|
1189
|
+
veteran: { name: "\u6C99\u573A\u8001\u5175", desc: "10\u80DC", check: (l) => l.wins >= 10 },
|
|
1190
|
+
warlord: { name: "\u6DF1\u6D77\u6218\u795E", desc: "50\u80DC", check: (l) => l.wins >= 50 },
|
|
1191
|
+
explorer: { name: "\u6D77\u57DF\u63A2\u7D22\u8005", desc: "20\u6B21\u5DE1\u903B", check: (l) => l.patrol_count >= 20 },
|
|
1192
|
+
deep_diver: { name: "\u6DF1\u6F5C\u8005", desc: "\u6DF1\u5EA65", check: (l) => (l.depth ?? 0) >= 5 },
|
|
1193
|
+
abyss_walker: { name: "\u6DF1\u6E0A\u884C\u8005", desc: "\u6DF1\u5EA610", check: (l) => (l.depth ?? 0) >= 10 },
|
|
1194
|
+
fully_armed: { name: "\u5168\u526F\u6B66\u88C5", desc: "\u88C5\u5907\u6EE13\u69FD", check: (l) => {
|
|
1195
|
+
if (!l.equipped) return false;
|
|
1196
|
+
return !!(l.equipped.claw && l.equipped.shell && l.equipped.charm);
|
|
1197
|
+
} },
|
|
1198
|
+
survivor: { name: "\u767E\u6298\u4E0D\u6320", desc: "\u7D2F\u8BA110\u8D1F\u540E\u4ECD\u5728\u6218\u6597", check: (l) => l.losses >= 10 && l.wins > 0 },
|
|
1199
|
+
streak_5: { name: "\u52BF\u4E0D\u53EF\u6321", desc: "5\u8FDE\u80DC", check: (l) => l.streak >= 5 },
|
|
1200
|
+
streak_10: { name: "\u65E0\u4EBA\u80FD\u654C", desc: "10\u8FDE\u80DC", check: (l) => l.streak >= 10 },
|
|
1201
|
+
high_level: { name: "\u738B\u8005\u9F99\u867E", desc: "\u8FBE\u523010\u7EA7", check: (l) => l.level >= 10 },
|
|
1202
|
+
molt_master: { name: "\u8715\u53D8\u5927\u5E08", desc: "\u8715\u58F33\u6B21", check: (l) => l.molt_count >= 3 },
|
|
1203
|
+
first_dungeon: { name: "\u521D\u63A2\u5730\u4E0B\u57CE", desc: "\u5B8C\u6210\u9996\u4E2A\u5730\u4E0B\u57CE", check: (l) => (l.dungeons_completed ?? 0) >= 1 },
|
|
1204
|
+
dungeon_master: { name: "\u5730\u4E0B\u57CE\u4E4B\u738B", desc: "\u5B8C\u621010\u4E2A\u5730\u4E0B\u57CE", check: (l) => (l.dungeons_completed ?? 0) >= 10 },
|
|
1205
|
+
boss_slayer: { name: "Boss\u730E\u624B", desc: "\u51FB\u8D25\u5730\u4E0B\u57CEBoss", check: (l) => (l.boss_kills ?? 0) >= 1 },
|
|
1206
|
+
perfect_run: { name: "\u5B8C\u7F8E\u901A\u5173", desc: "\u6EE1HP\u901A\u5173\u5730\u4E0B\u57CE", check: () => false },
|
|
1207
|
+
treasure_hunter: { name: "\u5BFB\u5B9D\u730E\u4EBA", desc: "\u5728\u5730\u4E0B\u57CE\u83B7\u5F975\u4EF6\u53F2\u8BD7+\u88C5\u5907", check: (l) => (l.dungeon_epics_found ?? 0) >= 5 }
|
|
1208
|
+
};
|
|
1209
|
+
function checkAchievements(lobster) {
|
|
1210
|
+
const unlocked = [];
|
|
1211
|
+
const existing = new Set(lobster.achievements ?? []);
|
|
1212
|
+
for (const [id, def] of Object.entries(ACHIEVEMENTS)) {
|
|
1213
|
+
if (existing.has(id)) continue;
|
|
1214
|
+
if (def.check(lobster)) {
|
|
1215
|
+
unlocked.push(id);
|
|
1216
|
+
if (!lobster.achievements) lobster.achievements = [];
|
|
1217
|
+
lobster.achievements.push(id);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
return unlocked;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
439
1223
|
// src/commands/patrol.ts
|
|
440
1224
|
var PATROL_EXP = 15;
|
|
441
1225
|
async function patrol() {
|
|
442
1226
|
const lobster = await readLobster();
|
|
443
1227
|
if (!lobster) {
|
|
444
|
-
console.log("\n
|
|
1228
|
+
console.log("\n" + t("no_lobster"));
|
|
445
1229
|
return;
|
|
446
1230
|
}
|
|
447
1231
|
if (lobster.status === "molting") {
|
|
448
|
-
console.log(
|
|
449
|
-
\u{1F7E1} ${lobster.name} \u6B63\u5728\u8715\u58F3\u4E2D\uFF0C\u65E0\u6CD5\u5DE1\u903B\u3002`);
|
|
1232
|
+
console.log("\n" + t("status_cant_patrol_molt", { name: lobster.name }));
|
|
450
1233
|
return;
|
|
451
1234
|
}
|
|
452
1235
|
if (lobster.status === "hibernating") {
|
|
453
|
-
console.log(
|
|
454
|
-
\u{1F4A4} ${lobster.name} \u6B63\u5728\u51AC\u7720\u4E2D\uFF0C\u65E0\u6CD5\u5DE1\u903B\u3002`);
|
|
1236
|
+
console.log("\n" + t("status_cant_patrol_hibernate", { name: lobster.name }));
|
|
455
1237
|
return;
|
|
456
1238
|
}
|
|
457
1239
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
458
1240
|
const lastDay = lobster.last_patrol ? lobster.last_patrol.split("T")[0] : "";
|
|
459
|
-
if (today !== lastDay)
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
\
|
|
1241
|
+
if (today !== lastDay) lobster.today_exp = 0;
|
|
1242
|
+
const depth = lobster.depth ?? 0;
|
|
1243
|
+
const soul = lobster.soul;
|
|
1244
|
+
const trait = soulTag(soul);
|
|
1245
|
+
console.log("\n" + t("patrol_start", { name: lobster.name }) + ` [${t("depth_display", { depth })}]`);
|
|
1246
|
+
if (trait) console.log(t("soul_trait", { trait }));
|
|
464
1247
|
console.log("\u2500".repeat(40));
|
|
465
1248
|
const expGain = Math.min(PATROL_EXP, lobster.daily_exp_cap - lobster.today_exp);
|
|
466
1249
|
if (expGain > 0) {
|
|
467
1250
|
lobster.exp += expGain;
|
|
468
1251
|
lobster.today_exp += expGain;
|
|
469
|
-
console.log(
|
|
1252
|
+
console.log(t("patrol_checkin", { exp: expGain }));
|
|
470
1253
|
}
|
|
471
1254
|
const eventResult = await rollEvent(lobster);
|
|
472
1255
|
if (eventResult) {
|
|
473
1256
|
console.log();
|
|
474
|
-
console.log(
|
|
1257
|
+
console.log(t("event_prefix", { category: eventResult.event.category, id: eventResult.event.id }));
|
|
475
1258
|
console.log(` ${eventResult.narrative}`);
|
|
476
1259
|
const changes = applyEventEffects(lobster, eventResult.event.effects);
|
|
477
|
-
if (changes.length > 0) {
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
await appendLog(`\u{1F3B2} \u4E8B\u4EF6\u300C${eventResult.event.id}\u300D: ${eventResult.narrative.slice(0, 60)}...`);
|
|
1260
|
+
if (changes.length > 0) console.log(t("event_effects", { changes: changes.join(", ") }));
|
|
1261
|
+
await appendLog(`\u{1F3B2} ${eventResult.event.id}: ${eventResult.narrative.slice(0, 60)}...`);
|
|
481
1262
|
}
|
|
482
1263
|
checkLevelUp(lobster);
|
|
483
1264
|
lobster.patrol_count++;
|
|
484
1265
|
lobster.last_patrol = (/* @__PURE__ */ new Date()).toISOString();
|
|
485
|
-
console.log("\n
|
|
1266
|
+
console.log("\n" + t("patrol_connecting"));
|
|
486
1267
|
const serverResponse = await apiPatrol(lobster);
|
|
487
1268
|
if (serverResponse) {
|
|
488
|
-
if (serverResponse.
|
|
489
|
-
console.log(
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
1269
|
+
if (serverResponse.message === "patrol_cooldown") {
|
|
1270
|
+
console.log(t("patrol_cooldown"));
|
|
1271
|
+
} else if (serverResponse.encounter && serverResponse.opponent && serverResponse.battle_result) {
|
|
1272
|
+
const br = serverResponse.battle_result;
|
|
1273
|
+
const opp = serverResponse.opponent;
|
|
1274
|
+
console.log("\n" + t("patrol_encounter", { name: opp.name, level: opp.level }));
|
|
1275
|
+
console.log(t(`patrol_result_${br.result}`, { rounds: br.rounds }));
|
|
1276
|
+
if (br.result === "win") {
|
|
1277
|
+
lobster.wins++;
|
|
1278
|
+
lobster.streak = Math.max(0, lobster.streak) + 1;
|
|
1279
|
+
lobster.reputation++;
|
|
1280
|
+
} else if (br.result === "loss") {
|
|
1281
|
+
lobster.losses++;
|
|
1282
|
+
lobster.streak = Math.min(0, lobster.streak) - 1;
|
|
1283
|
+
lobster.reputation = Math.max(0, lobster.reputation - 1);
|
|
1284
|
+
const penalty = depthPenalty(soul);
|
|
1285
|
+
lobster.depth = Math.max(0, (lobster.depth ?? 0) - penalty);
|
|
1286
|
+
}
|
|
1287
|
+
let battleExp = br.exp_gain;
|
|
1288
|
+
if (br.result === "win") battleExp = Math.floor(battleExp * winExpMultiplier(soul));
|
|
1289
|
+
battleExp = Math.min(battleExp, lobster.daily_exp_cap - lobster.today_exp);
|
|
1290
|
+
if (battleExp > 0) {
|
|
1291
|
+
lobster.exp += battleExp;
|
|
1292
|
+
lobster.today_exp += battleExp;
|
|
1293
|
+
}
|
|
1294
|
+
lobster.last_battle = (/* @__PURE__ */ new Date()).toISOString();
|
|
1295
|
+
console.log(t("patrol_exp_stats", { exp: battleExp, wins: lobster.wins, losses: lobster.losses, streak: lobster.streak }));
|
|
1296
|
+
await appendLog(`\u2694\uFE0F VS ${opp.name}(Lv.${opp.level}) \u2192 ${br.result} (${br.rounds}R)`);
|
|
1297
|
+
const broken = degradeEquipment(lobster);
|
|
1298
|
+
if (broken.length) console.log(t("equip_broken", { items: broken.join(", ") }));
|
|
1299
|
+
checkLevelUp(lobster);
|
|
1300
|
+
} else if (serverResponse.encounter && serverResponse.opponent) {
|
|
1301
|
+
console.log(t("patrol_no_battle", { name: serverResponse.opponent.name, level: serverResponse.opponent.level }));
|
|
493
1302
|
} else {
|
|
494
|
-
console.log(
|
|
1303
|
+
console.log(t("patrol_done", { pool: serverResponse.pool_size || 0 }));
|
|
495
1304
|
}
|
|
496
1305
|
} else {
|
|
497
|
-
console.log("
|
|
1306
|
+
console.log(t("patrol_offline"));
|
|
1307
|
+
}
|
|
1308
|
+
lobster.depth = (lobster.depth ?? 0) + 1;
|
|
1309
|
+
if (shouldDrop(depth, soul)) {
|
|
1310
|
+
const loot = generateEquipment(depth, soul);
|
|
1311
|
+
console.log(t("equip_drop", { item: formatEquip(loot) }));
|
|
1312
|
+
await appendLog(`\u{1F381} ${loot.rarity}+${loot.level} ${loot.name}`);
|
|
1313
|
+
const actions = autoManageLoot(lobster, loot);
|
|
1314
|
+
for (const a of actions) {
|
|
1315
|
+
switch (a.type) {
|
|
1316
|
+
case "auto_equip":
|
|
1317
|
+
console.log(t("auto_equip", { name: lobster.name, item: formatEquip(a.item), reason: a.reason }));
|
|
1318
|
+
break;
|
|
1319
|
+
case "auto_swap":
|
|
1320
|
+
console.log(t("auto_swap", { name: lobster.name, item: formatEquip(a.item), old: a.old.name, reason: a.reason }));
|
|
1321
|
+
break;
|
|
1322
|
+
case "auto_discard":
|
|
1323
|
+
console.log(t("auto_discard", { name: lobster.name, item: a.item.name, reason: a.reason }));
|
|
1324
|
+
break;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
if (shouldDropMap(lobster.depth ?? 0, lobster.soul)) {
|
|
1329
|
+
const map = generateMap(lobster.depth ?? 0, lobster.environment);
|
|
1330
|
+
if (!lobster.dungeon_maps) lobster.dungeon_maps = [];
|
|
1331
|
+
if (lobster.dungeon_maps.length < 5) {
|
|
1332
|
+
lobster.dungeon_maps.push(map);
|
|
1333
|
+
console.log(t("dg_map_found", { theme: t(`dg_theme_${map.theme}`), rooms: map.rooms, diff: t(`dg_diff_${map.difficulty}`) }));
|
|
1334
|
+
await appendLog(`\u{1F5FA}\uFE0F \u53D1\u73B0\u5730\u56FE: ${map.theme} (${map.rooms}\u623F\u95F4, ${map.difficulty})`);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
const newAchievements = checkAchievements(lobster);
|
|
1338
|
+
for (const id of newAchievements) {
|
|
1339
|
+
const def = ACHIEVEMENTS[id];
|
|
1340
|
+
console.log(t("achieve_unlock", { name: def.name, desc: def.desc }));
|
|
498
1341
|
}
|
|
499
1342
|
await writeLobster(lobster);
|
|
500
1343
|
console.log("\u2500".repeat(40));
|
|
501
|
-
|
|
1344
|
+
const inv = lobster.inventory?.length ?? 0;
|
|
1345
|
+
console.log(t("patrol_depth", {
|
|
1346
|
+
level: lobster.level,
|
|
1347
|
+
exp: lobster.exp,
|
|
1348
|
+
next: lobster.exp_to_next,
|
|
1349
|
+
today: lobster.today_exp,
|
|
1350
|
+
cap: lobster.daily_exp_cap,
|
|
1351
|
+
depth: lobster.depth ?? 0,
|
|
1352
|
+
inv,
|
|
1353
|
+
inv_max: MAX_INVENTORY
|
|
1354
|
+
}));
|
|
1355
|
+
}
|
|
1356
|
+
function soulTag(soul) {
|
|
1357
|
+
const tags = [];
|
|
1358
|
+
if (soul.bravery >= 7) tags.push("\u52C7\u731B");
|
|
1359
|
+
if (soul.bravery <= 3) tags.push("\u8C28\u614E");
|
|
1360
|
+
if (soul.curiosity >= 7) tags.push("\u535A\u5B66");
|
|
1361
|
+
if (soul.curiosity <= 3) tags.push("\u4E13\u6CE8");
|
|
1362
|
+
if (soul.talkativeness <= 3) tags.push("\u9690\u533F");
|
|
1363
|
+
if (soul.temper >= 7) tags.push("\u66B4\u70C8");
|
|
1364
|
+
if (soul.temper <= 3) tags.push("\u6C89\u7A33");
|
|
1365
|
+
return tags.join("\xB7");
|
|
1366
|
+
}
|
|
1367
|
+
var ENV_THEMES = {
|
|
1368
|
+
coastal: ["coral_maze", "shipwreck", "tide_pool"],
|
|
1369
|
+
"deep-sea": ["deep_rift", "abyss_trench"],
|
|
1370
|
+
"hot-spring": ["thermal_vent", "coral_maze"],
|
|
1371
|
+
polar: ["ice_cavern", "deep_rift"],
|
|
1372
|
+
space: ["void_rift", "abyss_trench"],
|
|
1373
|
+
freshwater: ["tide_pool", "coral_maze"]
|
|
1374
|
+
};
|
|
1375
|
+
function shouldDropMap(depth, soul) {
|
|
1376
|
+
let chance = Math.min(0.5, 0.1 + depth * 0.03);
|
|
1377
|
+
if (soul.curiosity >= 7) chance += 0.1;
|
|
1378
|
+
return Math.random() < chance;
|
|
1379
|
+
}
|
|
1380
|
+
function generateMap(depth, environment) {
|
|
1381
|
+
const themes = ENV_THEMES[environment] || ENV_THEMES.coastal;
|
|
1382
|
+
const theme = themes[Math.floor(Math.random() * themes.length)];
|
|
1383
|
+
const rooms = Math.min(5, 3 + Math.floor(depth / 5));
|
|
1384
|
+
const difficulties = ["easy", "normal", "hard", "nightmare"];
|
|
1385
|
+
const di = Math.min(3, Math.floor(depth / 3));
|
|
1386
|
+
const difficulty = difficulties[di];
|
|
1387
|
+
return { theme, rooms, difficulty };
|
|
502
1388
|
}
|
|
503
1389
|
function checkLevelUp(lobster) {
|
|
504
1390
|
const l = lobster;
|
|
@@ -513,10 +1399,9 @@ function checkLevelUp(lobster) {
|
|
|
513
1399
|
l.stats[key] += gain;
|
|
514
1400
|
gains.push(`${key}+${gain}`);
|
|
515
1401
|
}
|
|
516
|
-
console.log(
|
|
517
|
-
\u{1F389} \u5347\u7EA7\uFF01Lv.${l.level}! [${gains.join(", ")}]`);
|
|
1402
|
+
console.log("\n" + t("level_up", { level: l.level, gains: gains.join(", ") }));
|
|
518
1403
|
if (l.level % 5 === 0) {
|
|
519
|
-
console.log("
|
|
1404
|
+
console.log(t("molt_trigger"));
|
|
520
1405
|
l.status = "molting";
|
|
521
1406
|
l.molt_count++;
|
|
522
1407
|
}
|
|
@@ -524,148 +1409,106 @@ function checkLevelUp(lobster) {
|
|
|
524
1409
|
}
|
|
525
1410
|
|
|
526
1411
|
// src/commands/battle.ts
|
|
527
|
-
function
|
|
528
|
-
const r = (base) => base + Math.floor(Math.random() * 5) - 2;
|
|
529
|
-
return {
|
|
530
|
-
id: "sim-" + Math.random().toString(36).slice(2, 10),
|
|
531
|
-
name: ["\u6DF1\u6D77\u5C0F\u900F\u660E", "\u73CA\u745A\u523A\u5BA2", "\u6697\u7901\u5B88\u536B", "\u6F6E\u6C50\u9738\u738B", "\u84DD\u7532\u9690\u8005"][Math.floor(Math.random() * 5)],
|
|
532
|
-
level: Math.max(1, level + Math.floor(Math.random() * 5) - 2),
|
|
533
|
-
stats: {
|
|
534
|
-
hp: r(10 + level * 2),
|
|
535
|
-
attack: r(5 + level),
|
|
536
|
-
defense: r(5 + level),
|
|
537
|
-
speed: r(5 + level),
|
|
538
|
-
intimidation: r(3 + Math.floor(level / 2)),
|
|
539
|
-
luck: r(3 + Math.floor(level / 2))
|
|
540
|
-
}
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
function runBattle(a, b) {
|
|
544
|
-
let hpA = a.hp;
|
|
545
|
-
let hpB = b.hp;
|
|
546
|
-
const log = [];
|
|
547
|
-
const first = a.speed > b.speed ? "a" : b.speed > a.speed ? "b" : Math.random() > 0.5 ? "a" : "b";
|
|
548
|
-
log.push(`\u5148\u624B: ${first === "a" ? "\u6211\u65B9" : "\u5BF9\u624B"} (\u901F\u5EA6 ${first === "a" ? a.speed : b.speed})`);
|
|
549
|
-
for (let round = 1; round <= 10; round++) {
|
|
550
|
-
const [atk1, def1, atk2, def2] = first === "a" ? [a, b, b, a] : [b, a, a, b];
|
|
551
|
-
const [hp1Ref, hp2Ref] = first === "a" ? ["hpB", "hpA"] : ["hpA", "hpB"];
|
|
552
|
-
const dmg1 = Math.max(1, Math.floor((atk1.attack - def1.defense * 0.5) * (1 + Math.random() * 0.2)));
|
|
553
|
-
if (hp1Ref === "hpB") hpB -= dmg1;
|
|
554
|
-
else hpA -= dmg1;
|
|
555
|
-
log.push(` R${round}: ${first === "a" ? "\u6211\u65B9" : "\u5BF9\u624B"}\u653B\u51FB \u2192 ${dmg1} \u4F24\u5BB3`);
|
|
556
|
-
if ((hp1Ref === "hpB" ? hpB : hpA) <= 0) {
|
|
557
|
-
return { winner: first, rounds: round, log };
|
|
558
|
-
}
|
|
559
|
-
const dmg2 = Math.max(1, Math.floor((atk2.attack - def2.defense * 0.5) * (1 + Math.random() * 0.2)));
|
|
560
|
-
if (hp2Ref === "hpB") hpB -= dmg2;
|
|
561
|
-
else hpA -= dmg2;
|
|
562
|
-
log.push(` R${round}: ${first === "a" ? "\u5BF9\u624B" : "\u6211\u65B9"}\u653B\u51FB \u2192 ${dmg2} \u4F24\u5BB3`);
|
|
563
|
-
if ((hp2Ref === "hpB" ? hpB : hpA) <= 0) {
|
|
564
|
-
return { winner: first === "a" ? "b" : "a", rounds: round, log };
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
return { winner: "draw", rounds: 10, log };
|
|
568
|
-
}
|
|
569
|
-
async function battle() {
|
|
1412
|
+
async function battle(opponentCode) {
|
|
570
1413
|
const lobster = await readLobster();
|
|
571
1414
|
if (!lobster) {
|
|
572
|
-
console.log("\n
|
|
1415
|
+
console.log("\n" + t("no_lobster"));
|
|
573
1416
|
return;
|
|
574
1417
|
}
|
|
575
1418
|
if (lobster.status !== "active") {
|
|
576
|
-
console.log(
|
|
577
|
-
|
|
1419
|
+
console.log("\n" + t("status_cant_fight", { name: lobster.name, status: lobster.status }));
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
if (!opponentCode) {
|
|
1423
|
+
console.log("\n" + t("battle_no_code"));
|
|
1424
|
+
console.log(t("battle_usage"));
|
|
1425
|
+
console.log(t("battle_hint"));
|
|
578
1426
|
return;
|
|
579
1427
|
}
|
|
580
|
-
|
|
1428
|
+
console.log("\n" + t("battle_connecting", { code: opponentCode }));
|
|
1429
|
+
const result = await apiBattle(lobster.id, opponentCode);
|
|
1430
|
+
if (!result) {
|
|
1431
|
+
console.log(t("battle_server_down"));
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
if (result.error) {
|
|
1435
|
+
console.log(`\u26A0\uFE0F ${result.error}`);
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
const opp = result.opponent;
|
|
1439
|
+
const myResult = result.result;
|
|
1440
|
+
const rounds = result.rounds;
|
|
1441
|
+
const expGain = result.exp_gain;
|
|
581
1442
|
console.log("\n" + "\u2694\uFE0F".repeat(20));
|
|
582
|
-
console.log(` ${lobster.name} (Lv.${lobster.level}) VS ${
|
|
1443
|
+
console.log(` ${lobster.name} (Lv.${lobster.level}) VS ${opp.name} (Lv.${opp.level})`);
|
|
583
1444
|
console.log("\u2694\uFE0F".repeat(20));
|
|
584
|
-
|
|
585
|
-
console.log();
|
|
586
|
-
for (const line of result.log) {
|
|
587
|
-
console.log(line);
|
|
588
|
-
}
|
|
589
|
-
const isWin = result.winner === "a";
|
|
590
|
-
const isDraw = result.winner === "draw";
|
|
591
|
-
let expGain;
|
|
592
|
-
if (isDraw) {
|
|
593
|
-
expGain = 10;
|
|
594
|
-
console.log(`
|
|
595
|
-
\u{1F91D} \u5E73\u5C40\uFF01${result.rounds} \u56DE\u5408\u540E\u53CC\u65B9\u7CBE\u75B2\u529B\u7AED`);
|
|
596
|
-
} else if (isWin) {
|
|
597
|
-
expGain = 30;
|
|
1445
|
+
if (myResult === "win") {
|
|
598
1446
|
lobster.wins++;
|
|
599
1447
|
lobster.streak = Math.max(0, lobster.streak) + 1;
|
|
600
1448
|
lobster.reputation++;
|
|
601
|
-
console.log(
|
|
602
|
-
|
|
603
|
-
} else {
|
|
604
|
-
expGain = 10;
|
|
1449
|
+
console.log("\n" + t("battle_win", { name: lobster.name, opponent: opp.name, rounds }));
|
|
1450
|
+
} else if (myResult === "loss") {
|
|
605
1451
|
lobster.losses++;
|
|
606
1452
|
lobster.streak = Math.min(0, lobster.streak) - 1;
|
|
607
1453
|
lobster.reputation = Math.max(0, lobster.reputation - 1);
|
|
608
|
-
console.log(
|
|
609
|
-
|
|
1454
|
+
console.log("\n" + t("battle_loss", { name: lobster.name, opponent: opp.name, rounds }));
|
|
1455
|
+
} else {
|
|
1456
|
+
console.log("\n" + t("battle_draw", { rounds }));
|
|
610
1457
|
}
|
|
611
1458
|
const actual = Math.min(expGain, lobster.daily_exp_cap - lobster.today_exp);
|
|
612
1459
|
if (actual > 0) {
|
|
613
1460
|
lobster.exp += actual;
|
|
614
1461
|
lobster.today_exp += actual;
|
|
615
1462
|
}
|
|
616
|
-
console.log(`\u7ECF\u9A8C +${actual} | \u6218\u7EE9: ${lobster.wins}\u80DC ${lobster.losses}\u8D1F | \u8FDE\u80DC: ${lobster.streak}`);
|
|
617
1463
|
lobster.last_battle = (/* @__PURE__ */ new Date()).toISOString();
|
|
618
|
-
|
|
619
|
-
await appendLog(`\u2694\uFE0F VS ${
|
|
1464
|
+
console.log(t("battle_exp", { exp: actual, wins: lobster.wins, losses: lobster.losses, streak: lobster.streak }));
|
|
1465
|
+
await appendLog(`\u2694\uFE0F VS ${opp.name}(Lv.${opp.level}) \u2192 ${myResult} (${rounds}R)`);
|
|
620
1466
|
await writeLobster(lobster);
|
|
621
1467
|
}
|
|
622
1468
|
|
|
623
1469
|
// src/commands/feed.ts
|
|
624
1470
|
var FOOD_TYPES = {
|
|
625
|
-
protein: { exp: 15,
|
|
626
|
-
algae: { exp: 10,
|
|
627
|
-
mineral: { exp: 12,
|
|
1471
|
+
protein: { exp: 15, labelKey: "food_protein", statBias: "attack" },
|
|
1472
|
+
algae: { exp: 10, labelKey: "food_algae", statBias: "hp" },
|
|
1473
|
+
mineral: { exp: 12, labelKey: "food_mineral", statBias: "defense" }
|
|
628
1474
|
};
|
|
629
1475
|
async function feed(foodType) {
|
|
630
1476
|
const lobster = await readLobster();
|
|
631
1477
|
if (!lobster) {
|
|
632
|
-
console.log("\n
|
|
1478
|
+
console.log("\n" + t("no_lobster"));
|
|
633
1479
|
return;
|
|
634
1480
|
}
|
|
635
1481
|
if (!foodType || !FOOD_TYPES[foodType]) {
|
|
636
|
-
console.log("\n
|
|
1482
|
+
console.log("\n" + t("feed_menu_title"));
|
|
637
1483
|
for (const [key, info] of Object.entries(FOOD_TYPES)) {
|
|
638
|
-
console.log(` ${key.padEnd(10)} \u2014 ${info.
|
|
1484
|
+
console.log(` ${key.padEnd(10)} \u2014 ${t(info.labelKey)} (+${info.exp} EXP, ${info.statBias})`);
|
|
639
1485
|
}
|
|
640
|
-
console.log("\n
|
|
1486
|
+
console.log("\n" + t("feed_menu_usage"));
|
|
641
1487
|
return;
|
|
642
1488
|
}
|
|
643
1489
|
const food = FOOD_TYPES[foodType];
|
|
644
1490
|
const actual = Math.min(food.exp, lobster.daily_exp_cap - lobster.today_exp);
|
|
645
1491
|
if (actual <= 0) {
|
|
646
|
-
console.log(
|
|
647
|
-
\u26A0\uFE0F ${lobster.name} \u4ECA\u5929\u5DF2\u7ECF\u5403\u9971\u4E86\uFF08\u6BCF\u65E5\u7ECF\u9A8C\u4E0A\u9650 ${lobster.daily_exp_cap}\uFF09`);
|
|
1492
|
+
console.log("\n" + t("feed_full", { name: lobster.name, cap: lobster.daily_exp_cap }));
|
|
648
1493
|
return;
|
|
649
1494
|
}
|
|
650
1495
|
lobster.exp += actual;
|
|
651
1496
|
lobster.today_exp += actual;
|
|
1497
|
+
const foodLabel = t(food.labelKey);
|
|
652
1498
|
const stats = lobster.stats;
|
|
653
1499
|
if (food.statBias in stats) {
|
|
654
1500
|
const bonus = Math.random() > 0.5 ? 1 : 0;
|
|
1501
|
+
console.log("\n" + t("feed_ate", { name: lobster.name, food: foodLabel }));
|
|
655
1502
|
if (bonus > 0) {
|
|
656
1503
|
stats[food.statBias] += bonus;
|
|
657
|
-
console.log(
|
|
658
|
-
\u{1F37D}\uFE0F ${lobster.name} \u5403\u4E86 ${food.label}\uFF01`);
|
|
659
|
-
console.log(` \u7ECF\u9A8C +${actual} | ${food.statBias} +${bonus}`);
|
|
1504
|
+
console.log(t("feed_exp_stat", { exp: actual, stat: food.statBias, bonus }));
|
|
660
1505
|
} else {
|
|
661
|
-
console.log(
|
|
662
|
-
\u{1F37D}\uFE0F ${lobster.name} \u5403\u4E86 ${food.label}\uFF01`);
|
|
663
|
-
console.log(` \u7ECF\u9A8C +${actual}`);
|
|
1506
|
+
console.log(t("feed_exp", { exp: actual }));
|
|
664
1507
|
}
|
|
665
1508
|
}
|
|
666
|
-
await appendLog(`\u{1F37D}\uFE0F
|
|
1509
|
+
await appendLog(`\u{1F37D}\uFE0F ${foodLabel} \u2192 EXP+${actual}`);
|
|
667
1510
|
await writeLobster(lobster);
|
|
668
|
-
console.log(
|
|
1511
|
+
console.log(t("feed_today", { today: lobster.today_exp, cap: lobster.daily_exp_cap }));
|
|
669
1512
|
}
|
|
670
1513
|
|
|
671
1514
|
// src/commands/leaderboard.ts
|
|
@@ -678,73 +1521,75 @@ var RARITY_SYMBOLS = {
|
|
|
678
1521
|
albino: "\u2B1C"
|
|
679
1522
|
};
|
|
680
1523
|
async function leaderboard() {
|
|
681
|
-
console.log("\n
|
|
1524
|
+
console.log("\n" + t("lb_loading"));
|
|
682
1525
|
const data = await apiLeaderboard(20);
|
|
683
1526
|
if (!data) {
|
|
684
|
-
console.log("
|
|
1527
|
+
console.log(t("lb_offline"));
|
|
685
1528
|
return;
|
|
686
1529
|
}
|
|
687
1530
|
if (data.leaderboard.length === 0) {
|
|
688
|
-
console.log("\n
|
|
1531
|
+
console.log("\n" + t("lb_empty"));
|
|
689
1532
|
return;
|
|
690
1533
|
}
|
|
691
|
-
console.log("\n" + "\u2550".repeat(
|
|
692
|
-
console.log("
|
|
693
|
-
console.log("\u2550".repeat(
|
|
694
|
-
console.log(
|
|
695
|
-
console.log("\u2500".repeat(
|
|
1534
|
+
console.log("\n" + "\u2550".repeat(70));
|
|
1535
|
+
console.log(t("lb_title"));
|
|
1536
|
+
console.log("\u2550".repeat(70));
|
|
1537
|
+
console.log(t("lb_header"));
|
|
1538
|
+
console.log("\u2500".repeat(70));
|
|
696
1539
|
for (const entry of data.leaderboard) {
|
|
697
1540
|
const sym = RARITY_SYMBOLS[entry.rarity] || " ";
|
|
698
1541
|
const name = entry.name.length > 12 ? entry.name.slice(0, 11) + "\u2026" : entry.name;
|
|
1542
|
+
const code = entry.id.slice(0, 8);
|
|
699
1543
|
console.log(
|
|
700
|
-
` ${sym} #${String(entry.rank).padEnd(4)} ${name.padEnd(14)} Lv.${String(entry.level).padEnd(5)} ${String(entry.wins).padEnd(7)} ${entry.win_rate}
|
|
1544
|
+
` ${sym} #${String(entry.rank).padEnd(4)} ${name.padEnd(14)} Lv.${String(entry.level).padEnd(5)} ${String(entry.wins).padEnd(7)} ${String(entry.win_rate).padEnd(3)}% ${code}`
|
|
701
1545
|
);
|
|
702
1546
|
}
|
|
703
|
-
console.log("\u2500".repeat(
|
|
704
|
-
console.log(
|
|
705
|
-
console.log("
|
|
1547
|
+
console.log("\u2500".repeat(70));
|
|
1548
|
+
console.log(t("lb_total", { total: data.total_lobsters, active: data.active_lobsters }));
|
|
1549
|
+
console.log(t("lb_hint"));
|
|
1550
|
+
console.log("\u2550".repeat(70));
|
|
706
1551
|
}
|
|
707
1552
|
|
|
708
1553
|
// src/commands/rest.ts
|
|
709
1554
|
async function rest() {
|
|
710
1555
|
const lobster = await readLobster();
|
|
711
1556
|
if (!lobster) {
|
|
712
|
-
console.log("\n
|
|
1557
|
+
console.log("\n" + t("no_lobster"));
|
|
713
1558
|
return;
|
|
714
1559
|
}
|
|
715
1560
|
if (lobster.status === "hibernating") {
|
|
716
|
-
console.log(
|
|
717
|
-
\u{1F4A4} ${lobster.name} \u5DF2\u7ECF\u5728\u4F11\u7720\u4E2D\u4E86\u3002\u8FD0\u884C npx clawfight wake \u6765\u5524\u9192\u5B83\u3002`);
|
|
1561
|
+
console.log("\n" + t("rest_already", { name: lobster.name }));
|
|
718
1562
|
return;
|
|
719
1563
|
}
|
|
720
1564
|
if (lobster.status === "molting") {
|
|
721
|
-
console.log(
|
|
722
|
-
\u{1F7E1} ${lobster.name} \u6B63\u5728\u8715\u58F3\uFF0C\u4E0D\u80FD\u4F11\u7720\u3002\u7B49\u8715\u58F3\u7ED3\u675F\u518D\u6765\u3002`);
|
|
1565
|
+
console.log("\n" + t("rest_molting", { name: lobster.name }));
|
|
723
1566
|
return;
|
|
724
1567
|
}
|
|
725
1568
|
lobster.status = "hibernating";
|
|
726
1569
|
lobster.hibernated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1570
|
+
const hadDepth = lobster.depth && lobster.depth > 0;
|
|
1571
|
+
if (hadDepth) lobster.depth = 0;
|
|
727
1572
|
await writeLobster(lobster);
|
|
728
|
-
await appendLog(`\u{1F4A4} ${lobster.name} \
|
|
1573
|
+
await appendLog(`\u{1F4A4} ${lobster.name} \u2192 hibernation`);
|
|
729
1574
|
console.log("\n" + "\u2500".repeat(40));
|
|
730
|
-
console.log(
|
|
731
|
-
console.log("
|
|
732
|
-
console.log("
|
|
733
|
-
console.log("
|
|
1575
|
+
console.log(t("rest_desc1", { name: lobster.name }));
|
|
1576
|
+
console.log(t("rest_desc2"));
|
|
1577
|
+
console.log(t("rest_desc3"));
|
|
1578
|
+
console.log(t("rest_desc4"));
|
|
1579
|
+
if (hadDepth) console.log(t("depth_reset"));
|
|
734
1580
|
console.log("\u2500".repeat(40));
|
|
735
|
-
console.log("\n
|
|
1581
|
+
console.log("\n" + t("rest_wake_hint"));
|
|
736
1582
|
}
|
|
737
1583
|
|
|
738
1584
|
// src/commands/wake.ts
|
|
739
1585
|
async function wake() {
|
|
740
1586
|
const lobster = await readLobster();
|
|
741
1587
|
if (!lobster) {
|
|
742
|
-
console.log("\n
|
|
1588
|
+
console.log("\n" + t("no_lobster"));
|
|
743
1589
|
return;
|
|
744
1590
|
}
|
|
745
1591
|
if (lobster.status !== "hibernating") {
|
|
746
|
-
console.log(
|
|
747
|
-
\u{1F7E2} ${lobster.name} \u6CA1\u6709\u5728\u4F11\u7720\u3002\u5B83\u5DF2\u7ECF\u662F\u6D3B\u8DC3\u72B6\u6001\u4E86\uFF01`);
|
|
1592
|
+
console.log("\n" + t("wake_not_sleeping", { name: lobster.name }));
|
|
748
1593
|
return;
|
|
749
1594
|
}
|
|
750
1595
|
const sleepStart = lobster.hibernated_at ? new Date(lobster.hibernated_at) : /* @__PURE__ */ new Date();
|
|
@@ -772,21 +1617,369 @@ async function wake() {
|
|
|
772
1617
|
lobster.status = "active";
|
|
773
1618
|
delete lobster.hibernated_at;
|
|
774
1619
|
await writeLobster(lobster);
|
|
775
|
-
const
|
|
776
|
-
const bonusStr = bonuses.length > 0 ? bonuses.join(", ") : "
|
|
777
|
-
await appendLog(`\u2600\uFE0F ${lobster.name}
|
|
1620
|
+
const duration = hoursSlept < 1 ? t("duration_minutes", { n: Math.round(hoursSlept * 60) }) : t("duration_hours", { n: Math.round(hoursSlept) });
|
|
1621
|
+
const bonusStr = bonuses.length > 0 ? bonuses.join(", ") : t("wake_no_bonus");
|
|
1622
|
+
await appendLog(`\u2600\uFE0F ${lobster.name} woke (${duration}) \u2192 ${bonusStr}`);
|
|
778
1623
|
console.log("\n" + "\u2500".repeat(40));
|
|
779
|
-
console.log(
|
|
780
|
-
console.log(
|
|
781
|
-
console.log(
|
|
1624
|
+
console.log(t("wake_desc", { name: lobster.name }));
|
|
1625
|
+
console.log(t("wake_duration", { duration }));
|
|
1626
|
+
console.log(t("wake_bonus", { bonus: bonusStr }));
|
|
1627
|
+
console.log("\u2500".repeat(40));
|
|
1628
|
+
console.log("\n" + t("wake_ready", { name: lobster.name }));
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
// src/commands/equip.ts
|
|
1632
|
+
var SLOTS = ["claw", "shell", "charm"];
|
|
1633
|
+
async function equip(action, arg) {
|
|
1634
|
+
const lobster = await readLobster();
|
|
1635
|
+
if (!lobster) {
|
|
1636
|
+
console.log("\n" + t("no_lobster"));
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
if (!lobster.equipped) lobster.equipped = {};
|
|
1640
|
+
if (!lobster.inventory) lobster.inventory = [];
|
|
1641
|
+
if (!action) {
|
|
1642
|
+
console.log("\n" + t("equip_title"));
|
|
1643
|
+
console.log("\u2500".repeat(40));
|
|
1644
|
+
for (const s of SLOTS) {
|
|
1645
|
+
const eq = lobster.equipped[s];
|
|
1646
|
+
if (eq) {
|
|
1647
|
+
console.log(t("equip_slot_item", { icon: SLOT_ICONS[s], slot: SLOT_LABELS[s], item: formatEquip(eq) }));
|
|
1648
|
+
} else {
|
|
1649
|
+
console.log(t("equip_slot_empty", { icon: SLOT_ICONS[s], slot: SLOT_LABELS[s] }));
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
console.log();
|
|
1653
|
+
console.log(t("equip_inv_title", { count: lobster.inventory.length, max: MAX_INVENTORY }));
|
|
1654
|
+
if (lobster.inventory.length === 0) {
|
|
1655
|
+
console.log(t("equip_inv_empty"));
|
|
1656
|
+
} else {
|
|
1657
|
+
for (let i = 0; i < lobster.inventory.length; i++) {
|
|
1658
|
+
console.log(t("equip_inv_item", { index: i + 1, item: formatEquip(lobster.inventory[i]) }));
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
console.log("\u2500".repeat(40));
|
|
1662
|
+
console.log(t("equip_usage"));
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1665
|
+
if (action === "drop") {
|
|
1666
|
+
const idx2 = parseInt(arg || "", 10) - 1;
|
|
1667
|
+
if (isNaN(idx2) || idx2 < 0 || idx2 >= lobster.inventory.length) {
|
|
1668
|
+
console.log("\n" + t("equip_bad_index"));
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
const removed = lobster.inventory.splice(idx2, 1)[0];
|
|
1672
|
+
await writeLobster(lobster);
|
|
1673
|
+
console.log("\n" + t("equip_dropped", { item: formatEquip(removed) }));
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
if (action === "unequip") {
|
|
1677
|
+
const slot = arg;
|
|
1678
|
+
if (!slot || !SLOTS.includes(slot)) {
|
|
1679
|
+
console.log("\n" + t("equip_bad_index"));
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
const eq = lobster.equipped[slot];
|
|
1683
|
+
if (!eq) {
|
|
1684
|
+
console.log("\n" + t("equip_slot_empty", { icon: SLOT_ICONS[slot], slot: SLOT_LABELS[slot] }));
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
if (lobster.inventory.length >= MAX_INVENTORY) {
|
|
1688
|
+
console.log("\n" + t("equip_inv_full", { max: MAX_INVENTORY, item: eq.name }));
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
lobster.inventory.push(eq);
|
|
1692
|
+
delete lobster.equipped[slot];
|
|
1693
|
+
await writeLobster(lobster);
|
|
1694
|
+
console.log("\n" + t("equip_unequipped", { item: formatEquip(eq) }));
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
const idx = parseInt(action, 10) - 1;
|
|
1698
|
+
if (isNaN(idx) || idx < 0 || idx >= lobster.inventory.length) {
|
|
1699
|
+
console.log("\n" + t("equip_bad_index"));
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
const item = lobster.inventory[idx];
|
|
1703
|
+
const existing = lobster.equipped[item.slot];
|
|
1704
|
+
lobster.inventory.splice(idx, 1);
|
|
1705
|
+
lobster.equipped[item.slot] = item;
|
|
1706
|
+
if (existing) {
|
|
1707
|
+
lobster.inventory.push(existing);
|
|
1708
|
+
await writeLobster(lobster);
|
|
1709
|
+
console.log("\n" + t("equip_swapped", { old: existing.name, item: formatEquip(item) }));
|
|
1710
|
+
} else {
|
|
1711
|
+
await writeLobster(lobster);
|
|
1712
|
+
console.log("\n" + t("equip_equipped", { item: formatEquip(item), slot: SLOT_LABELS[item.slot] }));
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
// src/commands/achievements.ts
|
|
1717
|
+
async function achievements() {
|
|
1718
|
+
const lobster = await readLobster();
|
|
1719
|
+
if (!lobster) {
|
|
1720
|
+
console.log("\n" + t("no_lobster"));
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
const unlocked = new Set(lobster.achievements ?? []);
|
|
1724
|
+
const total = Object.keys(ACHIEVEMENTS).length;
|
|
1725
|
+
console.log("\n" + t("achieve_title", { count: unlocked.size, total }));
|
|
1726
|
+
console.log("\u2500".repeat(40));
|
|
1727
|
+
for (const [id, def] of Object.entries(ACHIEVEMENTS)) {
|
|
1728
|
+
if (unlocked.has(id)) {
|
|
1729
|
+
console.log(t("achieve_item", { name: def.name, desc: def.desc }));
|
|
1730
|
+
} else {
|
|
1731
|
+
console.log(t("achieve_locked", { name: def.name, desc: def.desc }));
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
782
1734
|
console.log("\u2500".repeat(40));
|
|
783
|
-
|
|
784
|
-
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
// src/commands/explore.ts
|
|
1738
|
+
var RISK_ICON = { low: "\u{1F7E2}", mid: "\u{1F7E1}", high: "\u{1F534}" };
|
|
1739
|
+
var THEME_ICON = {
|
|
1740
|
+
coral_maze: "\u{1FAB8}",
|
|
1741
|
+
deep_rift: "\u{1F30A}",
|
|
1742
|
+
thermal_vent: "\u{1F30B}",
|
|
1743
|
+
ice_cavern: "\u2744\uFE0F",
|
|
1744
|
+
shipwreck: "\u{1F6A2}",
|
|
1745
|
+
abyss_trench: "\u{1F573}\uFE0F",
|
|
1746
|
+
tide_pool: "\u{1F3D6}\uFE0F",
|
|
1747
|
+
void_rift: "\u{1F300}"
|
|
1748
|
+
};
|
|
1749
|
+
function formatRoom(room, theme) {
|
|
1750
|
+
const icon = THEME_ICON[theme] || "\u{1F3D4}\uFE0F";
|
|
1751
|
+
const lines = [];
|
|
1752
|
+
lines.push(`${icon} ${t(`dg_theme_${theme}`)} | ${room.index + 1}/${room.total} | HP:${room.hp.current}/${room.hp.max}`);
|
|
1753
|
+
const c1 = room.choices[0];
|
|
1754
|
+
const c2 = room.choices[1];
|
|
1755
|
+
lines.push(` [1] ${t(`dg_${c1.key}`)} (${c1.stat.toUpperCase()}, ${RISK_ICON[c1.risk]}${t(`dg_risk_${c1.risk}`)}) [2] ${t(`dg_${c2.key}`)} (${c2.stat.toUpperCase()}, ${RISK_ICON[c2.risk]}${t(`dg_risk_${c2.risk}`)})`);
|
|
1756
|
+
if (c1.soul_hint) lines.push(` \u{1F99E} ${t(`dg_${c1.soul_hint}`)}`);
|
|
1757
|
+
if (c2.soul_hint) lines.push(` \u{1F99E} ${t(`dg_${c2.soul_hint}`)}`);
|
|
1758
|
+
return lines.join("\n");
|
|
1759
|
+
}
|
|
1760
|
+
function lootToEquipment(l) {
|
|
1761
|
+
return { ...l, id: Math.random().toString(36).slice(2, 10) };
|
|
1762
|
+
}
|
|
1763
|
+
async function explore(action) {
|
|
1764
|
+
const lobster = await readLobster();
|
|
1765
|
+
if (!lobster) {
|
|
1766
|
+
console.log("\n" + t("no_lobster"));
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
if (lobster.status === "molting") {
|
|
1770
|
+
console.log("\n" + t("status_cant_patrol_molt", { name: lobster.name }));
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
if (lobster.status === "hibernating") {
|
|
1774
|
+
console.log("\n" + t("status_cant_patrol_hibernate", { name: lobster.name }));
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
if (action === "abandon") {
|
|
1778
|
+
return await abandonDungeon(lobster);
|
|
1779
|
+
}
|
|
1780
|
+
if (action === "1" || action === "2") {
|
|
1781
|
+
return await makeChoice(lobster, parseInt(action));
|
|
1782
|
+
}
|
|
1783
|
+
if (action === "maps") {
|
|
1784
|
+
return showMaps(lobster);
|
|
1785
|
+
}
|
|
1786
|
+
return await enterOrResume(lobster, action);
|
|
1787
|
+
}
|
|
1788
|
+
async function enterOrResume(lobster, mapIndex) {
|
|
1789
|
+
console.log("\n" + t("dg_connecting"));
|
|
1790
|
+
const stateRes = await apiDungeonState(lobster.id);
|
|
1791
|
+
if (!stateRes) {
|
|
1792
|
+
console.log(t("patrol_offline"));
|
|
1793
|
+
return;
|
|
1794
|
+
}
|
|
1795
|
+
if (stateRes.active && stateRes.room) {
|
|
1796
|
+
console.log(t("dg_resume"));
|
|
1797
|
+
console.log(formatRoom(stateRes.room, stateRes.theme));
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
const maps = lobster.dungeon_maps || [];
|
|
1801
|
+
if (maps.length === 0) {
|
|
1802
|
+
console.log(t("dg_no_maps"));
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
let idx = 0;
|
|
1806
|
+
if (mapIndex && !isNaN(parseInt(mapIndex))) {
|
|
1807
|
+
idx = parseInt(mapIndex) - 1;
|
|
1808
|
+
if (idx < 0 || idx >= maps.length) {
|
|
1809
|
+
console.log(t("dg_bad_map_index", { count: maps.length }));
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
const map = maps[idx];
|
|
1814
|
+
console.log(t("dg_entering", { theme: t(`dg_theme_${map.theme}`), rooms: map.rooms, diff: t(`dg_diff_${map.difficulty}`) }));
|
|
1815
|
+
const res = await apiDungeonEnter(lobster, map.theme);
|
|
1816
|
+
if (!res) {
|
|
1817
|
+
console.log(t("patrol_offline"));
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
if (res.error) {
|
|
1821
|
+
console.log(`\u26A0\uFE0F ${res.error}`);
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
lobster.active_dungeon = res.dungeon_id;
|
|
1825
|
+
maps.splice(idx, 1);
|
|
1826
|
+
lobster.dungeon_maps = maps;
|
|
1827
|
+
await writeLobster(lobster);
|
|
1828
|
+
await appendLog(`\u{1F5FA}\uFE0F \u8FDB\u5165\u5730\u4E0B\u57CE: ${map.theme} (${map.rooms}\u623F\u95F4)`);
|
|
1829
|
+
console.log("\u2500".repeat(40));
|
|
1830
|
+
console.log(formatRoom(res.room, res.theme));
|
|
1831
|
+
}
|
|
1832
|
+
async function makeChoice(lobster, choice) {
|
|
1833
|
+
if (!lobster.active_dungeon) {
|
|
1834
|
+
console.log("\n" + t("dg_no_active"));
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
console.log("");
|
|
1838
|
+
const res = await apiDungeonAct(lobster.active_dungeon, lobster.id, choice);
|
|
1839
|
+
if (!res) {
|
|
1840
|
+
console.log(t("patrol_offline"));
|
|
1841
|
+
return;
|
|
1842
|
+
}
|
|
1843
|
+
const o = res.outcome;
|
|
1844
|
+
const icon = o.success ? "\u2705" : "\u274C";
|
|
1845
|
+
console.log(`${icon} ${t(`dg_${o.key}`, { damage: o.damage_taken, heal: o.hp_healed })} | EXP+${o.exp_gained}`);
|
|
1846
|
+
if (o.damage_taken > 0) console.log(` \u{1F494} HP -${o.damage_taken} \u2192 ${res.hp.current}/${res.hp.max}`);
|
|
1847
|
+
if (o.hp_healed > 0) console.log(` \u{1F49A} HP +${o.hp_healed} \u2192 ${res.hp.current}/${res.hp.max}`);
|
|
1848
|
+
if (o.soul_activated) console.log(` \u{1F99E} ${t(`dg_${o.soul_activated}`)}`);
|
|
1849
|
+
if (o.loot) {
|
|
1850
|
+
const equip2 = lootToEquipment(o.loot);
|
|
1851
|
+
console.log(` ${t("equip_drop", { item: formatEquip(equip2) })}`);
|
|
1852
|
+
}
|
|
1853
|
+
if (res.status === "completed" || res.status === "failed") {
|
|
1854
|
+
console.log("\u2500".repeat(40));
|
|
1855
|
+
if (res.status === "completed") {
|
|
1856
|
+
console.log(t("dg_complete"));
|
|
1857
|
+
lobster.dungeons_completed = (lobster.dungeons_completed ?? 0) + 1;
|
|
1858
|
+
} else {
|
|
1859
|
+
console.log(t("dg_failed"));
|
|
1860
|
+
}
|
|
1861
|
+
if (res.rewards) {
|
|
1862
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1863
|
+
const lastDay = lobster.last_patrol ? lobster.last_patrol.split("T")[0] : "";
|
|
1864
|
+
if (today !== lastDay) lobster.today_exp = 0;
|
|
1865
|
+
const expGain = Math.min(res.rewards.total_exp, lobster.daily_exp_cap - lobster.today_exp);
|
|
1866
|
+
if (expGain > 0) {
|
|
1867
|
+
lobster.exp += expGain;
|
|
1868
|
+
lobster.today_exp += expGain;
|
|
1869
|
+
}
|
|
1870
|
+
console.log(t("dg_rewards_exp", { exp: expGain }));
|
|
1871
|
+
for (const loot of res.rewards.loot) {
|
|
1872
|
+
const equip2 = lootToEquipment(loot);
|
|
1873
|
+
console.log(` ${t("equip_drop", { item: formatEquip(equip2) })}`);
|
|
1874
|
+
if (loot.rarity === "epic" || loot.rarity === "legendary") {
|
|
1875
|
+
lobster.dungeon_epics_found = (lobster.dungeon_epics_found ?? 0) + 1;
|
|
1876
|
+
}
|
|
1877
|
+
const actions = autoManageLoot(lobster, equip2);
|
|
1878
|
+
for (const a of actions) {
|
|
1879
|
+
if (a.type === "auto_equip") console.log(` ${t("auto_equip", { name: lobster.name, item: formatEquip(a.item), reason: a.reason })}`);
|
|
1880
|
+
else if (a.type === "auto_swap") console.log(` ${t("auto_swap", { name: lobster.name, item: formatEquip(a.item), old: a.old.name, reason: a.reason })}`);
|
|
1881
|
+
else if (a.type === "auto_discard") console.log(` ${t("auto_discard", { name: lobster.name, item: a.item.name, reason: a.reason })}`);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
checkLevelUp2(lobster);
|
|
1885
|
+
for (const loot of res.rewards.loot) {
|
|
1886
|
+
if (loot.rarity === "epic" || loot.rarity === "legendary") {
|
|
1887
|
+
const room = res.rewards.loot.indexOf(loot);
|
|
1888
|
+
if (room === res.rewards.loot.length - 1) {
|
|
1889
|
+
lobster.boss_kills = (lobster.boss_kills ?? 0) + 1;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
await appendLog(`\u{1F3F0} \u5730\u4E0B\u57CE${res.status === "completed" ? "\u901A\u5173" : "\u5931\u8D25"}: EXP+${expGain}, \u6218\u5229\u54C1\xD7${res.rewards.loot.length}`);
|
|
1894
|
+
}
|
|
1895
|
+
lobster.active_dungeon = void 0;
|
|
1896
|
+
const newAch = checkAchievements(lobster);
|
|
1897
|
+
for (const id of newAch) {
|
|
1898
|
+
const def = ACHIEVEMENTS[id];
|
|
1899
|
+
console.log(t("achieve_unlock", { name: def.name, desc: def.desc }));
|
|
1900
|
+
}
|
|
1901
|
+
await writeLobster(lobster);
|
|
1902
|
+
console.log(t("dg_summary", {
|
|
1903
|
+
level: lobster.level,
|
|
1904
|
+
exp: lobster.exp,
|
|
1905
|
+
next: lobster.exp_to_next,
|
|
1906
|
+
today: lobster.today_exp,
|
|
1907
|
+
cap: lobster.daily_exp_cap
|
|
1908
|
+
}));
|
|
1909
|
+
return;
|
|
1910
|
+
}
|
|
1911
|
+
if (res.next_room) {
|
|
1912
|
+
console.log("\u2500".repeat(40));
|
|
1913
|
+
const stateRes = await apiDungeonState(lobster.id);
|
|
1914
|
+
const theme = stateRes?.theme || "";
|
|
1915
|
+
console.log(formatRoom(res.next_room, theme));
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
async function abandonDungeon(lobster) {
|
|
1919
|
+
if (!lobster.active_dungeon) {
|
|
1920
|
+
console.log("\n" + t("dg_no_active"));
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
console.log("\n" + t("dg_abandoning"));
|
|
1924
|
+
const res = await apiDungeonAbandon(lobster.id);
|
|
1925
|
+
if (!res) {
|
|
1926
|
+
console.log(t("patrol_offline"));
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
const expGain = Math.min(res.partial_exp, lobster.daily_exp_cap - lobster.today_exp);
|
|
1930
|
+
if (expGain > 0) {
|
|
1931
|
+
lobster.exp += expGain;
|
|
1932
|
+
lobster.today_exp += expGain;
|
|
1933
|
+
}
|
|
1934
|
+
for (const loot of res.partial_loot) {
|
|
1935
|
+
const equip2 = lootToEquipment(loot);
|
|
1936
|
+
autoManageLoot(lobster, equip2);
|
|
1937
|
+
}
|
|
1938
|
+
lobster.active_dungeon = void 0;
|
|
1939
|
+
const penalty = Math.max(0, (lobster.depth ?? 0) - 2);
|
|
1940
|
+
lobster.depth = penalty;
|
|
1941
|
+
await writeLobster(lobster);
|
|
1942
|
+
await appendLog(`\u{1F3F0} \u653E\u5F03\u5730\u4E0B\u57CE: EXP+${expGain}, \u6DF1\u5EA6\u2192${lobster.depth}`);
|
|
1943
|
+
console.log(t("dg_abandoned", { exp: expGain, loot: res.partial_loot.length, depth: lobster.depth }));
|
|
1944
|
+
}
|
|
1945
|
+
function showMaps(lobster) {
|
|
1946
|
+
const maps = lobster.dungeon_maps || [];
|
|
1947
|
+
if (maps.length === 0) {
|
|
1948
|
+
console.log("\n" + t("dg_no_maps"));
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1951
|
+
console.log("\n" + t("dg_maps_title", { count: maps.length }));
|
|
1952
|
+
for (let i = 0; i < maps.length; i++) {
|
|
1953
|
+
const m = maps[i];
|
|
1954
|
+
const icon = THEME_ICON[m.theme] || "\u{1F3D4}\uFE0F";
|
|
1955
|
+
console.log(` [${i + 1}] ${icon} ${t(`dg_theme_${m.theme}`)} | ${m.rooms}${t("dg_rooms")} | ${t(`dg_diff_${m.difficulty}`)}`);
|
|
1956
|
+
}
|
|
1957
|
+
console.log(t("dg_maps_hint"));
|
|
1958
|
+
}
|
|
1959
|
+
function checkLevelUp2(lobster) {
|
|
1960
|
+
while (lobster.exp >= lobster.exp_to_next) {
|
|
1961
|
+
lobster.exp -= lobster.exp_to_next;
|
|
1962
|
+
lobster.level++;
|
|
1963
|
+
lobster.exp_to_next = calcExpToNext(lobster.level);
|
|
1964
|
+
const statKeys = ["hp", "attack", "defense", "speed", "intimidation", "luck"];
|
|
1965
|
+
const gains = [];
|
|
1966
|
+
for (const key of statKeys) {
|
|
1967
|
+
const gain = 1 + Math.floor(Math.random() * 3);
|
|
1968
|
+
lobster.stats[key] += gain;
|
|
1969
|
+
gains.push(`${key}+${gain}`);
|
|
1970
|
+
}
|
|
1971
|
+
console.log("\n" + t("level_up", { level: lobster.level, gains: gains.join(", ") }));
|
|
1972
|
+
if (lobster.level % 5 === 0) {
|
|
1973
|
+
console.log(t("molt_trigger"));
|
|
1974
|
+
lobster.status = "molting";
|
|
1975
|
+
lobster.molt_count++;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
785
1978
|
}
|
|
786
1979
|
|
|
787
1980
|
// src/index.ts
|
|
788
1981
|
var program = new Command();
|
|
789
|
-
program.name("clawfight").description("\u{1F99E} ClawFight \u2014 \u9F99\u867E\u7535\u5B50\u5BA0\u7269\u5BF9\u6218").version("1.
|
|
1982
|
+
program.name("clawfight").description("\u{1F99E} ClawFight \u2014 \u9F99\u867E\u7535\u5B50\u5BA0\u7269\u5BF9\u6218").version("1.5.0");
|
|
790
1983
|
program.command("hatch").description("\u5B75\u5316\u4E00\u53EA\u65B0\u9F99\u867E").argument("[name]", "\u4E3A\u9F99\u867E\u53D6\u540D").action(async (name) => {
|
|
791
1984
|
await hatch(name);
|
|
792
1985
|
});
|
|
@@ -796,8 +1989,8 @@ program.command("status").description("\u67E5\u770B\u9F99\u867E\u72B6\u6001").ac
|
|
|
796
1989
|
program.command("patrol").description("\u5DE1\u903B\u7B7E\u5230\uFF0C\u89E6\u53D1\u968F\u673A\u4E8B\u4EF6\u548C\u906D\u9047").action(async () => {
|
|
797
1990
|
await patrol();
|
|
798
1991
|
});
|
|
799
|
-
program.command("battle").description("\
|
|
800
|
-
await battle();
|
|
1992
|
+
program.command("battle").description("\u901A\u8FC7\u6218\u6597\u7801\u6311\u6218\u6307\u5B9A\u5BF9\u624B").argument("[code]", "\u5BF9\u624B\u7684\u6218\u6597\u7801\uFF08\u6392\u884C\u699C\u4E2D\u53EF\u89C1\uFF09").action(async (code) => {
|
|
1993
|
+
await battle(code);
|
|
801
1994
|
});
|
|
802
1995
|
program.command("feed").description("\u5582\u517B\u9F99\u867E").argument("[food_type]", "\u98DF\u7269\u7C7B\u578B: protein, algae, mineral").action(async (foodType) => {
|
|
803
1996
|
await feed(foodType);
|
|
@@ -811,4 +2004,13 @@ program.command("rest").description("\u8FDB\u5165\u4F11\u7720\uFF08\u6682\u505C\
|
|
|
811
2004
|
program.command("wake").description("\u4ECE\u4F11\u7720\u4E2D\u5524\u9192\uFF08\u9644\u5E26\u6062\u590D\u52A0\u6210\uFF09").action(async () => {
|
|
812
2005
|
await wake();
|
|
813
2006
|
});
|
|
2007
|
+
program.command("equip").description("\u88C5\u5907\u7BA1\u7406\uFF08\u67E5\u770B/\u7A7F\u6234/\u5378\u4E0B/\u4E22\u5F03\uFF09").argument("[action]", "\u7F16\u53F7(\u88C5\u5907) / drop / unequip").argument("[arg]", "\u7F16\u53F7\u6216\u69FD\u4F4D(claw/shell/charm)").action(async (action, arg) => {
|
|
2008
|
+
await equip(action, arg);
|
|
2009
|
+
});
|
|
2010
|
+
program.command("achievements").alias("ach").description("\u67E5\u770B\u6210\u5C31").action(async () => {
|
|
2011
|
+
await achievements();
|
|
2012
|
+
});
|
|
2013
|
+
program.command("explore").alias("dg").description("\u5730\u4E0B\u57CE\u63A2\u7D22\uFF08\u8FDB\u5165/\u9009\u62E9/\u653E\u5F03/\u67E5\u770B\u5730\u56FE\uFF09").argument("[action]", "1|2(\u9009\u62E9) / abandon(\u653E\u5F03) / maps(\u67E5\u770B\u5730\u56FE) / \u5730\u56FE\u7F16\u53F7(\u8FDB\u5165)").action(async (action) => {
|
|
2014
|
+
await explore(action);
|
|
2015
|
+
});
|
|
814
2016
|
program.parse();
|