koishi-plugin-maple-warriors 0.0.2 → 0.0.3
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/index.js +57 -53
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -34,13 +34,13 @@ var DEFAULT_PREY_DATA = [
|
|
|
34
34
|
"野兔 1 3-5 2-4 2-4 1-3 5-50"
|
|
35
35
|
];
|
|
36
36
|
var Config = import_koishi.Schema.object({
|
|
37
|
-
preyData: import_koishi.Schema.array(import_koishi.Schema.string()).role("table").default(DEFAULT_PREY_DATA).description("猎物数据,每行格式:猎物名 权重 体质 攻击
|
|
37
|
+
preyData: import_koishi.Schema.array(import_koishi.Schema.string()).role("table").default(DEFAULT_PREY_DATA).description("猎物数据,每行格式:猎物名 权重 体质 攻击 防御 暴击 敏捷(权重是固定数值,属性可以是固定数值或范围,如1-10)"),
|
|
38
38
|
battleMessageInterval: import_koishi.Schema.number().min(1).max(5).default(2).description("战斗消息发送间隔(秒)")
|
|
39
39
|
});
|
|
40
40
|
function calculateRates(character) {
|
|
41
41
|
const resistance = (character.toughness / (character.toughness + 90)).toFixed(4);
|
|
42
42
|
const critRate = (character.crit / (character.crit + 90)).toFixed(4);
|
|
43
|
-
const chargeTime = (1 +
|
|
43
|
+
const chargeTime = (1 + 720 / (character.agility + 80)).toFixed(2);
|
|
44
44
|
const dodgeRate = (0.2 * character.agility / (character.agility + 90)).toFixed(4);
|
|
45
45
|
return { resistance, critRate, chargeTime, dodgeRate };
|
|
46
46
|
}
|
|
@@ -233,7 +233,7 @@ function apply(ctx, config) {
|
|
|
233
233
|
等级: ${character.level}
|
|
234
234
|
体质: ${character.constitution} (HP: ${character.currentHp}/${character.maxHp})
|
|
235
235
|
攻击: ${character.attack}
|
|
236
|
-
|
|
236
|
+
防御: ${character.toughness} (韧性: ${(parseFloat(rates.resistance) * 100).toFixed(2)}%)
|
|
237
237
|
暴击: ${character.crit} (暴击率: ${(parseFloat(rates.critRate) * 100).toFixed(2)}%)
|
|
238
238
|
敏捷: ${character.agility} (蓄力: ${rates.chargeTime}s 闪避率: ${(parseFloat(rates.dodgeRate) * 100).toFixed(2)}%)
|
|
239
239
|
状态: ${character.status}${character.statusEndTime ? " 剩余" + formatRemainingTime(character.statusEndTime) : ""}
|
|
@@ -300,7 +300,7 @@ ${itemsText || "空空如也"}`;
|
|
|
300
300
|
}
|
|
301
301
|
__name(checkCharacterStatus, "checkCharacterStatus");
|
|
302
302
|
ctx.command("猫武士", "猫武士插件 - 帮助菜单");
|
|
303
|
-
ctx.command("猫武士/修改名字 <name>", "修改角色名字").example("修改名字
|
|
303
|
+
ctx.command("猫武士/修改名字 <name>", "修改角色名字").example("修改名字 火星").action(async ({ session }, name2) => {
|
|
304
304
|
if (!name2 || name2.trim().length === 0) {
|
|
305
305
|
return "格式错误!正确格式:修改名字 角色名";
|
|
306
306
|
}
|
|
@@ -343,27 +343,26 @@ ${itemsText || "空空如也"}`;
|
|
|
343
343
|
let character = await getOrCreateCharacter(userId);
|
|
344
344
|
return await formatCharacterInfo(character);
|
|
345
345
|
});
|
|
346
|
-
ctx.command("猫武士/训练
|
|
346
|
+
ctx.command("猫武士/训练 <...args>", "训练提升属性").example("训练 体质 体质 攻击").example("训练 体质").example("训练 随机").action(async ({ session }, ...args) => {
|
|
347
347
|
const userId = session.userId;
|
|
348
348
|
let character = await getOrCreateCharacter(userId);
|
|
349
|
-
const statusCheck = checkCharacterStatus(character);
|
|
350
|
-
if (!statusCheck.canAct) {
|
|
351
|
-
return statusCheck.message;
|
|
352
|
-
}
|
|
353
349
|
const today = getTodayDateString();
|
|
354
350
|
if (character.lastTrainDate && isSameDay(character.lastTrainDate, today)) {
|
|
355
351
|
return "今天已经训练过了,要注意劳逸结合哦!";
|
|
356
352
|
}
|
|
357
|
-
|
|
353
|
+
const statusCheck = checkCharacterStatus(character);
|
|
354
|
+
if (!statusCheck.canAct) {
|
|
355
|
+
return statusCheck.message;
|
|
356
|
+
}
|
|
357
|
+
if (args.length === 0) {
|
|
358
358
|
return "格式错误!正确格式:训练 属性1 属性2 属性3(可重复,若只指定一项,则其余两项随机提升)或 训练 随机";
|
|
359
359
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
const validAttrs2 = ["体质", "攻击", "韧性", "暴击", "敏捷"];
|
|
360
|
+
if (args.length === 1 && args[0] === "随机") {
|
|
361
|
+
const validAttrs2 = ["体质", "攻击", "防御", "暴击", "敏捷"];
|
|
363
362
|
const attrMap2 = {
|
|
364
363
|
"体质": "constitution",
|
|
365
364
|
"攻击": "attack",
|
|
366
|
-
"
|
|
365
|
+
"防御": "toughness",
|
|
367
366
|
"暴击": "crit",
|
|
368
367
|
"敏捷": "agility"
|
|
369
368
|
};
|
|
@@ -385,30 +384,30 @@ ${itemsText || "空空如也"}`;
|
|
|
385
384
|
return `训练成功!你好像领悟了什么……
|
|
386
385
|
${changes2.join(" ")}`;
|
|
387
386
|
}
|
|
388
|
-
if (
|
|
387
|
+
if (args.length > 3) {
|
|
389
388
|
return "只能指定3个属性(可以重复),不要太贪心哦!";
|
|
390
389
|
}
|
|
391
|
-
const validAttrs = ["体质", "攻击", "
|
|
390
|
+
const validAttrs = ["体质", "攻击", "防御", "暴击", "敏捷"];
|
|
392
391
|
const attrMap = {
|
|
393
392
|
"体质": "constitution",
|
|
394
393
|
"攻击": "attack",
|
|
395
|
-
"
|
|
394
|
+
"防御": "toughness",
|
|
396
395
|
"暴击": "crit",
|
|
397
396
|
"敏捷": "agility"
|
|
398
397
|
};
|
|
399
|
-
for (const attr of
|
|
398
|
+
for (const attr of args) {
|
|
400
399
|
if (!validAttrs.includes(attr)) {
|
|
401
400
|
return `属性名错误!有效的属性有:${validAttrs.join("、")}`;
|
|
402
401
|
}
|
|
403
402
|
}
|
|
404
403
|
const updates = {};
|
|
405
404
|
const attributeCounts = {};
|
|
406
|
-
for (const attr of
|
|
405
|
+
for (const attr of args) {
|
|
407
406
|
const field = attrMap[attr];
|
|
408
407
|
updates[field] = (updates[field] || character[field] || 0) + 1;
|
|
409
408
|
attributeCounts[attr] = (attributeCounts[attr] || 0) + 1;
|
|
410
409
|
}
|
|
411
|
-
for (let i = 0; i < 3 -
|
|
410
|
+
for (let i = 0; i < 3 - args.length; i++) {
|
|
412
411
|
const randomAttr = validAttrs[Math.floor(Math.random() * validAttrs.length)];
|
|
413
412
|
const field = attrMap[randomAttr];
|
|
414
413
|
updates[field] = (updates[field] || character[field] || 0) + 1;
|
|
@@ -450,7 +449,7 @@ ${changes.join(" ")}`;
|
|
|
450
449
|
const crit = parseAttributeRange(selectedPrey.crit);
|
|
451
450
|
const agility = parseAttributeRange(selectedPrey.agility);
|
|
452
451
|
const preyHp = constitution * 5;
|
|
453
|
-
const chargeTime = parseFloat((1 +
|
|
452
|
+
const chargeTime = parseFloat((1 + 720 / (agility + 80)).toFixed(2));
|
|
454
453
|
const prey = {
|
|
455
454
|
name: selectedPrey.name,
|
|
456
455
|
constitution,
|
|
@@ -474,7 +473,7 @@ ${changes.join(" ")}`;
|
|
|
474
473
|
await session.send(`发现猎物: ${prey.name}
|
|
475
474
|
体质: ${prey.constitution} (HP: ${prey.hp})
|
|
476
475
|
攻击: ${prey.attack}
|
|
477
|
-
|
|
476
|
+
防御: ${prey.toughness} (韧性: ${(parseFloat(preyRates.resistance) * 100).toFixed(2)}%)
|
|
478
477
|
暴击: ${prey.crit} (暴击率: ${(parseFloat(preyRates.critRate) * 100).toFixed(2)}%)
|
|
479
478
|
敏捷: ${prey.agility} (蓄力: ${preyRates.chargeTime}s 闪避率: ${(parseFloat(preyRates.dodgeRate) * 100).toFixed(2)}%)`);
|
|
480
479
|
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
@@ -489,7 +488,7 @@ ${changes.join(" ")}`;
|
|
|
489
488
|
agility: character.agility,
|
|
490
489
|
hp: character.currentHp,
|
|
491
490
|
maxHp: character.maxHp,
|
|
492
|
-
chargeTime: parseFloat((1 +
|
|
491
|
+
chargeTime: parseFloat((1 + 720 / (character.agility + 80)).toFixed(2)),
|
|
493
492
|
nextAttackTime: 0
|
|
494
493
|
};
|
|
495
494
|
await executeBattle(
|
|
@@ -517,6 +516,7 @@ ${changes.join(" ")}`;
|
|
|
517
516
|
const items = parseItemsString(character.items);
|
|
518
517
|
items[selectedPrey.name] = (items[selectedPrey.name] || 0) + 1;
|
|
519
518
|
updates.items = serializeItems(items);
|
|
519
|
+
await session.send(`捕猎成功!获得物品 ${selectedPrey.name}*1`);
|
|
520
520
|
}
|
|
521
521
|
}
|
|
522
522
|
await ctx.database.set("maple_warriors", { userId }, updates);
|
|
@@ -593,7 +593,7 @@ ${changes.join(" ")}`;
|
|
|
593
593
|
}
|
|
594
594
|
if (item.toughnessBonus) {
|
|
595
595
|
updates.toughness = character.toughness + item.toughnessBonus * count;
|
|
596
|
-
changes.push(
|
|
596
|
+
changes.push(`防御+${item.toughnessBonus * count}`);
|
|
597
597
|
}
|
|
598
598
|
if (item.critBonus) {
|
|
599
599
|
updates.crit = character.crit + item.critBonus * count;
|
|
@@ -663,6 +663,7 @@ ${changes.join(" ")}`;
|
|
|
663
663
|
});
|
|
664
664
|
}
|
|
665
665
|
battleManager.endBattle(channelId);
|
|
666
|
+
return;
|
|
666
667
|
} else {
|
|
667
668
|
return "当前没有正在进行的战斗。";
|
|
668
669
|
}
|
|
@@ -697,7 +698,7 @@ ${changes.join(" ")}`;
|
|
|
697
698
|
if (item.hpBonus) bonuses.push(`HP+${item.hpBonus}`);
|
|
698
699
|
if (item.constitutionBonus) bonuses.push(`体质+${item.constitutionBonus}`);
|
|
699
700
|
if (item.attackBonus) bonuses.push(`攻击+${item.attackBonus}`);
|
|
700
|
-
if (item.toughnessBonus) bonuses.push(
|
|
701
|
+
if (item.toughnessBonus) bonuses.push(`防御+${item.toughnessBonus}`);
|
|
701
702
|
if (item.critBonus) bonuses.push(`暴击+${item.critBonus}`);
|
|
702
703
|
if (item.agilityBonus) bonuses.push(`敏捷+${item.agilityBonus}`);
|
|
703
704
|
let result = `物品: ${item.name}
|
|
@@ -710,7 +711,7 @@ ${changes.join(" ")}`;
|
|
|
710
711
|
}
|
|
711
712
|
return result.trim();
|
|
712
713
|
});
|
|
713
|
-
ctx.command("猫武士/添加物品 <...args>", "添加或修改物品").example("添加物品 老鼠
|
|
714
|
+
ctx.command("猫武士/添加物品 <...args>", "添加或修改物品").example("添加物品 老鼠 hp 1 很常见的老鼠").example("添加物品 治疗药水 hp 10 恢复生命值").action(async ({ session }, ...args) => {
|
|
714
715
|
if (args.length < 1) {
|
|
715
716
|
return "格式错误!正确格式:添加物品 物品名 [属性 增加数 ...] [介绍]";
|
|
716
717
|
}
|
|
@@ -725,13 +726,13 @@ ${changes.join(" ")}`;
|
|
|
725
726
|
agilityBonus: 0
|
|
726
727
|
};
|
|
727
728
|
let i = 1;
|
|
728
|
-
const validAttrs = ["HP", "hp", "体质", "攻击", "
|
|
729
|
+
const validAttrs = ["HP", "hp", "体质", "攻击", "防御", "暴击", "敏捷"];
|
|
729
730
|
const attrMap = {
|
|
730
731
|
"HP": "hpBonus",
|
|
731
732
|
"hp": "hpBonus",
|
|
732
733
|
"体质": "constitutionBonus",
|
|
733
734
|
"攻击": "attackBonus",
|
|
734
|
-
"
|
|
735
|
+
"防御": "toughnessBonus",
|
|
735
736
|
"暴击": "critBonus",
|
|
736
737
|
"敏捷": "agilityBonus"
|
|
737
738
|
};
|
|
@@ -760,7 +761,7 @@ ${changes.join(" ")}`;
|
|
|
760
761
|
if (fieldName) {
|
|
761
762
|
updates[fieldName] = value;
|
|
762
763
|
} else {
|
|
763
|
-
return `属性名错误!有效的属性有:${["HP", "体质", "攻击", "
|
|
764
|
+
return `属性名错误!有效的属性有:${["HP", "体质", "攻击", "防御", "暴击", "敏捷"].join("、")}`;
|
|
764
765
|
}
|
|
765
766
|
i += 2;
|
|
766
767
|
}
|
|
@@ -771,7 +772,7 @@ ${changes.join(" ")}`;
|
|
|
771
772
|
description,
|
|
772
773
|
createdAt: /* @__PURE__ */ new Date()
|
|
773
774
|
});
|
|
774
|
-
return
|
|
775
|
+
return `修改物品成功!`;
|
|
775
776
|
} else {
|
|
776
777
|
await ctx.database.create("maple_warriors_items", {
|
|
777
778
|
name: itemName,
|
|
@@ -779,7 +780,7 @@ ${changes.join(" ")}`;
|
|
|
779
780
|
description,
|
|
780
781
|
createdAt: /* @__PURE__ */ new Date()
|
|
781
782
|
});
|
|
782
|
-
return
|
|
783
|
+
return `添加物品成功!`;
|
|
783
784
|
}
|
|
784
785
|
});
|
|
785
786
|
ctx.command("猫武士/物品列表 [page]", "查看物品列表").example("物品列表").example("物品列表 2").action(async ({ session }, page = "1") => {
|
|
@@ -819,13 +820,18 @@ ${changes.join(" ")}`;
|
|
|
819
820
|
ctx.command("猫武士/战斗训练 <target:user>", "与指定用户的角色进行训练战斗(不消耗HP)").example("战斗训练 @火星").action(async ({ session }, target) => {
|
|
820
821
|
const channelId = session.channelId;
|
|
821
822
|
const userId = session.userId;
|
|
823
|
+
let targetUserId = target;
|
|
824
|
+
if (target.includes(":")) {
|
|
825
|
+
const parts = target.split(":");
|
|
826
|
+
targetUserId = parts[parts.length - 1];
|
|
827
|
+
}
|
|
822
828
|
if (battleManager.isBattling(channelId)) {
|
|
823
829
|
return "请等待当前战斗结束!";
|
|
824
830
|
}
|
|
825
|
-
if (!
|
|
831
|
+
if (!targetUserId) {
|
|
826
832
|
return "请指定训练对手!正确格式:战斗训练 @用户名";
|
|
827
833
|
}
|
|
828
|
-
if (
|
|
834
|
+
if (targetUserId === userId) {
|
|
829
835
|
return "不能和自己进行战斗训练哦!";
|
|
830
836
|
}
|
|
831
837
|
let player1 = await getOrCreateCharacter(userId);
|
|
@@ -833,7 +839,11 @@ ${changes.join(" ")}`;
|
|
|
833
839
|
if (!statusCheck.canAct) {
|
|
834
840
|
return statusCheck.message;
|
|
835
841
|
}
|
|
836
|
-
let
|
|
842
|
+
let player2Characters = await ctx.database.get("maple_warriors", { userId: targetUserId });
|
|
843
|
+
if (player2Characters.length === 0) {
|
|
844
|
+
return "战斗失败!对方尚未生成角色";
|
|
845
|
+
}
|
|
846
|
+
let player2 = player2Characters[0];
|
|
837
847
|
const opponentStatusCheck = checkCharacterStatus(player2);
|
|
838
848
|
if (!opponentStatusCheck.canAct) {
|
|
839
849
|
return `对手目前状态不佳,无法进行战斗训练:${opponentStatusCheck.message}`;
|
|
@@ -851,7 +861,7 @@ ${changes.join(" ")}`;
|
|
|
851
861
|
hp: player1.currentHp,
|
|
852
862
|
// 使用当前HP
|
|
853
863
|
maxHp: player1.maxHp,
|
|
854
|
-
chargeTime: parseFloat((1 +
|
|
864
|
+
chargeTime: parseFloat((1 + 720 / (player1.agility + 80)).toFixed(2)),
|
|
855
865
|
nextAttackTime: 0
|
|
856
866
|
};
|
|
857
867
|
const player2Char = {
|
|
@@ -864,7 +874,7 @@ ${changes.join(" ")}`;
|
|
|
864
874
|
hp: player2.currentHp,
|
|
865
875
|
// 使用当前HP
|
|
866
876
|
maxHp: player2.maxHp,
|
|
867
|
-
chargeTime: parseFloat((1 +
|
|
877
|
+
chargeTime: parseFloat((1 + 720 / (player2.agility + 80)).toFixed(2)),
|
|
868
878
|
nextAttackTime: 0
|
|
869
879
|
};
|
|
870
880
|
const abortController = battleManager.getAbortController(channelId);
|
|
@@ -911,8 +921,8 @@ ${changes.join(" ")}`;
|
|
|
911
921
|
}
|
|
912
922
|
__name(apply, "apply");
|
|
913
923
|
async function executeBattle(session, player1, player2, battleMessageInterval, isTraining = false, abortController) {
|
|
914
|
-
const
|
|
915
|
-
const
|
|
924
|
+
const initialHp1 = player1.hp;
|
|
925
|
+
const initialHp2 = player2.hp;
|
|
916
926
|
const rates1 = calculateRates({
|
|
917
927
|
toughness: player1.toughness,
|
|
918
928
|
crit: player1.crit,
|
|
@@ -966,21 +976,18 @@ async function executeBattle(session, player1, player2, battleMessageInterval, i
|
|
|
966
976
|
}
|
|
967
977
|
const baseDamage = attacker.attack * (0.5 + Math.random());
|
|
968
978
|
let initialDamage = Math.ceil(baseDamage);
|
|
969
|
-
let totalDamage = initialDamage;
|
|
970
979
|
const attackerCritRate = attacker === player1 ? critRate1 : critRate2;
|
|
971
980
|
let isCritical = false;
|
|
972
981
|
if (Math.random() < attackerCritRate) {
|
|
973
|
-
|
|
982
|
+
initialDamage *= 2;
|
|
974
983
|
isCritical = true;
|
|
975
984
|
battleMessage += ` 暴击!`;
|
|
976
985
|
}
|
|
986
|
+
battleMessage += ` 造成了${initialDamage}点伤害。`;
|
|
977
987
|
const reduceAmount = defender.toughness * Math.random();
|
|
978
|
-
const reducedDamage = Math.min(Math.ceil(reduceAmount),
|
|
979
|
-
const finalDamage =
|
|
988
|
+
const reducedDamage = Math.min(Math.ceil(reduceAmount), initialDamage);
|
|
989
|
+
const finalDamage = initialDamage - reducedDamage;
|
|
980
990
|
if (finalDamage <= 0) {
|
|
981
|
-
if (isCritical) {
|
|
982
|
-
battleMessage += ` 造成了${totalDamage}点伤害。`;
|
|
983
|
-
}
|
|
984
991
|
battleMessage += ` 被${defender.name}抵挡住了!`;
|
|
985
992
|
await session.send(battleMessage);
|
|
986
993
|
currentTime = attackTime;
|
|
@@ -988,11 +995,6 @@ async function executeBattle(session, player1, player2, battleMessageInterval, i
|
|
|
988
995
|
}
|
|
989
996
|
defender.hp -= finalDamage;
|
|
990
997
|
if (defender.hp < 0) defender.hp = 0;
|
|
991
|
-
if (isCritical) {
|
|
992
|
-
battleMessage += ` 造成了${totalDamage}点伤害。`;
|
|
993
|
-
} else {
|
|
994
|
-
battleMessage += ` 造成了${initialDamage}点伤害。`;
|
|
995
|
-
}
|
|
996
998
|
battleMessage += ` ${defender.name}抵挡了${reducedDamage}点伤害,实际造成${finalDamage}点伤害。${defender.name} HP: ${defender.hp}`;
|
|
997
999
|
await session.send(battleMessage);
|
|
998
1000
|
if (defender.hp <= 0) {
|
|
@@ -1002,10 +1004,12 @@ async function executeBattle(session, player1, player2, battleMessageInterval, i
|
|
|
1002
1004
|
currentTime = attackTime;
|
|
1003
1005
|
}
|
|
1004
1006
|
if (currentTime > maxBattleTime && player1.hp > 0 && player2.hp > 0) {
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
+
const player1Loss = initialHp1 - player1.hp;
|
|
1008
|
+
const player2Loss = initialHp2 - player2.hp;
|
|
1009
|
+
if (player1Loss < player2Loss) {
|
|
1010
|
+
await session.send(`战斗超时!${player1.name} 损失HP较少,获得胜利!`);
|
|
1007
1011
|
} else if (player2.hp > player1.hp) {
|
|
1008
|
-
await session.send(`战斗超时!${player2.name}
|
|
1012
|
+
await session.send(`战斗超时!${player2.name} 损失HP较少,获得胜利!`);
|
|
1009
1013
|
} else {
|
|
1010
1014
|
await session.send(`战斗超时!双方平局!`);
|
|
1011
1015
|
}
|