koishi-plugin-smmcat-gensokyo 0.0.4 → 0.0.6

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/battle.d.ts CHANGED
@@ -82,6 +82,8 @@ export type BattleAttribute = {
82
82
  name: string;
83
83
  time: number;
84
84
  }[];
85
+ /** 持有技能 */
86
+ fn?: [];
85
87
  };
86
88
  /** 最后战斗状态 */
87
89
  type LastPlay = {
@@ -129,9 +131,22 @@ export declare const BattleData: {
129
131
  }): {
130
132
  over: boolean;
131
133
  type: string;
134
+ win: string;
132
135
  };
133
136
  /** 清理战场 */
134
137
  clearBattleData(session: Session): void;
135
- play(session: Session, atkType: "\u666E\u653B", select?: string): Promise<void>;
138
+ play(session: Session, atkType: string, select?: string): Promise<void>;
139
+ /** 结算奖励 */
140
+ settlement(tempData: {
141
+ self: BattleAttribute[];
142
+ goal: BattleAttribute[];
143
+ isPK?: boolean;
144
+ }, overInfo: {
145
+ over: boolean;
146
+ type: string;
147
+ win: string;
148
+ }, session: Session): Promise<void>;
136
149
  };
150
+ /** 获取阵容角色名 */
151
+ export declare function getLineupName(agent: BattleAttribute): string;
137
152
  export {};
