koishi-plugin-deadcells-burst 0.1.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/lib/commands/alchemy.d.ts +3 -0
- package/lib/commands/alchemy.js +67 -0
- package/lib/commands/boss.d.ts +3 -0
- package/lib/commands/boss.js +179 -0
- package/lib/commands/character.d.ts +3 -0
- package/lib/commands/character.js +28 -0
- package/lib/commands/duel.d.ts +3 -0
- package/lib/commands/duel.js +180 -0
- package/lib/commands/explore.d.ts +3 -0
- package/lib/commands/explore.js +36 -0
- package/lib/commands/forge.d.ts +3 -0
- package/lib/commands/forge.js +73 -0
- package/lib/commands/index.d.ts +3 -0
- package/lib/commands/index.js +20 -0
- package/lib/commands/upgrade.d.ts +3 -0
- package/lib/commands/upgrade.js +42 -0
- package/lib/config.d.ts +13 -0
- package/lib/config.js +43 -0
- package/lib/core/battle.d.ts +2 -0
- package/lib/core/battle.js +720 -0
- package/lib/core/boss.d.ts +27 -0
- package/lib/core/boss.js +210 -0
- package/lib/core/exploration-dispatch.d.ts +9 -0
- package/lib/core/exploration-dispatch.js +111 -0
- package/lib/core/exploration.d.ts +45 -0
- package/lib/core/exploration.js +197 -0
- package/lib/core/progression.d.ts +20 -0
- package/lib/core/progression.js +87 -0
- package/lib/data/amulets.d.ts +31 -0
- package/lib/data/amulets.js +92 -0
- package/lib/data/equipment.d.ts +27 -0
- package/lib/data/equipment.js +83 -0
- package/lib/data/maps.d.ts +11 -0
- package/lib/data/maps.js +147 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.js +68 -0
- package/lib/output/forward.d.ts +3 -0
- package/lib/output/forward.js +16 -0
- package/lib/output/image.d.ts +25 -0
- package/lib/output/image.js +941 -0
- package/lib/output/text.d.ts +6 -0
- package/lib/output/text.js +60 -0
- package/lib/types.d.ts +161 -0
- package/lib/types.js +2 -0
- package/lib/utils/player.d.ts +16 -0
- package/lib/utils/player.js +86 -0
- package/package.json +31 -0
- package/pic/Assassin's_Dagger_Icon.webp +0 -0
- package/pic/Balanced_Blade_Icon.webp +0 -0
- package/pic/Rusty_Sword_Icon.webp +0 -0
- package/pic/boss/347/273/206/350/203/236.webp +0 -0
- package/pic/mapandboss/Infested_Shipwreck.png +0 -0
- package/pic/mapandboss//344/270/215/346/255/273/346/265/267/346/273/251.webp +0 -0
- package/pic/mapandboss//344/273/206/344/272/272.webp +0 -0
- package/pic/mapandboss//344/275/234/345/221/225/345/234/260/347/252/226.webp +0 -0
- package/pic/mapandboss//345/233/275/347/216/213/344/271/213/346/211/213.webp +0 -0
- package/pic/mapandboss//345/241/224/351/241/266.webp +0 -0
- package/pic/mapandboss//345/242/223/345/234/260.webp +0 -0
- package/pic/mapandboss//345/243/201/345/236/222/357/274/210/345/234/272/346/231/257/357/274/211.webp +0 -0
- package/pic/mapandboss//345/244/232/347/234/274/346/200/252.webp +0 -0
- package/pic/mapandboss//345/244/247/346/241/245/345/256/210/345/215/253.webp +0 -0
- package/pic/mapandboss//345/244/247/347/234/274.webp +0 -0
- package/pic/mapandboss//345/245/263/347/216/213.webp +0 -0
- package/pic/mapandboss//345/256/210/346/212/244/350/200/205/347/232/204/345/261/205/346/211/200.webp +0 -0
- package/pic/mapandboss//345/261/261/345/267/205/345/237/216/345/240/241.webp +0 -0
- package/pic/mapandboss//345/261/261/346/264/236.webp +0 -0
- package/pic/mapandboss//345/264/251/345/235/217/347/245/236/345/272/231.webp +0 -0
- package/pic/mapandboss//345/267/242/347/251/264.webp +0 -0
- package/pic/mapandboss//345/267/250/344/272/272.webp +0 -0
- package/pic/mapandboss//345/272/237/345/274/203/351/205/277/351/205/222/345/216/202.webp +0 -0
- package/pic/mapandboss//346/224/266/350/227/217/345/256/266.webp +0 -0
- package/pic/mapandboss//346/227/247/344/270/213/346/260/264/351/201/223.webp +0 -0
- package/pic/mapandboss//346/227/266/351/222/237/345/256/244.webp +0 -0
- package/pic/mapandboss//346/227/266/351/227/264/345/256/210/346/212/244/350/200/205.webp +0 -0
- package/pic/mapandboss//346/234/211/347/275/252/350/200/205/347/232/204/345/244/247/351/201/223.webp +0 -0
- package/pic/mapandboss//346/262/211/347/235/241/345/272/207/346/212/244/346/211/200.webp +0 -0
- package/pic/mapandboss//347/201/257/345/241/224.webp +0 -0
- package/pic/mapandboss//347/211/242/346/210/277.webp +0 -0
- package/pic/mapandboss//347/214/233/346/257/222/344/270/213/346/260/264/351/201/223.webp +0 -0
- package/pic/mapandboss//347/216/213/345/272/247/344/271/213/351/227/264.webp +0 -0
- package/pic/mapandboss//347/233/221/347/213/261/346/267/261/345/244/204.webp +0 -0
- package/pic/mapandboss//347/250/273/350/215/211/344/272/272.webp +0 -0
- package/pic/mapandboss//350/205/220/345/214/226/347/211/242/346/210/277.webp +0 -0
- package/pic/mapandboss//350/215/222/345/272/237/346/244/215/347/211/251/345/233/255.webp +0 -0
- package/pic/mapandboss//350/227/217/351/252/250/345/240/202.webp +0 -0
- package/pic/mapandboss//350/242/253/345/274/203/350/200/205/346/262/274/346/263/275.webp +0 -0
- package/pic/mapandboss//350/242/253/351/201/227/345/277/230/347/232/204/351/231/265/345/242/223.webp +0 -0
- package/pic/mapandboss//350/247/202/346/230/237/345/217/260.webp +0 -0
- package/pic/mapandboss//350/247/202/346/230/237/345/256/236/351/252/214/346/211/200.webp +0 -0
- package/pic/mapandboss//351/222/237/346/245/274.webp +0 -0
- package/pic/mapandboss//351/230/264/346/243/256/345/242/223/345/233/255.webp +0 -0
- package/pic/mapandboss//351/233/276/350/220/246/346/270/257/346/271/276.webp +0 -0
- package/pic/mapandboss//351/273/221/350/211/262/345/244/247/346/241/245.webp +0 -0
- package/pic//344/275/215/347/247/273.webp +0 -0
- package/pic//345/206/260/344/271/213/345/274/223.webp +0 -0
- package/pic//345/206/260/345/206/273/346/211/213/351/233/267.webp +0 -0
- package/pic//345/207/273/346/231/225/347/233/276.webp +0 -0
- package/pic//345/211/215/347/272/277/347/233/276.webp +0 -0
- package/pic//345/212/233/345/234/272/347/233/276.png +0 -0
- package/pic//345/214/227/346/226/227/344/271/213/345/274/223.webp +0 -0
- package/pic//345/217/214/345/214/225/351/246/226.webp +0 -0
- package/pic//345/220/270/350/241/200.webp +0 -0
- package/pic//345/233/232/350/200/205/351/242/210/347/216/257.webp +0 -0
- package/pic//345/234/206/346/226/251/347/256/255/345/241/224.webp +0 -0
- package/pic//345/234/206/350/210/236/351/243/236/345/210/200.webp +0 -0
- package/pic//345/240/225/350/220/275/345/212/233/351/207/217.webp +0 -0
- package/pic//345/243/201/345/236/222/357/274/210/347/233/276/347/211/214/357/274/211.webp +0 -0
- package/pic//345/244/232/345/244/264/345/274/223.webp +0 -0
- package/pic//345/244/234/346/255/214.webp +0 -0
- package/pic//345/244/247/345/211/221.webp +0 -0
- package/pic//345/257/222/345/206/260/347/233/276.webp +0 -0
- package/pic//345/257/271/347/247/260/351/225/277/346/236/252.webp +0 -0
- package/pic//345/260/226/345/210/272/347/233/276.webp +0 -0
- package/pic//345/274/272/345/212/233/346/211/213/351/233/267.webp +0 -0
- package/pic//346/200/250/346/201/250/344/271/213/345/210/203.webp +0 -0
- package/pic//346/210/230/344/272/211/345/267/250/346/236/255.webp +0 -0
- package/pic//346/210/230/347/237/233.webp +0 -0
- package/pic//346/212/244/347/254/2461.webp +0 -0
- package/pic//346/212/244/347/254/2462.webp +0 -0
- package/pic//346/212/244/347/254/2463.webp +0 -0
- package/pic//346/212/244/347/254/2464.webp +0 -0
- package/pic//346/215/225/345/205/275/345/244/271.webp +0 -0
- package/pic//346/222/225/350/243/202/345/205/211/347/216/257.webp +0 -0
- package/pic//346/226/257/345/267/264/350/276/276/350/215/211/351/236/213.webp +0 -0
- package/pic//346/227/240/351/231/220/347/256/255/345/210/266/345/274/223.webp +0 -0
- package/pic//346/255/245/345/205/265/347/237/255/345/274/223.png +0 -0
- package/pic//346/255/246/345/243/253/345/210/200.webp +0 -0
- package/pic//347/210/206/347/202/270/345/215/201/345/255/227/345/274/223.png +0 -0
- package/pic//347/210/206/347/202/270/350/257/261/351/245/265.webp +0 -0
- package/pic//347/213/202/346/232/264/344/271/213/345/210/203.webp +0 -0
- package/pic//347/214/216/344/272/272/346/211/213/351/233/267.webp +0 -0
- package/pic//347/223/246/345/260/224/350/222/231/347/211/271/351/225/277/351/236/255.webp +0 -0
- package/pic//347/224/265/351/236/255.webp +0 -0
- package/pic//347/252/201/345/207/273/347/233/276.png +0 -0
- package/pic//347/274/240/347/273/225/351/236/255.webp +0 -0
- package/pic//350/200/201/346/234/250/347/233/276.webp +0 -0
- package/pic//350/203/241/346/241/203/345/244/271/345/255/220.webp +0 -0
- package/pic//350/241/200/344/271/213/345/210/203.webp +0 -0
- package/pic//350/241/200/347/223/266.webp +0 -0
- package/pic//350/257/205/345/222/222/344/271/213/345/210/203.webp +0 -0
- package/pic//350/264/252/345/251/252/347/233/276.png +0 -0
- package/pic//351/207/215/345/236/213/345/274/251/345/274/223.webp +0 -0
- package/pic//351/207/215/345/236/213/347/256/255/345/241/224.webp +0 -0
- package/pic//351/222/211/345/205/245/347/237/233.webp +0 -0
- package/pic//351/227/252/345/205/211/345/274/271.png +0 -0
- package/pic//351/227/252/347/224/265/345/205/211/346/235/237.webp +0 -0
- package/pic//351/232/274/344/271/213/351/235/264.webp +0 -0
- package/pic//351/233/206/346/235/237/346/211/213/351/233/267.webp +0 -0
- package/pic//351/243/236/345/210/200.webp +0 -0
- package/src/commands/alchemy.ts +58 -0
- package/src/commands/boss.ts +187 -0
- package/src/commands/character.ts +26 -0
- package/src/commands/duel.ts +173 -0
- package/src/commands/explore.ts +30 -0
- package/src/commands/forge.ts +64 -0
- package/src/commands/index.ts +20 -0
- package/src/commands/upgrade.ts +38 -0
- package/src/config.ts +53 -0
- package/src/core/battle.ts +705 -0
- package/src/core/boss.ts +201 -0
- package/src/core/exploration-dispatch.ts +114 -0
- package/src/core/exploration.ts +259 -0
- package/src/core/progression.ts +90 -0
- package/src/data/amulets.ts +112 -0
- package/src/data/equipment.ts +104 -0
- package/src/data/maps.ts +156 -0
- package/src/index.ts +70 -0
- package/src/output/forward.ts +15 -0
- package/src/output/image.ts +1006 -0
- package/src/output/text.ts +60 -0
- package/src/types.ts +169 -0
- package/src/utils/player.ts +81 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerAlchemyCommand = registerAlchemyCommand;
|
|
4
|
+
const amulets_1 = require("../data/amulets");
|
|
5
|
+
const player_1 = require("../utils/player");
|
|
6
|
+
const image_1 = require("../output/image");
|
|
7
|
+
function craftCount(value) {
|
|
8
|
+
if (value === undefined || value === null || value === '')
|
|
9
|
+
return 1;
|
|
10
|
+
const count = Number(value);
|
|
11
|
+
return Number.isInteger(count) && count >= 1 && count <= 5 ? count : undefined;
|
|
12
|
+
}
|
|
13
|
+
function registerAlchemyCommand(ctx, config, busy) {
|
|
14
|
+
ctx.command(`${config.commandAlchemy} [count:number]`)
|
|
15
|
+
.action(async ({ session }, countInput) => {
|
|
16
|
+
if (!session?.userId)
|
|
17
|
+
return '当前消息缺少用户身份,无法炼化护符。';
|
|
18
|
+
const count = craftCount(countInput);
|
|
19
|
+
if (!count)
|
|
20
|
+
return '护符炼化次数必须是 1-5 的整数。';
|
|
21
|
+
const player = await (0, player_1.getPlayer)(ctx, session.userId);
|
|
22
|
+
if (!player)
|
|
23
|
+
return '未找到用户数据哦,请先使用 deadcells 指令来创建角色!';
|
|
24
|
+
const totalCost = config.alchemyCost * count;
|
|
25
|
+
if (player.cells < totalCost)
|
|
26
|
+
return `当前细胞数不足,需要 ${totalCost} 个细胞才能炼化 ${count} 次。`;
|
|
27
|
+
if (busy.has(player.userId))
|
|
28
|
+
return '你当前正在进行其他操作,请稍后再试。';
|
|
29
|
+
busy.add(player.userId);
|
|
30
|
+
try {
|
|
31
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, { cells: player.cells - totalCost });
|
|
32
|
+
const generated = Array.from({ length: count }, () => (0, amulets_1.rollAmulet)(Math.random));
|
|
33
|
+
const selected = count === 1 ? generated[0] : undefined;
|
|
34
|
+
const card = config.enableImages
|
|
35
|
+
? selected
|
|
36
|
+
? await (0, image_1.renderAmuletCard)(ctx, player, selected, totalCost)
|
|
37
|
+
: await (0, image_1.renderAmuletChoicesCard)(ctx, player, generated, totalCost)
|
|
38
|
+
: undefined;
|
|
39
|
+
const text = count === 1
|
|
40
|
+
? `【护符炼化】已消耗 ${totalCost} 个细胞!\n新护符词条:${selected.traits.join('、')}\n回复 y 替换当前护符,其他内容或超时则放弃。`
|
|
41
|
+
: `【护符炼化】已消耗 ${totalCost} 个细胞,生成 ${count} 个护符候选!\n${generated.map((amulet, index) => `${index + 1}. 词条:${amulet.traits.join('、')}`).join('\n')}\n回复 1-${count} 选择护符,其他内容或超时则放弃。`;
|
|
42
|
+
if (card)
|
|
43
|
+
await session.send(card);
|
|
44
|
+
else
|
|
45
|
+
await session.send(text);
|
|
46
|
+
const answer = await session.prompt(config.equipmentConfirmTimeout * 1000);
|
|
47
|
+
const selectedIndex = count === 1 ? 0 : Number.parseInt(answer?.trim() || '', 10) - 1;
|
|
48
|
+
if (!Number.isInteger(selectedIndex) || selectedIndex < 0 || selectedIndex >= generated.length)
|
|
49
|
+
return count === 1 ? '已放弃替换,炼化护符消失。' : '未选择有效护符,炼化结果消失。';
|
|
50
|
+
const selectedAmulet = generated[selectedIndex];
|
|
51
|
+
if (count > 1) {
|
|
52
|
+
await session.send(`已选择第 ${selectedIndex + 1} 个护符(词条:${selectedAmulet.traits.join('、')}),回复 y 替换当前护符,其他内容或超时则放弃。`);
|
|
53
|
+
}
|
|
54
|
+
const confirmation = count === 1 ? answer : await session.prompt(config.equipmentConfirmTimeout * 1000);
|
|
55
|
+
if (!confirmation || !['y', 'yes'].includes(confirmation.trim().toLowerCase()))
|
|
56
|
+
return '已放弃替换,炼化护符消失。';
|
|
57
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, {
|
|
58
|
+
amuletId: selectedAmulet.id,
|
|
59
|
+
amuletTraits: (0, amulets_1.serializeAmuletTraits)(selectedAmulet.traits),
|
|
60
|
+
});
|
|
61
|
+
return '护符已替换成功!';
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
busy.delete(player.userId);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerBossCommand = registerBossCommand;
|
|
4
|
+
const boss_1 = require("../core/boss");
|
|
5
|
+
const exploration_dispatch_1 = require("../core/exploration-dispatch");
|
|
6
|
+
const amulets_1 = require("../data/amulets");
|
|
7
|
+
const image_1 = require("../output/image");
|
|
8
|
+
const player_1 = require("../utils/player");
|
|
9
|
+
const DIFFICULTY_NAMES = {
|
|
10
|
+
normal: '普通',
|
|
11
|
+
veteran: '历战',
|
|
12
|
+
'veteran-king': '历战王',
|
|
13
|
+
};
|
|
14
|
+
function choiceIndex(value, length) {
|
|
15
|
+
const index = Number.parseInt(value?.trim() || '', 10) - 1;
|
|
16
|
+
return Number.isInteger(index) && index >= 0 && index < length ? index : undefined;
|
|
17
|
+
}
|
|
18
|
+
function rankingForUser(rankings, userId, username, damage) {
|
|
19
|
+
const existing = rankings.find((item) => item.userId === userId);
|
|
20
|
+
if (existing) {
|
|
21
|
+
existing.damage += damage;
|
|
22
|
+
existing.username = username;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
rankings.push({ userId, username, damage });
|
|
26
|
+
}
|
|
27
|
+
return rankings;
|
|
28
|
+
}
|
|
29
|
+
function bossText(boss) {
|
|
30
|
+
const hp = Math.max(0, Math.round(boss.currentHp));
|
|
31
|
+
return `今日 Boss:【${boss.bossName}】(${boss.mapName},${DIFFICULTY_NAMES[boss.difficulty]})\nBoss 生命:${hp} / ${boss.maxHp}`;
|
|
32
|
+
}
|
|
33
|
+
async function sendBossCard(ctx, session, player, boss, result, rankings = (0, boss_1.parseBossRankings)(boss.rankings), completed = boss.completed) {
|
|
34
|
+
const card = await (0, image_1.renderBossRaidCard)(ctx, player, boss, result, rankings, completed);
|
|
35
|
+
if (card)
|
|
36
|
+
await session.send(card);
|
|
37
|
+
else {
|
|
38
|
+
const log = result?.events?.join('\n');
|
|
39
|
+
await session.send(`${bossText(boss)}${result ? `\n本次造成伤害:${result.damage}\n${log || ''}` : ''}${completed ? '\nBoss 已被讨伐。' : ''}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function settleBossChoice(ctx, config, session, player, state, firstAnswer) {
|
|
43
|
+
if (state.date !== (0, exploration_dispatch_1.beijingDate)() || Date.now() > state.expiresAt) {
|
|
44
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, { bossChoiceState: null });
|
|
45
|
+
return '词条选择已超时,Boss 最后一击奖励失效。';
|
|
46
|
+
}
|
|
47
|
+
const selectedIndex = choiceIndex(firstAnswer, state.choices.length);
|
|
48
|
+
if (selectedIndex === undefined)
|
|
49
|
+
return `请选择 1-${state.choices.length} 其中一个词条。`;
|
|
50
|
+
const selectedTrait = state.choices[selectedIndex];
|
|
51
|
+
const currentTraits = (0, amulets_1.parseAmuletTraits)(player.amuletTraits);
|
|
52
|
+
let nextTraits;
|
|
53
|
+
let amuletId = player.amuletId;
|
|
54
|
+
if (currentTraits.length >= 2) {
|
|
55
|
+
await session.send('请选择替换第几个护符词条:\n1. 词条1\n2. 词条2');
|
|
56
|
+
const slotAnswer = await session.prompt(config.equipmentConfirmTimeout * 1000);
|
|
57
|
+
if (!slotAnswer) {
|
|
58
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, { bossChoiceState: null });
|
|
59
|
+
return '词条选择已超时,Boss 最后一击奖励失效。';
|
|
60
|
+
}
|
|
61
|
+
if (!['1', '2'].includes(slotAnswer.trim()))
|
|
62
|
+
return '请选择 1 或 2 替换护符词条。';
|
|
63
|
+
nextTraits = [...currentTraits];
|
|
64
|
+
nextTraits[Number(slotAnswer.trim()) - 1] = selectedTrait;
|
|
65
|
+
}
|
|
66
|
+
else if (currentTraits.length === 1) {
|
|
67
|
+
nextTraits = [...currentTraits, selectedTrait];
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
amuletId = amuletId === 'prisoner-necklace' ? 'amulet-1' : amuletId;
|
|
71
|
+
nextTraits = [selectedTrait];
|
|
72
|
+
}
|
|
73
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, {
|
|
74
|
+
cells: player.cells + state.rewardCells,
|
|
75
|
+
amuletId,
|
|
76
|
+
amuletTraits: (0, amulets_1.serializeAmuletTraits)(nextTraits),
|
|
77
|
+
bossChoiceState: null,
|
|
78
|
+
});
|
|
79
|
+
const trait = (0, amulets_1.getAmuletTrait)(selectedTrait);
|
|
80
|
+
return `已获得 ${state.rewardCells} 个细胞,并装备词条【${trait?.name || selectedTrait}】。${currentTraits.length >= 2 ? '已替换选择的词条槽位。' : currentTraits.length === 1 ? '已装入第二个词条槽位。' : `已获得护符【${(0, amulets_1.getAmulet)(amuletId)?.name || '炼化护符'}】。`}`;
|
|
81
|
+
}
|
|
82
|
+
function registerBossCommand(ctx, config, busy) {
|
|
83
|
+
const raidLock = '__daily-boss-raid__';
|
|
84
|
+
const commandName = config.commandBoss || 'boss讨伐';
|
|
85
|
+
ctx.command(`${commandName} [choice:text]`)
|
|
86
|
+
.action(async ({ session }, choiceInput) => {
|
|
87
|
+
if (!session?.userId)
|
|
88
|
+
return '当前消息缺少用户身份,无法参加 Boss 讨伐。';
|
|
89
|
+
const player = await (0, player_1.getPlayer)(ctx, session.userId);
|
|
90
|
+
if (!player)
|
|
91
|
+
return '未找到用户数据哦,请先使用 deadcells 指令来创建角色!';
|
|
92
|
+
if (busy.has(player.userId))
|
|
93
|
+
return '你当前正在进行其他操作,请稍后再试。';
|
|
94
|
+
const pending = (0, boss_1.parseBossChoiceState)(player.bossChoiceState);
|
|
95
|
+
if (pending) {
|
|
96
|
+
busy.add(player.userId);
|
|
97
|
+
try {
|
|
98
|
+
let answer = choiceInput?.trim();
|
|
99
|
+
if (!answer) {
|
|
100
|
+
const boss = await (0, boss_1.getOrCreateDailyBoss)(ctx);
|
|
101
|
+
const card = config.enableImages ? await (0, image_1.renderBossTraitChoiceCard)(ctx, player, boss, pending.choices, pending.rewardCells, config.equipmentConfirmTimeout) : undefined;
|
|
102
|
+
if (card)
|
|
103
|
+
await session.send(card);
|
|
104
|
+
else
|
|
105
|
+
await session.send(`Boss 最后一击奖励:${pending.rewardCells} 个细胞\n${pending.choices.map((id, index) => `${index + 1}. ${(0, amulets_1.getAmuletTrait)(id)?.name || id}:${(0, amulets_1.getAmuletTrait)(id)?.description || ''}`).join('\n')}\n请回复 1-${pending.choices.length} 选择词条。`);
|
|
106
|
+
answer = await session.prompt(config.equipmentConfirmTimeout * 1000);
|
|
107
|
+
}
|
|
108
|
+
return settleBossChoice(ctx, config, session, player, pending, answer);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
busy.delete(player.userId);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const boss = await (0, boss_1.getOrCreateDailyBoss)(ctx);
|
|
115
|
+
if (boss.completed) {
|
|
116
|
+
await sendBossCard(ctx, session, player, boss, undefined, (0, boss_1.parseBossRankings)(boss.rankings), true);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (choiceInput?.trim())
|
|
120
|
+
return '当前没有待选择的 Boss 词条。';
|
|
121
|
+
if (Date.now() < player.lastBossRaidAt + config.bossRaidCooldownSeconds * 1000) {
|
|
122
|
+
const seconds = Math.ceil((player.lastBossRaidAt + config.bossRaidCooldownSeconds * 1000 - Date.now()) / 1000);
|
|
123
|
+
return `你还在 Boss 讨伐冷却中,请 ${seconds} 秒后再试。`;
|
|
124
|
+
}
|
|
125
|
+
if (busy.has(raidLock))
|
|
126
|
+
return '当前已有其他玩家正在讨伐今日 Boss,请稍后再试。';
|
|
127
|
+
busy.add(player.userId);
|
|
128
|
+
busy.add(raidLock);
|
|
129
|
+
let updatedBoss = boss;
|
|
130
|
+
try {
|
|
131
|
+
const result = (0, boss_1.simulateBossRaid)(player, boss, config);
|
|
132
|
+
const rankings = rankingForUser((0, boss_1.parseBossRankings)(boss.rankings), player.userId, player.username, result.damage);
|
|
133
|
+
const currentHp = Math.max(0, boss.currentHp - result.damage);
|
|
134
|
+
const killed = currentHp <= 0;
|
|
135
|
+
updatedBoss = {
|
|
136
|
+
...boss,
|
|
137
|
+
currentHp,
|
|
138
|
+
completed: killed,
|
|
139
|
+
killerId: killed ? player.userId : boss.killerId,
|
|
140
|
+
killerName: killed ? player.username : boss.killerName,
|
|
141
|
+
rankings: (0, boss_1.serializeBossRankings)(rankings),
|
|
142
|
+
};
|
|
143
|
+
await ctx.database.set('deadcells_daily_bosses', { date: boss.date }, {
|
|
144
|
+
currentHp: updatedBoss.currentHp,
|
|
145
|
+
completed: updatedBoss.completed,
|
|
146
|
+
killerId: updatedBoss.killerId,
|
|
147
|
+
killerName: updatedBoss.killerName,
|
|
148
|
+
rankings: updatedBoss.rankings,
|
|
149
|
+
});
|
|
150
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, { lastBossRaidAt: Date.now() });
|
|
151
|
+
const reward = (0, boss_1.calculateBossReward)(player, result.damage, boss.rewardMultiplier);
|
|
152
|
+
if (killed) {
|
|
153
|
+
const state = {
|
|
154
|
+
date: boss.date,
|
|
155
|
+
choices: (0, boss_1.randomTraitChoices)(Math.random),
|
|
156
|
+
rewardCells: reward,
|
|
157
|
+
expiresAt: Date.now() + config.equipmentConfirmTimeout * 1000,
|
|
158
|
+
};
|
|
159
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, { bossChoiceState: (0, boss_1.serializeBossChoiceState)(state) });
|
|
160
|
+
const resultPlayer = { ...player, lastBossRaidAt: Date.now(), bossChoiceState: (0, boss_1.serializeBossChoiceState)(state) };
|
|
161
|
+
await sendBossCard(ctx, session, resultPlayer, updatedBoss, result, rankings, true);
|
|
162
|
+
const card = config.enableImages ? await (0, image_1.renderBossTraitChoiceCard)(ctx, resultPlayer, updatedBoss, state.choices, reward, config.equipmentConfirmTimeout) : undefined;
|
|
163
|
+
if (card)
|
|
164
|
+
await session.send(card);
|
|
165
|
+
else
|
|
166
|
+
await session.send(`最后一击奖励:${reward} 个细胞\n${state.choices.map((id, index) => `${index + 1}. ${(0, amulets_1.getAmuletTrait)(id)?.name || id}:${(0, amulets_1.getAmuletTrait)(id)?.description || ''}`).join('\n')}\n请回复 1-${state.choices.length} 选择词条。`);
|
|
167
|
+
return settleBossChoice(ctx, config, session, resultPlayer, state, await session.prompt(config.equipmentConfirmTimeout * 1000));
|
|
168
|
+
}
|
|
169
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, { cells: player.cells + reward, bossChoiceState: null });
|
|
170
|
+
const resultPlayer = { ...player, cells: player.cells + reward, lastBossRaidAt: Date.now() };
|
|
171
|
+
await sendBossCard(ctx, session, resultPlayer, updatedBoss, result, rankings, false);
|
|
172
|
+
return `本次获得 ${reward} 个细胞。`;
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
busy.delete(player.userId);
|
|
176
|
+
busy.delete(raidLock);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerCharacterCommand = registerCharacterCommand;
|
|
4
|
+
const koishi_1 = require("koishi");
|
|
5
|
+
const text_1 = require("../output/text");
|
|
6
|
+
const image_1 = require("../output/image");
|
|
7
|
+
const player_1 = require("../utils/player");
|
|
8
|
+
function registerCharacterCommand(ctx, config) {
|
|
9
|
+
ctx.command(config.commandCharacter)
|
|
10
|
+
.action(async ({ session }) => {
|
|
11
|
+
if (!session?.userId)
|
|
12
|
+
return '当前消息缺少用户身份,无法创建角色。';
|
|
13
|
+
const userId = session.userId;
|
|
14
|
+
const username = session.username || userId;
|
|
15
|
+
const { player, created } = await (0, player_1.getOrCreatePlayer)(ctx, userId, username);
|
|
16
|
+
const prefix = created ? '未检测到数据,将创建角色……\n创建成功!' : '查询数据中……\n查到了!';
|
|
17
|
+
if (config.enableImages) {
|
|
18
|
+
const card = await (0, image_1.renderPlayerCard)(ctx, player);
|
|
19
|
+
if (card) {
|
|
20
|
+
return (0, koishi_1.h)('message', {}, [
|
|
21
|
+
(0, koishi_1.h)('text', { content: `${prefix}\n` }),
|
|
22
|
+
card,
|
|
23
|
+
]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return `${prefix}\n${(0, text_1.playerStatus)(player)}\n${(0, text_1.equipmentDescription)(player)}`;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerDuelCommand = registerDuelCommand;
|
|
4
|
+
const koishi_1 = require("koishi");
|
|
5
|
+
const equipment_1 = require("../data/equipment");
|
|
6
|
+
const amulets_1 = require("../data/amulets");
|
|
7
|
+
const battle_1 = require("../core/battle");
|
|
8
|
+
const player_1 = require("../utils/player");
|
|
9
|
+
const image_1 = require("../output/image");
|
|
10
|
+
function lockKeys(a, b) {
|
|
11
|
+
return [a, b].sort();
|
|
12
|
+
}
|
|
13
|
+
function registerDuelCommand(ctx, config, busy) {
|
|
14
|
+
ctx.command(`${config.commandDuel} <target:text>`)
|
|
15
|
+
.example(`${config.commandDuel} @用户`)
|
|
16
|
+
.action(async ({ session }, targetInput) => {
|
|
17
|
+
if (!session?.userId)
|
|
18
|
+
return '当前消息缺少用户身份,无法发起对战。';
|
|
19
|
+
const userId = session.userId;
|
|
20
|
+
const target = await (0, player_1.parseAtTarget)(session, targetInput || '');
|
|
21
|
+
if (!target)
|
|
22
|
+
return '请使用 @用户 指定对战目标。';
|
|
23
|
+
if (target.userId === userId)
|
|
24
|
+
return '不可以和自己对战。';
|
|
25
|
+
const keys = lockKeys(userId, target.userId);
|
|
26
|
+
if (keys.some((key) => busy.has(key)))
|
|
27
|
+
return '你或对方正在进行其他操作,请稍后再试。';
|
|
28
|
+
keys.forEach((key) => busy.add(key));
|
|
29
|
+
try {
|
|
30
|
+
const first = await (0, player_1.getPlayer)(ctx, userId);
|
|
31
|
+
const second = await (0, player_1.getPlayer)(ctx, target.userId);
|
|
32
|
+
if (!first)
|
|
33
|
+
return '未找到你的角色数据,请先使用 deadcells 指令创建角色。';
|
|
34
|
+
if (!second)
|
|
35
|
+
return `未找到 ${target.username} 的角色数据,对方需要先使用 deadcells 指令。`;
|
|
36
|
+
const remaining = Math.max((0, player_1.cooldownRemaining)(first.lastBattleAt, config.battleCooldownSeconds), (0, player_1.cooldownRemaining)(second.lastBattleAt, config.battleCooldownSeconds));
|
|
37
|
+
if (remaining > 0)
|
|
38
|
+
return `你或对方处于对战冷却中,还需等待 ${Math.ceil(remaining / 1000)} 秒。`;
|
|
39
|
+
const result = (0, battle_1.simulateBattle)(first, second, config);
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
const finalCells = new Map([
|
|
42
|
+
[result.attacker.userId, result.attacker.cells],
|
|
43
|
+
[result.defender.userId, result.defender.cells],
|
|
44
|
+
]);
|
|
45
|
+
await ctx.database.set('deadcells_players', { userId: first.userId }, {
|
|
46
|
+
cells: finalCells.get(first.userId) ?? first.cells,
|
|
47
|
+
battleCount: first.battleCount + 1,
|
|
48
|
+
winCount: first.winCount + (result.winnerId === first.userId ? 1 : 0),
|
|
49
|
+
lastBattleAt: now,
|
|
50
|
+
});
|
|
51
|
+
await ctx.database.set('deadcells_players', { userId: second.userId }, {
|
|
52
|
+
cells: finalCells.get(second.userId) ?? second.cells,
|
|
53
|
+
battleCount: second.battleCount + 1,
|
|
54
|
+
winCount: second.winCount + (result.winnerId === second.userId ? 1 : 0),
|
|
55
|
+
lastBattleAt: now,
|
|
56
|
+
});
|
|
57
|
+
const winner = result.winnerId === first.userId ? first : second;
|
|
58
|
+
const copied = result.droppedEquipment;
|
|
59
|
+
const equipment = copied && copied.type !== 'amulet'
|
|
60
|
+
? (0, equipment_1.getEquipment)(copied.id)
|
|
61
|
+
: !copied && Math.random() * 100 < config.equipmentDropRate
|
|
62
|
+
? (0, equipment_1.randomEquipment)(Math.random)
|
|
63
|
+
: undefined;
|
|
64
|
+
const copiedAmulet = copied?.type === 'amulet' ? copied : undefined;
|
|
65
|
+
let currentEquipment;
|
|
66
|
+
let autoEquipped = false;
|
|
67
|
+
if (equipment) {
|
|
68
|
+
const currentId = equipment.type === 'weapon'
|
|
69
|
+
? winner.weaponId
|
|
70
|
+
: equipment.type === 'offhand'
|
|
71
|
+
? winner.shieldId
|
|
72
|
+
: winner.item1Id || winner.item2Id;
|
|
73
|
+
currentEquipment = (0, equipment_1.getEquipment)(currentId);
|
|
74
|
+
const field = equipment.type === 'weapon'
|
|
75
|
+
? 'weaponId'
|
|
76
|
+
: equipment.type === 'offhand'
|
|
77
|
+
? 'shieldId'
|
|
78
|
+
: !winner.item1Id
|
|
79
|
+
? 'item1Id'
|
|
80
|
+
: !winner.item2Id
|
|
81
|
+
? 'item2Id'
|
|
82
|
+
: undefined;
|
|
83
|
+
const canAutoEquip = equipment.type === 'item'
|
|
84
|
+
? !winner.item1Id || !winner.item2Id
|
|
85
|
+
: !currentId;
|
|
86
|
+
if (field && canAutoEquip) {
|
|
87
|
+
await ctx.database.set('deadcells_players', { userId: winner.userId }, { [field]: equipment.id });
|
|
88
|
+
autoEquipped = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const battleCard = config.enableImages
|
|
92
|
+
? await (0, image_1.renderBattleCard)(ctx, first, second, result)
|
|
93
|
+
: undefined;
|
|
94
|
+
if (battleCard) {
|
|
95
|
+
await session.send(battleCard);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
await session.send(`${result.events.map((event) => event.text).join('\n')}\n【战斗结算】${winner.username} 获胜!获得细胞【${result.cellTransfer}】。`);
|
|
99
|
+
}
|
|
100
|
+
if (!equipment && !copiedAmulet)
|
|
101
|
+
return;
|
|
102
|
+
if (equipment) {
|
|
103
|
+
const prompt = equipment.type === 'item' && !autoEquipped
|
|
104
|
+
? '当前两个道具槽均有装备,回复 1 替换道具1,回复 2 替换道具2,其他内容或超时放弃。'
|
|
105
|
+
: undefined;
|
|
106
|
+
const equipmentCard = config.enableImages
|
|
107
|
+
? await (0, image_1.renderEquipmentDropCard)(ctx, winner, equipment, autoEquipped, currentEquipment, prompt)
|
|
108
|
+
: undefined;
|
|
109
|
+
if (equipmentCard) {
|
|
110
|
+
await session.send(equipmentCard);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
await session.send(`【装备获取】恭喜 ${koishi_1.h.at(winner.userId)} 获得装备【${equipment.name}】!\n${equipment.description}\n${autoEquipped ? '已自动装备。' : prompt || '回复 y 替换当前装备,其他内容或超时放弃。'}`);
|
|
114
|
+
}
|
|
115
|
+
if (autoEquipped)
|
|
116
|
+
return;
|
|
117
|
+
let field;
|
|
118
|
+
if (equipment.type === 'weapon')
|
|
119
|
+
field = 'weaponId';
|
|
120
|
+
else if (equipment.type === 'offhand')
|
|
121
|
+
field = 'shieldId';
|
|
122
|
+
else {
|
|
123
|
+
const answer = await new Promise((resolve) => {
|
|
124
|
+
let finished = false;
|
|
125
|
+
const dispose = ctx.on('message', (incoming) => {
|
|
126
|
+
if (incoming.userId !== winner.userId || incoming.channelId !== session.channelId)
|
|
127
|
+
return;
|
|
128
|
+
const value = incoming.content?.trim();
|
|
129
|
+
if (value !== '1' && value !== '2')
|
|
130
|
+
return;
|
|
131
|
+
finished = true;
|
|
132
|
+
dispose();
|
|
133
|
+
resolve(value);
|
|
134
|
+
});
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
if (finished)
|
|
137
|
+
return;
|
|
138
|
+
dispose();
|
|
139
|
+
resolve(undefined);
|
|
140
|
+
}, config.equipmentConfirmTimeout * 1000);
|
|
141
|
+
});
|
|
142
|
+
if (!answer)
|
|
143
|
+
return '已放弃替换,掉落装备消失。';
|
|
144
|
+
field = answer === '1' ? 'item1Id' : 'item2Id';
|
|
145
|
+
}
|
|
146
|
+
const accepted = equipment.type === 'item'
|
|
147
|
+
? true
|
|
148
|
+
: await (0, player_1.confirmFromUser)(ctx, session.channelId, winner.userId, config.equipmentConfirmTimeout * 1000);
|
|
149
|
+
if (!accepted)
|
|
150
|
+
return '已放弃替换,掉落装备消失。';
|
|
151
|
+
await ctx.database.set('deadcells_players', { userId: winner.userId }, { [field]: equipment.id });
|
|
152
|
+
return `装备已替换为【${equipment.name}】!`;
|
|
153
|
+
}
|
|
154
|
+
if (copiedAmulet) {
|
|
155
|
+
const traits = copiedAmulet.traits || [];
|
|
156
|
+
const amuletCard = config.enableImages
|
|
157
|
+
? await (0, image_1.renderAmuletDropCard)(ctx, winner, copiedAmulet.id, traits, false)
|
|
158
|
+
: undefined;
|
|
159
|
+
if (amuletCard) {
|
|
160
|
+
await session.send(amuletCard);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
const amulet = (0, amulets_1.getAmulet)(copiedAmulet.id);
|
|
164
|
+
await session.send(`【护符获取】${koishi_1.h.at(winner.userId)} 复制了【${amulet?.name || '炼化护符'}】及完整词条:${traits.join('、') || '无'}\n回复 y 替换当前护符,其他内容或超时放弃。`);
|
|
165
|
+
}
|
|
166
|
+
const accepted = await (0, player_1.confirmFromUser)(ctx, session.channelId, winner.userId, config.equipmentConfirmTimeout * 1000);
|
|
167
|
+
if (!accepted)
|
|
168
|
+
return '已放弃替换,复制的护符消失。';
|
|
169
|
+
await ctx.database.set('deadcells_players', { userId: winner.userId }, {
|
|
170
|
+
amuletId: copiedAmulet.id,
|
|
171
|
+
amuletTraits: (0, amulets_1.serializeAmuletTraits)(traits),
|
|
172
|
+
});
|
|
173
|
+
return '护符及其完整词条已复制并装备!';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
keys.forEach((key) => busy.delete(key));
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerExploreCommand = registerExploreCommand;
|
|
4
|
+
const player_1 = require("../utils/player");
|
|
5
|
+
const exploration_dispatch_1 = require("../core/exploration-dispatch");
|
|
6
|
+
function registerExploreCommand(ctx, config, busy) {
|
|
7
|
+
ctx.command(config.commandExplore)
|
|
8
|
+
.action(async ({ session }) => {
|
|
9
|
+
if (!session?.userId)
|
|
10
|
+
return '当前消息缺少用户身份,无法进行修炼。';
|
|
11
|
+
const userId = session.userId;
|
|
12
|
+
const player = await (0, player_1.getPlayer)(ctx, userId);
|
|
13
|
+
if (!player)
|
|
14
|
+
return '未找到用户数据哦,请先使用 deadcells 指令来创建角色!';
|
|
15
|
+
const status = (0, exploration_dispatch_1.dispatchStatus)(player);
|
|
16
|
+
if (status)
|
|
17
|
+
return status;
|
|
18
|
+
if (!(0, exploration_dispatch_1.dailyExploreAvailable)(player, config))
|
|
19
|
+
return `今日修炼结算次数已达到上限(${config.dailyExploreLimit}次),请明天再来。`;
|
|
20
|
+
if (busy.has(player.userId))
|
|
21
|
+
return '你当前正在进行其他操作,请稍后再试。';
|
|
22
|
+
busy.add(player.userId);
|
|
23
|
+
try {
|
|
24
|
+
await session.send('准备进行探索了!\n想要以什么方式进行探索呢?\n【1】更多细胞\n【2】更深层数');
|
|
25
|
+
const answer = await session.prompt(config.equipmentConfirmTimeout * 1000);
|
|
26
|
+
const strategy = answer?.trim() === '2' ? 'depth' : answer?.trim() === '1' ? 'cells' : undefined;
|
|
27
|
+
if (!strategy)
|
|
28
|
+
return '已取消探索或策略选择超时。';
|
|
29
|
+
await (0, exploration_dispatch_1.startExploration)(ctx, config, player, strategy, session.channelId, session.guildId);
|
|
30
|
+
return `开始探索了!\n当前在【被囚者的牢房】探索!\n当前策略【${strategy === 'cells' ? '更多细胞' : '更深层数'}】生效中!`;
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
busy.delete(player.userId);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerForgeCommand = registerForgeCommand;
|
|
4
|
+
const equipment_1 = require("../data/equipment");
|
|
5
|
+
const player_1 = require("../utils/player");
|
|
6
|
+
const image_1 = require("../output/image");
|
|
7
|
+
function choiceIndex(value, length) {
|
|
8
|
+
const index = Number.parseInt(value?.trim() || '', 10) - 1;
|
|
9
|
+
return Number.isInteger(index) && index >= 0 && index < length ? index : undefined;
|
|
10
|
+
}
|
|
11
|
+
function craftCount(value) {
|
|
12
|
+
if (value === undefined || value === null || value === '')
|
|
13
|
+
return 1;
|
|
14
|
+
const count = Number(value);
|
|
15
|
+
return Number.isInteger(count) && count >= 1 && count <= 5 ? count : undefined;
|
|
16
|
+
}
|
|
17
|
+
function registerForgeCommand(ctx, config, busy) {
|
|
18
|
+
ctx.command(`${config.commandForge} [count:number]`)
|
|
19
|
+
.action(async ({ session }, countInput) => {
|
|
20
|
+
if (!session?.userId)
|
|
21
|
+
return '当前消息缺少用户身份,无法锻造装备。';
|
|
22
|
+
const count = craftCount(countInput);
|
|
23
|
+
if (!count)
|
|
24
|
+
return '装备锻造次数必须是 1-5 的整数。';
|
|
25
|
+
const player = await (0, player_1.getPlayer)(ctx, session.userId);
|
|
26
|
+
if (!player)
|
|
27
|
+
return '未找到用户数据哦,请先使用 deadcells 指令来创建角色!';
|
|
28
|
+
const totalCost = config.forgeCost * count;
|
|
29
|
+
if (player.cells < totalCost)
|
|
30
|
+
return `当前细胞数不足,需要 ${totalCost} 个细胞才能锻造 ${count} 次。`;
|
|
31
|
+
if (busy.has(player.userId))
|
|
32
|
+
return '你当前正在进行其他操作,请稍后再试。';
|
|
33
|
+
busy.add(player.userId);
|
|
34
|
+
try {
|
|
35
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, { cells: player.cells - totalCost });
|
|
36
|
+
const choices = Array.from({ length: count }, () => (0, equipment_1.randomEquipmentChoices)(Math.random, 3)).flat();
|
|
37
|
+
const card = config.enableImages ? await (0, image_1.renderForgeCard)(ctx, player, choices, count, totalCost) : undefined;
|
|
38
|
+
if (card)
|
|
39
|
+
await session.send(card);
|
|
40
|
+
else
|
|
41
|
+
await session.send(`【装备锻造】已消耗 ${totalCost} 个细胞,生成 ${count} 组装备!\n${choices.map((item, index) => `第${Math.floor(index / 3) + 1}组-${index % 3 + 1}(总选项${index + 1})【${item.name}】(${(0, equipment_1.equipmentTypeText)(item.type)})${item.description}`).join('\n')}\n回复 1-${choices.length} 选择装备,其他内容放弃。`);
|
|
42
|
+
const selectedIndex = choiceIndex(await session.prompt(config.equipmentConfirmTimeout * 1000), choices.length);
|
|
43
|
+
if (selectedIndex === undefined)
|
|
44
|
+
return '已放弃锻造装备,消耗的细胞不返还。';
|
|
45
|
+
const selected = choices[selectedIndex];
|
|
46
|
+
let field;
|
|
47
|
+
if (selected.type === 'weapon')
|
|
48
|
+
field = 'weaponId';
|
|
49
|
+
else if (selected.type === 'offhand')
|
|
50
|
+
field = 'shieldId';
|
|
51
|
+
else {
|
|
52
|
+
if (!player.item1Id || !player.item2Id) {
|
|
53
|
+
field = !player.item1Id ? 'item1Id' : 'item2Id';
|
|
54
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, { [field]: selected.id });
|
|
55
|
+
return `已选择装备【${selected.name}】,当前存在空道具槽,已自动装备到${field === 'item1Id' ? '道具1' : '道具2'}!`;
|
|
56
|
+
}
|
|
57
|
+
await session.send(`已选择装备【${selected.name}】,请选择替换哪一个道具:\n1. 道具1:【${equipmentName(player.item1Id)}】\n2. 道具2:【${equipmentName(player.item2Id)}】\n请回复 1 或 2。`);
|
|
58
|
+
const slot = await session.prompt(config.equipmentConfirmTimeout * 1000);
|
|
59
|
+
if (!['1', '2'].includes(slot?.trim() || ''))
|
|
60
|
+
return '未选择有效道具槽位,锻造装备放弃。';
|
|
61
|
+
field = slot.trim() === '1' ? 'item1Id' : 'item2Id';
|
|
62
|
+
}
|
|
63
|
+
await ctx.database.set('deadcells_players', { userId: player.userId }, { [field]: selected.id });
|
|
64
|
+
return `已锻造并装备【${selected.name}】!`;
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
busy.delete(player.userId);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function equipmentName(id) {
|
|
72
|
+
return (0, equipment_1.getEquipment)(id)?.name || '无';
|
|
73
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerCommands = registerCommands;
|
|
4
|
+
const character_1 = require("./character");
|
|
5
|
+
const explore_1 = require("./explore");
|
|
6
|
+
const upgrade_1 = require("./upgrade");
|
|
7
|
+
const duel_1 = require("./duel");
|
|
8
|
+
const alchemy_1 = require("./alchemy");
|
|
9
|
+
const forge_1 = require("./forge");
|
|
10
|
+
const boss_1 = require("./boss");
|
|
11
|
+
function registerCommands(ctx, config) {
|
|
12
|
+
const busy = new Set();
|
|
13
|
+
(0, character_1.registerCharacterCommand)(ctx, config);
|
|
14
|
+
(0, explore_1.registerExploreCommand)(ctx, config, busy);
|
|
15
|
+
(0, upgrade_1.registerUpgradeCommand)(ctx, config, busy);
|
|
16
|
+
(0, duel_1.registerDuelCommand)(ctx, config, busy);
|
|
17
|
+
(0, alchemy_1.registerAlchemyCommand)(ctx, config, busy);
|
|
18
|
+
(0, forge_1.registerForgeCommand)(ctx, config, busy);
|
|
19
|
+
(0, boss_1.registerBossCommand)(ctx, config, busy);
|
|
20
|
+
}
|