package/lib/damage.d.ts CHANGED
@@ -10,7 +10,7 @@ type DamageCallback = {
10
10
  interface Callback {
11
11
  (data: DamageConfig): void;
12
12
  }
13
- type DamageConfig = {
13
+ export type DamageConfig = {
14
14
  agent: {
15
15
  self: BattleAttribute;
16
16
  goal: BattleAttribute;
@@ -48,4 +48,8 @@ declare class Damage {
48
48
  }
49
49
  /** 给予目标伤害 */
50
50
  declare function giveDamage(self: BattleAttribute, goal: BattleAttribute, damage: DamageConfig): number;
51
- export { Damage, giveDamage };
51
+ /** 治疗目标 */
52
+ declare function giveCure(goal: BattleAttribute, val: number): number;
53
+ /** 伤害额外信息 */
54
+ export declare function moreDamageInfo(damage: DamageConfig): string;
55
+ export { Damage, giveDamage, giveCure };
@@ -0,0 +1,57 @@
1
+ export declare enum MonsterOccupation {
2
+ 野怪 = "\u91CE\u602A",
3
+ BOSS = "BOSS"
4
+ }
5
+ export declare const monsterData: {
6
+ 小蜜蜂: {
7
+ name: string;
8
+ type: MonsterOccupation;
9
+ info: string;
10
+ hp: number;
11
+ maxHp: number;
12
+ mp: number;
13
+ maxMp: number;
14
+ atk: number;
15
+ def: number;
16
+ chr: number;
17
+ evasion: number;
18
+ hit: number;
19
+ ghd: number;
20
+ speed: number;
21
+ giveExp: number;
22
+ };
23
+ 小蜘蛛: {
24
+ name: string;
25
+ type: MonsterOccupation;
26
+ info: string;
27
+ hp: number;
28
+ maxHp: number;
29
+ mp: number;
30
+ maxMp: number;
31
+ atk: number;
32
+ def: number;
33
+ chr: number;
34
+ evasion: number;
35
+ hit: number;
36
+ ghd: number;
37
+ speed: number;
38
+ giveExp: number;
39
+ };
40
+ dora: {
41
+ name: string;
42
+ type: MonsterOccupation;
43
+ info: string;
44
+ hp: number;
45
+ maxHp: number;
46
+ mp: number;
47
+ maxMp: number;
48
+ atk: number;
49
+ def: number;
50
+ chr: number;
51
+ evasion: number;
52
+ hit: number;
53
+ ghd: number;
54
+ speed: number;
55
+ giveExp: number;
56
+ };
57
+ };
package/lib/index.js CHANGED
@@ -601,6 +601,103 @@ ${Object.keys(UserOccDict).map((i) => `【${i}】:${UserOccDict[i].info}`).join(
601
601
  【闪避值】${temp.evasion} (+0)
602
602
  【暴击率】${(temp.chr / 10).toFixed(1)}% (+0%)
603
603
  【暴击伤害】${(temp.ghd * 100).toFixed(1)}% (+0%)`;
604
+ },
605
+ /** 写入用户数据到数据库 */
606
+ async setDatabaseUserAttribute(userId) {
607
+ const userInfo = User.userTempData[userId];
608
+ if (!userInfo) return;
609
+ const temp = {
610
+ playName: userInfo.playName.trim(),
611
+ hp: userInfo.hp,
612
+ pp: userInfo.pp,
613
+ mp: userInfo.mp,
614
+ lv: userInfo.lv,
615
+ exp: userInfo.exp
616
+ };
617
+ User.ctx.database.set("smm_gensokyo_user_attribute", { userId }, temp);
618
+ },
619
+ /** 给予玩家经验 */
620
+ async giveExp(userId, value, fn) {
621
+ const userInfo = User.userTempData[userId];
622
+ if (!userInfo) return;
623
+ const beforData = { ...User.getUserAttributeByUserId(userId) };
624
+ let isUp = false;
625
+ userInfo.exp += value;
626
+ while (true) {
627
+ const { maxExp } = User.getUserAttributeByUserId(userId);
628
+ if (userInfo.exp < maxExp) break;
629
+ userInfo.lv += 1;
630
+ userInfo.exp -= maxExp;
631
+ isUp = true;
632
+ }
633
+ if (isUp) {
634
+ const afterData = User.getUserAttributeByUserId(userId);
635
+ const upTemp = {
636
+ name: afterData.playName,
637
+ lv: afterData.lv,
638
+ maxHp: afterData.maxHp - beforData.maxHp,
639
+ maxMp: afterData.maxMp = beforData.maxMp,
640
+ atk: afterData.atk - beforData.atk,
641
+ def: afterData.def - beforData.def
642
+ };
643
+ fn && await fn(upTemp);
644
+ }
645
+ await User.setDatabaseUserAttribute(userId);
646
+ }
647
+ };
648
+
649
+ // src/data/initMonster.ts
650
+ var monsterData = {
651
+ "小蜜蜂": {
652
+ name: "小蜜蜂",
653
+ type: "野怪" /* 野怪 */,
654
+ info: "幻想乡一层常见的生物",
655
+ hp: 50,
656
+ maxHp: 50,
657
+ mp: 30,
658
+ maxMp: 30,
659
+ atk: 7,
660
+ def: 2,
661
+ chr: 50,
662
+ evasion: 100,
663
+ hit: 1e3,
664
+ ghd: 1.2,
665
+ speed: 4,
666
+ giveExp: 10
667
+ },
668
+ "小蜘蛛": {
669
+ name: "小蜘蛛",
670
+ type: "野怪" /* 野怪 */,
671
+ info: "幻想乡一层常见的生物",
672
+ hp: 55,
673
+ maxHp: 55,
674
+ mp: 30,
675
+ maxMp: 30,
676
+ atk: 10,
677
+ def: 3,
678
+ chr: 50,
679
+ evasion: 200,
680
+ hit: 1e3,
681
+ ghd: 1.2,
682
+ speed: 4,
683
+ giveExp: 12
684
+ },
685
+ "dora": {
686
+ name: "dora",
687
+ type: "野怪" /* 野怪 */,
688
+ info: "偶尔出没在一层世界的奇怪生物",
689
+ hp: 88,
690
+ maxHp: 88,
691
+ mp: 10,
692
+ maxMp: 10,
693
+ atk: 20,
694
+ def: 5,
695
+ chr: 200,
696
+ evasion: 300,
697
+ hit: 1e3,
698
+ ghd: 1.2,
699
+ speed: 4,
700
+ giveExp: 15
604
701
  }
605
702
  };
606
703
 
@@ -636,12 +733,12 @@ var Monster = {
636
733
  autoInc: false
637
734
  }
638
735
  );
639
- const monsterData = await ctx.database.get("smm_gensokyo_monster_attribute", {});
640
- if (monsterData.length == 0) {
736
+ const monsterData2 = await ctx.database.get("smm_gensokyo_monster_attribute", {});
737
+ if (monsterData2.length == 0) {
641
738
  Monster.monsterTempData = Monster._createInitMonsterData();
642
739
  } else {
643
740
  const temp = {};
644
- monsterData.forEach((item) => {
741
+ monsterData2.forEach((item) => {
645
742
  temp[item.id] = item;
646
743
  });
647
744
  Monster.monsterTempData = temp;
@@ -649,56 +746,6 @@ var Monster = {
649
746
  },
650
747
  /** 赋予原始的怪物数据 */
651
748
  _createInitMonsterData() {
652
- const monsterData = {
653
- "小蜜蜂": {
654
- name: "小蜜蜂",
655
- type: "野怪" /* 野怪 */,
656
- info: "幻想乡一层常见的生物",
657
- hp: 50,
658
- maxHp: 50,
659
- mp: 30,
660
- maxMp: 30,
661
- atk: 7,
662
- def: 2,
663
- chr: 50,
664
- evasion: 100,
665
- hit: 1e3,
666
- ghd: 1.2,
667
- speed: 4
668
- },
669
- "小蜘蛛": {
670
- name: "小蜘蛛",
671
- type: "野怪" /* 野怪 */,
672
- info: "幻想乡一层常见的生物",
673
- hp: 55,
674
- maxHp: 55,
675
- mp: 30,
676
- maxMp: 30,
677
- atk: 10,
678
- def: 3,
679
- chr: 50,
680
- evasion: 200,
681
- hit: 1e3,
682
- ghd: 1.2,
683
- speed: 4
684
- },
685
- "dora": {
686
- name: "dora",
687
- type: "野怪" /* 野怪 */,
688
- info: "偶尔出没在一层世界的奇怪生物",
689
- hp: 88,
690
- maxHp: 88,
691
- mp: 10,
692
- maxMp: 10,
693
- atk: 20,
694
- def: 5,
695
- chr: 200,
696
- evasion: 300,
697
- hit: 1e3,
698
- ghd: 1.2,
699
- speed: 4
700
- }
701
- };
702
749
  return monsterData;
703
750
  },
704
751
  getMonsterAttributeData(monsterName, lv) {
@@ -800,7 +847,7 @@ var Damage = class {
800
847
  this.config = {
801
848
  agent: { self: { ...agent.self }, goal: { ...agent.goal } },
802
849
  harm: 0,
803
- default_harm: agent.self.atk + agent.self.gain.atk,
850
+ default_harm: 0,
804
851
  isRealHarm: realHarm,
805
852
  isEvasion: false,
806
853
  isCsp: false,
@@ -809,13 +856,14 @@ var Damage = class {
809
856
  }
810
857
  /** 伤害判定前 */
811
858
  before(fn) {
859
+ this.config.default_harm = this.config.agent.self.atk + this.config.agent.self.gain.atk;
812
860
  fn && fn(this.config);
813
861
  return this;
814
862
  }
815
863
  /** 真实伤害判定 */
816
864
  beforRealHarm(fn) {
817
865
  fn && fn(this.config);
818
- if (this.config.isEvasion) {
866
+ if (this.config.isRealHarm) {
819
867
  this.config.harm = this.config.default_harm;
820
868
  }
821
869
  return this;
@@ -825,7 +873,7 @@ var Damage = class {
825
873
  const { self, goal } = this.config.agent;
826
874
  if (this.config.isRealHarm) return this;
827
875
  const lvSup = /* @__PURE__ */ __name(() => Math.floor((goal.lv - self.lv) / 5) * 20, "lvSup");
828
- const evaVal = Math.min(95, (goal.evasion - (self.hit - 1e3) + lvSup()) / 10);
876
+ const evaVal = Math.min(95, (goal.evasion + goal.gain.evasion - (self.hit - 1e3) + lvSup()) / 10);
829
877
  if (random(0, 100) <= evaVal) {
830
878
  this.config.isEvasion = true;
831
879
  fn && fn(this.config);
@@ -839,10 +887,10 @@ var Damage = class {
839
887
  const { self, goal } = this.config.agent;
840
888
  if (this.config.isRealHarm) return this;
841
889
  if (this.config.isEvasion) return this;
842
- const cspVal = (self.chr - goal.csr) / 10;
890
+ const cspVal = (self.chr + self.gain.chr - goal.csr) / 10;
843
891
  if (random(0, 100) <= cspVal) {
844
892
  this.config.isCsp = true;
845
- this.config.harm = Math.floor(this.config.default_harm * self.ghd);
893
+ this.config.harm = Math.floor(this.config.default_harm * (self.ghd + self.gain.ghd));
846
894
  fn && fn(this.config);
847
895
  return this;
848
896
  }
@@ -855,7 +903,7 @@ var Damage = class {
855
903
  const { goal } = this.config.agent;
856
904
  if (this.config.isRealHarm) return this;
857
905
  if (this.config.isEvasion) return this;
858
- const dpVal = goal.def;
906
+ const dpVal = goal.def + goal.gain.def;
859
907
  fn && fn(this.config);
860
908
  if (this.config.harm - dpVal > 0) {
861
909
  this.config.harm -= dpVal;
@@ -891,6 +939,142 @@ function giveDamage(self, goal, damage) {
891
939
  }
892
940
  }
893
941
  __name(giveDamage, "giveDamage");
942
+ function giveCure(goal, val) {
943
+ const upVal = goal.hp + val;
944
+ if (upVal < goal.maxHp + goal.gain.maxHp) {
945
+ goal.hp = upVal;
946
+ return val;
947
+ } else {
948
+ const abHp = goal.maxHp + goal.gain.maxHp - goal.hp;
949
+ goal.hp += abHp;
950
+ return abHp;
951
+ }
952
+ }
953
+ __name(giveCure, "giveCure");
954
+ function moreDamageInfo(damage) {
955
+ return (damage.isCsp ? `(暴击!)` : "") + (damage.isEvasion ? `(闪避成功!)` : "") + (damage.isBadDef ? `(未破防!)` : "");
956
+ }
957
+ __name(moreDamageInfo, "moreDamageInfo");
958
+
959
+ // src/skillFn.ts
960
+ var skillFn = {
961
+ "重砍": {
962
+ name: "重砍",
963
+ type: "伤害技" /* 伤害技 */,
964
+ info: "[伤害技]消耗10MP,对敌方一个单位造成基于攻击力1.2倍伤害。该次伤害无视敌方30%防御!(最低无视1防御)",
965
+ lv: 3,
966
+ mp: 10,
967
+ feature: ["剑士" /* 剑士 */],
968
+ fn: /* @__PURE__ */ __name(function(agent, agentList, fn) {
969
+ const damageData = new Damage(agent).result({
970
+ before: /* @__PURE__ */ __name((val) => {
971
+ val.default_harm += Math.floor(val.default_harm * 0.2);
972
+ val.agent.goal.def -= Math.floor(val.agent.goal.def * 0.3) || 1;
973
+ }, "before")
974
+ });
975
+ fn({
976
+ damage: damageData,
977
+ type: this.type,
978
+ target: [agent.goal],
979
+ isNext: false
980
+ });
981
+ return `${getLineupName(agent.self)} 释放重砍,对 ${getLineupName(agent.goal)} 造成 ${damageData.harm} 伤害。` + moreDamageInfo(damageData);
982
+ }, "fn")
983
+ },
984
+ "突刺": {
985
+ name: "突刺",
986
+ type: "伤害技" /* 伤害技 */,
987
+ info: "[伤害技]消耗10MP,对敌方一个单位造成基于攻击力1.2倍伤害,该伤害无视敌方闪避10%",
988
+ lv: 3,
989
+ mp: 10,
990
+ feature: ["刺客" /* 刺客 */],
991
+ fn: /* @__PURE__ */ __name(function(agent, agentList, fn) {
992
+ const damageData = new Damage(agent).result({
993
+ before: /* @__PURE__ */ __name((val) => {
994
+ val.default_harm += Math.floor(val.default_harm * 0.2);
995
+ val.agent.goal.evasion -= Math.floor((val.agent.goal.evasion + val.agent.goal.gain.evasion) * 0.1);
996
+ }, "before")
997
+ });
998
+ fn({
999
+ damage: damageData,
1000
+ type: this.type,
1001
+ target: [agent.goal],
1002
+ isNext: false
1003
+ });
1004
+ return `${getLineupName(agent.self)} 释放突刺,对 ${getLineupName(agent.goal)} 造成 ${damageData.harm} 伤害。` + moreDamageInfo(damageData);
1005
+ }, "fn")
1006
+ },
1007
+ "水炮": {
1008
+ name: "水炮",
1009
+ type: "伤害技" /* 伤害技 */,
1010
+ info: "[伤害技]消耗10MP,通过凝集魔力对敌方造成基于攻击力1.2倍伤害,该伤害基于当前剩余魔法值10%额外叠加伤害。",
1011
+ lv: 3,
1012
+ mp: 10,
1013
+ feature: ["法师" /* 法师 */],
1014
+ fn: /* @__PURE__ */ __name(function(agent, agentList, fn) {
1015
+ const damageData = new Damage(agent).result({
1016
+ before: /* @__PURE__ */ __name((val) => {
1017
+ val.default_harm += Math.floor(val.default_harm * 0.2) + Math.floor(val.agent.self.mp * 0.1);
1018
+ }, "before")
1019
+ });
1020
+ fn({
1021
+ damage: damageData,
1022
+ type: this.type,
1023
+ target: [agent.goal],
1024
+ isNext: false
1025
+ });
1026
+ return `${getLineupName(agent.self)} 释放水炮,对 ${getLineupName(agent.goal)} 造成 ${damageData.harm} 伤害。` + moreDamageInfo(damageData);
1027
+ }, "fn")
1028
+ },
1029
+ "濒死一击": {
1030
+ name: "濒死一击",
1031
+ type: "伤害技" /* 伤害技 */,
1032
+ info: "[伤害技]血量低于40%可释放,消耗20MP,对敌方一个单位造成基于攻击力2倍伤害。该次伤害暴击率提高20%",
1033
+ lv: 3,
1034
+ mp: 20,
1035
+ fn: /* @__PURE__ */ __name(function(agent, agentList, fn) {
1036
+ if (agent.self.hp / (agent.self.maxHp + agent.self.gain.maxHp) < 0.4) {
1037
+ const damageData = new Damage(agent).result({
1038
+ before: /* @__PURE__ */ __name((val) => {
1039
+ val.default_harm += val.default_harm;
1040
+ val.agent.self.chr += 200;
1041
+ }, "before")
1042
+ });
1043
+ fn({
1044
+ damage: damageData,
1045
+ type: this.type,
1046
+ target: [agent.goal],
1047
+ isNext: false
1048
+ });
1049
+ return `${getLineupName(agent.self)} 释放濒死一击,对 ${getLineupName(agent.goal)} 造成 ${damageData.harm} 伤害。` + moreDamageInfo(damageData);
1050
+ } else {
1051
+ fn({
1052
+ type: "释放失败" /* 释放失败 */,
1053
+ isNext: true,
1054
+ err: "释放失败,未达成条件。"
1055
+ });
1056
+ return ``;
1057
+ }
1058
+ }, "fn")
1059
+ },
1060
+ "初级治愈": {
1061
+ name: "初级治愈",
1062
+ type: "治疗技" /* 治疗技 */,
1063
+ info: "[治疗技]直接恢复自身或者目标 40HP",
1064
+ lv: 1,
1065
+ mp: 30,
1066
+ fn: /* @__PURE__ */ __name(function(agent, agentList, fn) {
1067
+ const selectGoal = agent.goal;
1068
+ fn({
1069
+ value: 40,
1070
+ target: [selectGoal],
1071
+ type: "治疗技" /* 治疗技 */,
1072
+ isNext: false
1073
+ });
1074
+ return `${getLineupName(agent.self)}释放初级治愈,${getLineupName(agent.goal)}恢复40HP`;
1075
+ }, "fn")
1076
+ }
1077
+ };
894
1078
 
895
1079
  // src/battle.ts
896
1080
  var BattleData = {
@@ -921,8 +1105,12 @@ var BattleData = {
921
1105
  // 返回队伍信息
922
1106
  teamListByUser(userId) {
923
1107
  const teamList = [];
1108
+ if (!BattleData.teamTemp[userId]) {
1109
+ return [];
1110
+ }
1111
+ const _userId = BattleData.teamTemp[userId].for;
924
1112
  Object.keys(BattleData.teamTemp).forEach((item) => {
925
- if (BattleData.teamTemp[item].for == userId) {
1113
+ if (BattleData.teamTemp[item].for == _userId) {
926
1114
  teamList.push(User.getUserAttributeByUserId(item));
927
1115
  }
928
1116
  });
@@ -1024,7 +1212,8 @@ var BattleData = {
1024
1212
  team.self.forEach((item) => {
1025
1213
  if (item.hp > 0) {
1026
1214
  selfTemp.push(`lv.${item.lv}[${item.name}]:
1027
- ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${item.maxHp + item.gain.maxHp})`);
1215
+ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${item.maxHp + item.gain.maxHp})
1216
+ MP:${item.mp}/${item.maxMp + item.gain.maxMp}`);
1028
1217
  } else {
1029
1218
  selfTemp.push(`lv.${item.lv}[${item.name}]:已阵亡`);
1030
1219
  }
@@ -1032,7 +1221,8 @@ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${ite
1032
1221
  team.goal.forEach((item) => {
1033
1222
  if (item.hp > 0) {
1034
1223
  goalTemp.push(`lv.${item.lv}[${item.name}]:
1035
- ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${item.maxHp + item.gain.maxHp})`);
1224
+ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${item.maxHp + item.gain.maxHp})
1225
+ MP:${item.mp}/${item.maxMp + item.gain.maxMp}`);
1036
1226
  } else {
1037
1227
  goalTemp.push(`lv.${item.lv}[${item.name}]:已阵亡`);
1038
1228
  }
@@ -1051,13 +1241,13 @@ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${ite
1051
1241
  const self = team.self.every((item) => item.hp <= 0);
1052
1242
  const goal = team.goal.every((item) => item.hp <= 0);
1053
1243
  if (self && goal) {
1054
- return { over: true, type: "平局" };
1244
+ return { over: true, type: "平局", win: "" };
1055
1245
  } else if (self) {
1056
- return { over: true, type: team.isPK ? "敌方赢" : "防御方赢" };
1246
+ return { over: true, type: team.isPK ? "防御方赢" : "敌方赢", win: "goal" };
1057
1247
  } else if (goal) {
1058
- return { over: true, type: team.isPK ? "我方赢" : "攻击方赢" };
1248
+ return { over: true, type: team.isPK ? "攻击方赢" : "我方赢", win: "self" };
1059
1249
  }
1060
- return { over: false, type: "未结束" };
1250
+ return { over: false, type: "未结束", win: "" };
1061
1251
  },
1062
1252
  /** 清理战场 */
1063
1253
  clearBattleData(session) {
@@ -1084,27 +1274,79 @@ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${ite
1084
1274
  for (const agent of allAgentList) {
1085
1275
  if (agent.hp <= 0) continue;
1086
1276
  let lifeGoalList = [];
1277
+ let lifeSelfList = [];
1087
1278
  if (agent.for == "self") {
1088
1279
  lifeGoalList = currentBattle.goal.filter((item) => item.for == "goal" && item.hp > 0);
1280
+ lifeSelfList = currentBattle.self.filter((item) => item.for == "self" && item.hp > 0);
1089
1281
  } else {
1090
1282
  lifeGoalList = currentBattle.self.filter((item) => item.for == "self" && item.hp > 0);
1283
+ lifeSelfList = currentBattle.goal.filter((item) => item.for == "goal" && item.hp > 0);
1091
1284
  }
1092
1285
  if (!lifeGoalList.length) continue;
1093
1286
  let selectGoal = {};
1094
1287
  let isMy = false;
1288
+ let funType = "普攻";
1095
1289
  if (agent.type == "玩家" && agent.userId == session.userId) {
1096
1290
  isMy = true;
1291
+ funType = atkType;
1097
1292
  selectGoal = lifeGoalList.find((item) => item.name == select) || lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1098
1293
  } else if (agent.type == "玩家") {
1099
1294
  selectGoal = lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1100
1295
  } else {
1101
1296
  selectGoal = lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1102
1297
  }
1103
- const damageInfo = new Damage({ self: agent, goal: selectGoal }).result();
1104
- giveDamage(agent, selectGoal, damageInfo);
1105
- msgList.push(
1106
- `[${agent.type}]${agent.name} 使用普攻攻击了 [${selectGoal.type}]${selectGoal.name},造成了${damageInfo.harm}伤害。` + (damageInfo.isCsp ? `(暴击!)` : "") + (damageInfo.isEvasion ? `(闪避成功!)` : "") + (damageInfo.isBadDef ? `(未破防!)` : "")
1107
- );
1298
+ const noralAtk = /* @__PURE__ */ __name(() => {
1299
+ const damageInfo = new Damage({ self: agent, goal: selectGoal }).result();
1300
+ giveDamage(agent, selectGoal, damageInfo);
1301
+ msgList.push(
1302
+ `${getLineupName(agent)} 使用普攻攻击了 ${getLineupName(selectGoal)},造成了${damageInfo.harm}伤害。` + moreDamageInfo(damageInfo)
1303
+ );
1304
+ }, "noralAtk");
1305
+ if (funType == "普攻") {
1306
+ noralAtk();
1307
+ } else {
1308
+ if (skillFn[atkType]) {
1309
+ if (["治疗技" /* 治疗技 */, "增益技" /* 增益技 */].includes(skillFn[atkType].type)) {
1310
+ selectGoal = lifeSelfList.find((item) => item.name == select) || agent;
1311
+ }
1312
+ const selectFn = skillFn[atkType];
1313
+ if (selectFn.mp == 0 || agent.mp - selectFn.mp >= 0) {
1314
+ agent.mp -= selectFn.mp;
1315
+ let isNext = false;
1316
+ const fnMsg = selectFn.fn(
1317
+ { self: agent, goal: selectGoal },
1318
+ { selfList: lifeSelfList, goalList: lifeGoalList },
1319
+ (val) => {
1320
+ switch (val.type) {
1321
+ case "伤害技" /* 伤害技 */:
1322
+ val.target.map((goal) => {
1323
+ giveDamage(agent, goal, val.damage);
1324
+ });
1325
+ break;
1326
+ case "治疗技" /* 治疗技 */:
1327
+ val.target.map((goal) => {
1328
+ giveCure(goal, val.value);
1329
+ });
1330
+ break;
1331
+ case "释放失败" /* 释放失败 */:
1332
+ val.err && session.send(val.err);
1333
+ default:
1334
+ break;
1335
+ }
1336
+ isNext = val.isNext;
1337
+ }
1338
+ );
1339
+ fnMsg && msgList.push(fnMsg);
1340
+ isNext && noralAtk();
1341
+ } else {
1342
+ await session.send(`MP不足,释放失败!`);
1343
+ noralAtk();
1344
+ }
1345
+ } else {
1346
+ await session.send(`未持有该技能或者该技能不存在,释放失败!`);
1347
+ noralAtk();
1348
+ }
1349
+ }
1108
1350
  }
1109
1351
  await session.send(msgList.length ? `战斗记录:
1110
1352
  ` + msgList.join("\n") : "");
@@ -1112,10 +1354,61 @@ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${ite
1112
1354
  const result = BattleData.playOver(currentBattle);
1113
1355
  if (result.over) {
1114
1356
  await session.send(result.type);
1357
+ await BattleData.settlement(currentBattle, result, session);
1115
1358
  BattleData.clearBattleData(session);
1116
1359
  }
1360
+ },
1361
+ /** 结算奖励 */
1362
+ async settlement(tempData, overInfo, session) {
1363
+ const selfList = tempData.self.filter((item) => item.type == "玩家");
1364
+ const goalList = tempData.goal.filter((item) => item.type == "玩家");
1365
+ const msg = /* @__PURE__ */ __name(async (val) => {
1366
+ const msgTemp = `${val.name}[升级]${val.lv}级!
1367
+ ` + (val.atk ? `攻击力↑ ${val.atk}
1368
+ ` : "") + (val.def ? `防御力↑ ${val.def}
1369
+ ` : "") + (val.maxHp ? `最大血量↑ ${val.maxHp}
1370
+ ` : "") + (val.maxMp ? `最大蓝量↑ ${val.maxMp}` : "");
1371
+ await session.send(msgTemp);
1372
+ }, "msg");
1373
+ const aynchronize = /* @__PURE__ */ __name((agent) => {
1374
+ User.userTempData[agent.userId].hp = agent.hp;
1375
+ User.userTempData[agent.userId].mp = agent.mp;
1376
+ }, "aynchronize");
1377
+ if (tempData.isPK) {
1378
+ if (overInfo.win == "self") {
1379
+ await session.send("攻击方获得20EXP");
1380
+ for (const agent of selfList) {
1381
+ aynchronize(agent);
1382
+ await User.giveExp(agent.userId, 20, async (val) => await msg(val));
1383
+ }
1384
+ } else if (overInfo.win == "goal") {
1385
+ await session.send("防御方获得20EXP");
1386
+ for (const agent of goalList) {
1387
+ aynchronize(agent);
1388
+ await User.giveExp(agent.userId, 20, async (val) => await msg(val));
1389
+ }
1390
+ }
1391
+ } else {
1392
+ let val = 0;
1393
+ const monsterName = tempData.goal.filter((item) => item.type == "怪物").map((i) => ({ name: i.name, lv: i.lv }));
1394
+ monsterName.forEach((item) => {
1395
+ const monster = Monster.monsterTempData[item.name];
1396
+ if (monster[item.name]) {
1397
+ val += monster[item.name].giveExp + monster[item.name].giveExp * (monster[item.name].lv - 1) * 0.2;
1398
+ }
1399
+ });
1400
+ for (const agent of selfList) {
1401
+ aynchronize(agent);
1402
+ await session.send(`小队获得${val}EXP`);
1403
+ await User.giveExp(agent.userId, val, async (val2) => await msg(val2));
1404
+ }
1405
+ }
1117
1406
  }
1118
1407
  };
1408
+ function getLineupName(agent) {
1409
+ return `[${agent.type}]${agent.name}`;
1410
+ }
1411
+ __name(getLineupName, "getLineupName");
1119
1412
  function initBattleAttribute(data) {
1120
1413
  if ("playName" in data) {
1121
1414
  const userData = data;
@@ -1147,27 +1440,28 @@ function initBattleAttribute(data) {
1147
1440
  hit: 0,
1148
1441
  speed: 0
1149
1442
  },
1150
- buff: []
1443
+ buff: [],
1444
+ fn: []
1151
1445
  };
1152
1446
  return temp;
1153
1447
  } else {
1154
- const monsterData = data;
1448
+ const monsterData2 = data;
1155
1449
  const temp = {
1156
- name: monsterData.name,
1450
+ name: monsterData2.name,
1157
1451
  type: "怪物",
1158
- lv: monsterData.lv,
1159
- hp: monsterData.hp,
1160
- maxHp: monsterData.maxHp,
1161
- mp: monsterData.mp,
1162
- maxMp: monsterData.maxMp,
1163
- atk: monsterData.atk,
1164
- def: monsterData.def,
1165
- chr: monsterData.chr,
1166
- ghd: monsterData.ghd,
1452
+ lv: monsterData2.lv,
1453
+ hp: monsterData2.hp,
1454
+ maxHp: monsterData2.maxHp,
1455
+ mp: monsterData2.mp,
1456
+ maxMp: monsterData2.maxMp,
1457
+ atk: monsterData2.atk,
1458
+ def: monsterData2.def,
1459
+ chr: monsterData2.chr,
1460
+ ghd: monsterData2.ghd,
1167
1461
  csr: 0,
1168
- evasion: monsterData.evasion,
1169
- hit: monsterData.hit,
1170
- speed: monsterData.speed,
1462
+ evasion: monsterData2.evasion,
1463
+ hit: monsterData2.hit,
1464
+ speed: monsterData2.speed,
1171
1465
  gain: {
1172
1466
  maxHp: 0,
1173
1467
  maxMp: 0,
@@ -1179,7 +1473,8 @@ function initBattleAttribute(data) {
1179
1473
  hit: 0,
1180
1474
  speed: 0
1181
1475
  },
1182
- buff: []
1476
+ buff: [],
1477
+ fn: []
1183
1478
  };
1184
1479
  return temp;
1185
1480
  }
@@ -1313,7 +1608,7 @@ function apply(ctx, config) {
1313
1608
  GensokyoMap.initUserPoistion(session, userData);
1314
1609
  const areaInfo = GensokyoMap.getUserCurrentArea(session.userId);
1315
1610
  if (goal) {
1316
- if (!areaInfo.monster.map((i) => i.name).includes(goal)) {
1611
+ if (!areaInfo.monster?.map((i) => i.name).includes(goal)) {
1317
1612
  return `没有在该区域找到该怪物。`;
1318
1613
  }
1319
1614
  const selectMonster = areaInfo.monster.find((i) => i.name == goal);
@@ -1328,6 +1623,11 @@ function apply(ctx, config) {
1328
1623
  if (!userData) return;
1329
1624
  BattleData.play(session, "普攻", goal);
1330
1625
  });
1626
+ ctx.command("幻想乡/打怪技能 <skill> <goal>").action(async ({ session }, skill, goal) => {
1627
+ const userData = await User.getUserAttribute(session);
1628
+ if (!userData) return;
1629
+ BattleData.play(session, skill, goal);
1630
+ });
1331
1631
  ctx.command("打怪pk <goal>").action(async ({ session }, goal) => {
1332
1632
  const userData = await User.getUserAttribute(session);
1333
1633
  if (!userData) return;
@@ -1351,6 +1651,12 @@ function apply(ctx, config) {
1351
1651
  await BattleData.createBattleByUser(session, [{ userId: exist.userId }]);
1352
1652
  }
1353
1653
  });
1654
+ ctx.command("技能查询 <goal>").action(async ({ session }, goal) => {
1655
+ if (!goal) return `请输入技能名,例如 /技能查询 重砍`;
1656
+ if (!skillFn[goal]) return `没有存在 ${goal} 技能!`;
1657
+ return `[${goal}]信息如下:
1658
+ ` + skillFn[goal].info;
1659
+ });
1354
1660
  }
1355
1661
  __name(apply, "apply");
1356
1662
  // Annotate the CommonJS export names for ESM import in node:
package/lib/monster.d.ts CHANGED
@@ -1,14 +1,11 @@
1
1
  import { Context } from "koishi";
2
2
  import { Config } from ".";
3
+ import { MonsterOccupation } from "./data/initMonster";
3
4
  declare module 'koishi' {
4
5
  interface Tables {
5
6
  smm_gensokyo_monster_attribute: MonsterBaseAttribute;
6
7
  }
7
8
  }
8
- export declare enum MonsterOccupation {
9
- 野怪 = "\u91CE\u602A",
10
- BOSS = "BOSS"
11
- }
12
9
  /** 怪物基础属性 */
13
10
  export type MonsterBaseAttribute = {
14
11
  /** 凭据ID */
@@ -41,6 +38,8 @@ export type MonsterBaseAttribute = {
41
38
  hit: number;
42
39
  /** 出手速度 */
43
40
  speed: number;
41
+ /** 获得经验 */
42
+ giveExp: number;
44
43
  };
45
44
  type MonsterTempData = {
46
45
  [keys: string]: MonsterBaseAttribute;
@@ -0,0 +1,82 @@
1
+ import { BattleAttribute } from "./battle";
2
+ import { DamageConfig } from "./damage";
3
+ import { UserOccupation } from "./users";
4
+ export declare enum SkillType {
5
+ 释放失败 = "\u91CA\u653E\u5931\u8D25",
6
+ 伤害技 = "\u4F24\u5BB3\u6280",
7
+ 增益技 = "\u589E\u76CA\u6280",
8
+ 治疗技 = "\u6CBB\u7597\u6280",
9
+ 奥义 = "\u5965\u4E49"
10
+ }
11
+ interface DamageSkillParams {
12
+ /** 伤害类型 */
13
+ type: SkillType.伤害技;
14
+ /** 伤害信息 */
15
+ damage: DamageConfig;
16
+ /** 释放目标 */
17
+ target: BattleAttribute[];
18
+ /** 是否衔接普攻 */
19
+ isNext: boolean;
20
+ }
21
+ interface HealSkillParams {
22
+ type: SkillType.治疗技;
23
+ /** 是否衔接普攻 */
24
+ isNext: boolean;
25
+ /** 治疗量 */
26
+ value: number;
27
+ target: BattleAttribute[];
28
+ }
29
+ interface BuffSkillParams {
30
+ type: SkillType.增益技;
31
+ buffs: {
32
+ val: number;
33
+ time: number;
34
+ name: number;
35
+ }[];
36
+ target: BattleAttribute | BattleAttribute[];
37
+ /** 是否衔接普攻 */
38
+ isNext: boolean;
39
+ }
40
+ interface UltimateSkillParams {
41
+ type: SkillType.奥义;
42
+ /** 是否衔接普攻 */
43
+ isNext: boolean;
44
+ }
45
+ interface ErrSkillParams {
46
+ type: SkillType.释放失败;
47
+ /** 是否衔接普攻 */
48
+ isNext: boolean;
49
+ /** 错误提示 */
50
+ err?: string;
51
+ }
52
+ type SkillParams = DamageSkillParams | BuffSkillParams | HealSkillParams | UltimateSkillParams | ErrSkillParams;
53
+ interface SkillConfig<T extends SkillType = SkillType> {
54
+ /** 技能名 */
55
+ name: string;
56
+ /** 技能类型 */
57
+ type: T;
58
+ /** 技能说明 */
59
+ info: string;
60
+ /** 等级限制 */
61
+ lv: number;
62
+ /** 消耗MP */
63
+ mp: number;
64
+ /** 职业专属 */
65
+ feature?: UserOccupation[];
66
+ /** 技能函数 */
67
+ fn(agent: {
68
+ self: BattleAttribute;
69
+ goal: BattleAttribute;
70
+ }, agentList: {
71
+ selfList: BattleAttribute[];
72
+ goalList: BattleAttribute[];
73
+ }, cb?: (val: Extract<SkillParams, {
74
+ type: T;
75
+ }>) => void): string;
76
+ }
77
+ type SkillFn = {
78
+ [key: string]: SkillConfig;
79
+ };
80
+ export type UseAtkType = keyof typeof skillFn | '普攻';
81
+ export declare const skillFn: SkillFn;
82
+ export {};
package/lib/test.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ declare const nameList: {
2
+ readonly 张三: {
3
+ readonly age: 25;
4
+ };
5
+ readonly 李四: {
6
+ readonly age: 30;
7
+ };
8
+ };
9
+ declare const fn: (name: keyof typeof nameList) => {
10
+ readonly age: 25;
11
+ } | {
12
+ readonly age: 30;
13
+ };
package/lib/users.d.ts CHANGED
@@ -115,5 +115,16 @@ export declare const User: {
115
115
  createPlayUser(session: Session): Promise<void>;
116
116
  /** 信息格式化 */
117
117
  userAttributeTextFormat(userId: string): string;
118
+ /** 写入用户数据到数据库 */
119
+ setDatabaseUserAttribute(userId: string): Promise<void>;
120
+ /** 给予玩家经验 */
121
+ giveExp(userId: string, value: number, fn?: (upData: {
122
+ maxHp: number;
123
+ maxMp: number;
124
+ atk: number;
125
+ def: number;
126
+ lv: number;
127
+ name: string;
128
+ }) => Promise<void>): Promise<void>;
118
129
  };
119
130
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-smmcat-gensokyo",
3
3
  "description": "名为《幻想乡》的文字冒险游戏",
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [