koishi-plugin-smmcat-gensokyo 0.0.2 → 0.0.4

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
@@ -1,5 +1,6 @@
1
1
  import { Context, Session } from "koishi";
2
2
  import { Config } from ".";
3
+ import { UserBaseAttribute } from "./users";
3
4
  declare module 'koishi' {
4
5
  interface Tables {
5
6
  smm_gensokyo_battle_history: BattleHistory;
@@ -87,6 +88,7 @@ type LastPlay = {
87
88
  [keys: string]: {
88
89
  self: BattleAttribute[];
89
90
  goal: BattleAttribute[];
91
+ isPK?: boolean;
90
92
  };
91
93
  };
92
94
  export declare const BattleData: {
@@ -98,22 +100,32 @@ export declare const BattleData: {
98
100
  init(config: Config, ctx: Context): void;
99
101
  /** 玩家是否正在战斗 */
100
102
  isBattle(session: Session): boolean;
103
+ /** 玩家是否正在战斗 */
104
+ isBattleByUserId(userId: string): boolean;
101
105
  /** 玩家是否在队伍中 */
102
106
  isTeam(session: Session): boolean;
107
+ isTeamByUserId(userId: string): boolean;
108
+ teamListByUser(userId: string): UserBaseAttribute[];
103
109
  /** 创建战斗-与怪物 */
104
110
  createBattleByMonster(session: Session, goal: {
105
111
  name: string;
106
112
  lv: number;
107
113
  }[]): Promise<void>;
114
+ /** 创建战斗-与玩家 */
115
+ createBattleByUser(session: Session, goal: {
116
+ userId: string;
117
+ }[]): Promise<void>;
108
118
  /** 文本化当前战况 */
109
119
  battleSituationTextFormat(team: {
110
120
  self: BattleAttribute[];
111
121
  goal: BattleAttribute[];
122
+ isPK?: boolean;
112
123
  }): string;
113
124
  /** 判断输赢 */
114
125
  playOver(team: {
115
126
  self: BattleAttribute[];
116
127
  goal: BattleAttribute[];
128
+ isPK?: boolean;
117
129
  }): {
118
130
  over: boolean;
119
131
  type: string;
package/lib/index.js CHANGED
@@ -182,6 +182,7 @@ var GensokyoMap = {
182
182
  floor: 1,
183
183
  areaName: "绿野平原二",
184
184
  type: "冒险区" /* 冒险区 */,
185
+ monster: [{ name: "dora", lv: 2 }, { name: "dora", lv: 2 }, { name: "dora", lv: 3 }, { name: "dora", lv: 2 }],
185
186
  needLv: 1,
186
187
  right: "绿野平原一",
187
188
  down: "绿野平原五"
@@ -223,6 +224,7 @@ var GensokyoMap = {
223
224
  const userPoistionList = await ctx.database.get("smm_gensokyo_map_position", {});
224
225
  const poistionTemp = {};
225
226
  userPoistionList.forEach((poistion) => {
227
+ poistion.moveing = false;
226
228
  poistionTemp[poistion.userId] = poistion;
227
229
  });
228
230
  GensokyoMap.userCurrentLoal = poistionTemp;
@@ -306,10 +308,24 @@ var GensokyoMap = {
306
308
  };
307
309
  fn && await fn(areaInfo);
308
310
  await delay(3e3);
309
- GensokyoMap.setLocalStoragePoistionData(session.userId);
310
311
  userCurrentArea.moveing = false;
312
+ GensokyoMap.setLocalStoragePoistionData(session.userId);
311
313
  return;
312
314
  },
315
+ /** 查询附近玩家 */
316
+ nearbyPlayersByUserId(userId) {
317
+ const areaData = GensokyoMap.getUserCurrentArea(userId);
318
+ const liveUser = [];
319
+ Object.keys(GensokyoMap.userCurrentLoal).forEach((_userId) => {
320
+ const userItem = GensokyoMap.userCurrentLoal[_userId];
321
+ if (userItem.areaName == areaData.areaName && userItem.floor == areaData.floor) {
322
+ if (userId !== userItem.userId) {
323
+ liveUser.push({ userId: userItem.userId, playName: userItem.playName });
324
+ }
325
+ }
326
+ });
327
+ return liveUser;
328
+ },
313
329
  /** 区域信息格式化 */
314
330
  userAreaTextFormat(gameName, data) {
315
331
  const liveUser = [];
@@ -468,9 +484,8 @@ var User = {
468
484
  const lv = UserData.lv;
469
485
  const benchmark = {
470
486
  10: {
471
- hp: 1.2,
487
+ maxExp: 2,
472
488
  maxHp: 1.2,
473
- mp: 1.1,
474
489
  maxMp: 1.1,
475
490
  atk: 1.12,
476
491
  def: 1.1,
@@ -481,9 +496,8 @@ var User = {
481
496
  speed: 1.05
482
497
  },
483
498
  20: {
484
- hp: 1.15,
499
+ maxExp: 1.8,
485
500
  maxHp: 1.15,
486
- mp: 1.1,
487
501
  maxMp: 1.1,
488
502
  atk: 1.1,
489
503
  def: 1.1,
@@ -494,9 +508,8 @@ var User = {
494
508
  speed: 1.05
495
509
  },
496
510
  40: {
497
- hp: 1.1,
511
+ maxExp: 1.5,
498
512
  maxHp: 1.1,
499
- mp: 1.05,
500
513
  maxMp: 1.05,
501
514
  atk: 1.1,
502
515
  def: 1.05,
@@ -513,7 +526,11 @@ var User = {
513
526
  Object.keys(UserData).forEach((i) => {
514
527
  temp[i] = UserData[i];
515
528
  if (useBenchmark[i]) {
516
- temp[i] += Math.floor(temp[i] * (useBenchmark[i] - 1) * (lv - 1));
529
+ if (i == "maxExp") {
530
+ temp[i] = Math.floor(100 * useBenchmark[i] * (lv - 1)) || 100;
531
+ } else {
532
+ temp[i] += Math.floor(temp[i] * (useBenchmark[i] - 1) * (lv - 1));
533
+ }
517
534
  }
518
535
  });
519
536
  return temp;
@@ -745,16 +762,16 @@ var Monster = {
745
762
  const { name: name2, type, lv, hp, maxHp, mp, maxMp, atk, def, chr, evasion, hit, ghd, speed, info } = monster;
746
763
  const attributeText = `Lv.${lv}【${name2}】
747
764
 
748
- 怪物类型:${type}
749
- 生命值:${hp}/${maxHp}
750
- 魔法值:${mp}/${maxMp}
751
- 攻击力:${atk}
752
- 防御力:${def}
753
- 闪避值:${evasion}
754
- 命中值:${hit}
755
- 速度值:${speed}
756
- 暴击率:${(chr / 10).toFixed(1)}%
757
- 爆伤倍率:${(ghd * 100).toFixed(0)}%` + (info ? "\n\n" + info : "");
765
+ 【怪物类型】${type}
766
+ 【生命值】${hp}/${maxHp}
767
+ 【魔法值】${mp}/${maxMp}
768
+ 【攻击力】${atk}
769
+ 【防御力】${def}
770
+ 【闪避值】${evasion}
771
+ 【命中值】${hit}
772
+ 【速度值】${speed}
773
+ 【暴击率】${(chr / 10).toFixed(1)}%
774
+ 【爆伤倍率】${(ghd * 100).toFixed(0)}%` + (info ? "\n\n" + info : "");
758
775
  return attributeText;
759
776
  }
760
777
  };
@@ -890,10 +907,27 @@ var BattleData = {
890
907
  isBattle(session) {
891
908
  return !!BattleData.lastPlay[session.userId];
892
909
  },
910
+ /** 玩家是否正在战斗 */
911
+ isBattleByUserId(userId) {
912
+ return !!BattleData.lastPlay[userId];
913
+ },
893
914
  /** 玩家是否在队伍中 */
894
915
  isTeam(session) {
895
916
  return !!BattleData.teamTemp[session.userId];
896
917
  },
918
+ isTeamByUserId(userId) {
919
+ return !!BattleData.teamTemp[userId];
920
+ },
921
+ // 返回队伍信息
922
+ teamListByUser(userId) {
923
+ const teamList = [];
924
+ Object.keys(BattleData.teamTemp).forEach((item) => {
925
+ if (BattleData.teamTemp[item].for == userId) {
926
+ teamList.push(User.getUserAttributeByUserId(item));
927
+ }
928
+ });
929
+ return teamList;
930
+ },
897
931
  /** 创建战斗-与怪物 */
898
932
  async createBattleByMonster(session, goal) {
899
933
  if (BattleData.isBattle(session)) {
@@ -920,14 +954,69 @@ var BattleData = {
920
954
  goal.forEach((item) => {
921
955
  battle_monsterList.push(initBattleAttribute(Monster.getMonsterAttributeData(item.name, item.lv)));
922
956
  });
957
+ const temp = {
958
+ self: battle_user.map((i) => ({ ...i, for: "self" })),
959
+ goal: battle_monsterList.map((i) => ({ ...i, for: "goal" }))
960
+ };
923
961
  playUser.forEach((userId) => {
924
- BattleData.lastPlay[userId] = {
925
- self: battle_user.map((i) => ({ ...i, for: "self" })),
926
- goal: battle_monsterList.map((i) => ({ ...i, for: "goal" }))
927
- };
962
+ BattleData.lastPlay[userId] = temp;
928
963
  });
929
964
  await session.send(`开始与 ${goal.map((i) => i.name).join("、")} 进行战斗`);
930
965
  },
966
+ /** 创建战斗-与玩家 */
967
+ async createBattleByUser(session, goal) {
968
+ if (BattleData.isBattle(session)) {
969
+ await session.send("当前正在战斗,还不能逃脱!");
970
+ return;
971
+ }
972
+ const battle_self = [];
973
+ const battle_goal = [];
974
+ const playUser = [];
975
+ const lostMsg = [];
976
+ goal = goal.filter((item) => {
977
+ const isBattle = BattleData.isBattleByUserId(item.userId);
978
+ const pyUser = User.userTempData[item.userId];
979
+ if (isBattle) {
980
+ lostMsg.push(`${pyUser.playName}正在参与着一场战斗,无法被PK选中。`);
981
+ return false;
982
+ }
983
+ return true;
984
+ });
985
+ if (lostMsg.length) {
986
+ await session.send(lostMsg.join("\n"));
987
+ }
988
+ if (!goal.length) {
989
+ lostMsg.push(`PK失败,无任何目标进行PK`);
990
+ return;
991
+ }
992
+ if (BattleData.isTeam(session) && BattleData.teamTemp[session.userId].identity == "队员") {
993
+ await session.send("你不是队伍的队长,无法主动操作战斗!");
994
+ return;
995
+ } else if (BattleData.isTeam(session)) {
996
+ Object.keys(BattleData.teamTemp).forEach((item) => {
997
+ if (BattleData.teamTemp[item].for == session.userId) {
998
+ playUser.push(item);
999
+ battle_self.push(initBattleAttribute(User.getUserAttributeByUserId(item)));
1000
+ }
1001
+ });
1002
+ } else {
1003
+ playUser.push(session.userId);
1004
+ battle_self.push(initBattleAttribute(User.getUserAttributeByUserId(session.userId)));
1005
+ }
1006
+ goal.forEach((item) => {
1007
+ playUser.push(item.userId);
1008
+ battle_goal.push(initBattleAttribute(User.getUserAttributeByUserId(item.userId)));
1009
+ });
1010
+ const pkTemp = {
1011
+ self: battle_self.map((i) => ({ ...i, for: "self" })),
1012
+ goal: battle_goal.map((i) => ({ ...i, for: "goal" })),
1013
+ isPK: true
1014
+ };
1015
+ playUser.forEach((userId) => {
1016
+ BattleData.lastPlay[userId] = pkTemp;
1017
+ });
1018
+ await session.send(`开始与玩家 ${battle_goal.map((i) => i.name).join("、")} 进行PK战斗`);
1019
+ },
931
1020
  /** 文本化当前战况 */
932
1021
  battleSituationTextFormat(team) {
933
1022
  const selfTemp = [];
@@ -948,6 +1037,11 @@ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${ite
948
1037
  goalTemp.push(`lv.${item.lv}[${item.name}]:已阵亡`);
949
1038
  }
950
1039
  });
1040
+ if (team.isPK) {
1041
+ return `[当前战况]
1042
+ 攻击方:
1043
+ ` + selfTemp.join("\n") + "\n\n防御方:\n" + goalTemp.join("\n");
1044
+ }
951
1045
  return `[当前战况]
952
1046
  我方阵容:
953
1047
  ` + selfTemp.join("\n") + "\n\n敌方阵容:\n" + goalTemp.join("\n");
@@ -959,19 +1053,20 @@ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${ite
959
1053
  if (self && goal) {
960
1054
  return { over: true, type: "平局" };
961
1055
  } else if (self) {
962
- return { over: true, type: "敌方赢" };
1056
+ return { over: true, type: team.isPK ? "敌方赢" : "防御方赢" };
963
1057
  } else if (goal) {
964
- return { over: true, type: "我方赢" };
1058
+ return { over: true, type: team.isPK ? "我方赢" : "攻击方赢" };
965
1059
  }
966
1060
  return { over: false, type: "未结束" };
967
1061
  },
968
1062
  /** 清理战场 */
969
1063
  clearBattleData(session) {
970
1064
  if (BattleData.isTeam(session)) {
971
- const userId = BattleData.teamTemp[session.userId].for;
972
- Object.keys(BattleData.teamTemp).forEach((item) => {
973
- if (BattleData.teamTemp[item].for == userId) {
974
- delete BattleData.lastPlay[item];
1065
+ const currentBattle = BattleData.lastPlay[session.userId];
1066
+ const allAgentList = [...currentBattle.goal, ...currentBattle.self].sort((a, b) => b.speed - a.speed);
1067
+ allAgentList.forEach((item) => {
1068
+ if (item.type == "玩家") {
1069
+ delete BattleData.lastPlay[item.userId];
975
1070
  }
976
1071
  });
977
1072
  } else {
@@ -1000,6 +1095,8 @@ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${ite
1000
1095
  if (agent.type == "玩家" && agent.userId == session.userId) {
1001
1096
  isMy = true;
1002
1097
  selectGoal = lifeGoalList.find((item) => item.name == select) || lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1098
+ } else if (agent.type == "玩家") {
1099
+ selectGoal = lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1003
1100
  } else {
1004
1101
  selectGoal = lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1005
1102
  }
@@ -1107,9 +1204,19 @@ function apply(ctx, config) {
1107
1204
  const userData = await User.getUserAttribute(session);
1108
1205
  if (!userData) return;
1109
1206
  GensokyoMap.initUserPoistion(session, userData);
1207
+ if (BattleData.isBattle(session)) {
1208
+ await session.send("您正在战斗中,无法移动!");
1209
+ return;
1210
+ }
1110
1211
  GensokyoMap.move(session, "top" /* 上 */, async (val) => {
1111
- await session.send("移动成功...");
1112
1212
  await session.send(GensokyoMap.userAreaTextFormat(userData.playName, val));
1213
+ if (val.map.type == "冒险区" /* 冒险区 */ && val.map.monster?.length) {
1214
+ if (random(0, 10) <= 2) {
1215
+ const selectMonster = val.map.monster[random(0, val.map.monster.length)];
1216
+ await session.send(`糟糕!你被 Lv.${selectMonster.lv} ${selectMonster.name} 发现,强制开启战斗!`);
1217
+ await BattleData.createBattleByMonster(session, [selectMonster]);
1218
+ }
1219
+ }
1113
1220
  });
1114
1221
  });
1115
1222
  ctx.command("幻想乡/移动.下").action(async ({ session }) => {
@@ -1117,9 +1224,19 @@ function apply(ctx, config) {
1117
1224
  const userData = await User.getUserAttribute(session);
1118
1225
  if (!userData) return;
1119
1226
  GensokyoMap.initUserPoistion(session, userData);
1227
+ if (BattleData.isBattle(session)) {
1228
+ await session.send("您正在战斗中,无法移动!");
1229
+ return;
1230
+ }
1120
1231
  GensokyoMap.move(session, "down" /* 下 */, async (val) => {
1121
- await session.send("移动成功...");
1122
1232
  await session.send(GensokyoMap.userAreaTextFormat(userData.playName, val));
1233
+ if (val.map.type == "冒险区" /* 冒险区 */ && val.map.monster?.length) {
1234
+ if (random(0, 10) <= 2) {
1235
+ const selectMonster = val.map.monster[random(0, val.map.monster.length)];
1236
+ await session.send(`糟糕!你被 Lv.${selectMonster.lv} ${selectMonster.name} 发现,强制发生战斗!`);
1237
+ await BattleData.createBattleByMonster(session, [selectMonster]);
1238
+ }
1239
+ }
1123
1240
  });
1124
1241
  });
1125
1242
  ctx.command("幻想乡/移动.左").action(async ({ session }) => {
@@ -1127,9 +1244,19 @@ function apply(ctx, config) {
1127
1244
  const userData = await User.getUserAttribute(session);
1128
1245
  if (!userData) return;
1129
1246
  GensokyoMap.initUserPoistion(session, userData);
1247
+ if (BattleData.isBattle(session)) {
1248
+ await session.send("您正在战斗中,无法移动!");
1249
+ return;
1250
+ }
1130
1251
  GensokyoMap.move(session, "left" /* 左 */, async (val) => {
1131
- await session.send("移动成功...");
1132
1252
  await session.send(GensokyoMap.userAreaTextFormat(userData.playName, val));
1253
+ if (val.map.type == "冒险区" /* 冒险区 */ && val.map.monster?.length) {
1254
+ if (random(0, 10) <= 2) {
1255
+ const selectMonster = val.map.monster[random(0, val.map.monster.length)];
1256
+ await session.send(`糟糕!你被 Lv.${selectMonster.lv} ${selectMonster.name} 发现,强制发生战斗!`);
1257
+ await BattleData.createBattleByMonster(session, [selectMonster]);
1258
+ }
1259
+ }
1133
1260
  });
1134
1261
  });
1135
1262
  ctx.command("幻想乡/移动.右").action(async ({ session }) => {
@@ -1137,9 +1264,19 @@ function apply(ctx, config) {
1137
1264
  const userData = await User.getUserAttribute(session);
1138
1265
  if (!userData) return;
1139
1266
  GensokyoMap.initUserPoistion(session, userData);
1267
+ if (BattleData.isBattle(session)) {
1268
+ await session.send("您正在战斗中,无法移动!");
1269
+ return;
1270
+ }
1140
1271
  GensokyoMap.move(session, "right" /* 右 */, async (val) => {
1141
- await session.send("移动成功...");
1142
1272
  await session.send(GensokyoMap.userAreaTextFormat(userData.playName, val));
1273
+ if (val.map.type == "冒险区" /* 冒险区 */ && val.map.monster?.length) {
1274
+ if (random(0, 10) <= 2) {
1275
+ const selectMonster = val.map.monster[random(0, val.map.monster.length)];
1276
+ await session.send(`糟糕!你被 Lv.${selectMonster.lv} ${selectMonster.name} 发现,强制发生战斗!`);
1277
+ await BattleData.createBattleByMonster(session, [selectMonster]);
1278
+ }
1279
+ }
1143
1280
  });
1144
1281
  });
1145
1282
  ctx.command("幻想乡/位置").action(async ({ session }) => {
@@ -1191,6 +1328,29 @@ function apply(ctx, config) {
1191
1328
  if (!userData) return;
1192
1329
  BattleData.play(session, "普攻", goal);
1193
1330
  });
1331
+ ctx.command("打怪pk <goal>").action(async ({ session }, goal) => {
1332
+ const userData = await User.getUserAttribute(session);
1333
+ if (!userData) return;
1334
+ GensokyoMap.initUserPoistion(session, userData);
1335
+ if (!goal) {
1336
+ await session.send("请选择PK目标!");
1337
+ return;
1338
+ }
1339
+ const nearUserItem = GensokyoMap.nearbyPlayersByUserId(session.userId);
1340
+ const exist = nearUserItem.find((item) => item.playName == goal.trim());
1341
+ if (!exist) {
1342
+ await session.send(`PK失败,当前区域未存在【${goal}】玩家`);
1343
+ return;
1344
+ }
1345
+ if (BattleData.isTeamByUserId(exist.userId)) {
1346
+ const teamItem = BattleData.teamListByUser(exist.userId);
1347
+ await session.send(`对方有组队,您将扮演攻击方与对方队伍进行战斗。`);
1348
+ await BattleData.createBattleByUser(session, teamItem.map((item) => ({ userId: item.userId })));
1349
+ } else {
1350
+ await session.send(`您将扮演攻击方与对方进行战斗。`);
1351
+ await BattleData.createBattleByUser(session, [{ userId: exist.userId }]);
1352
+ }
1353
+ });
1194
1354
  }
1195
1355
  __name(apply, "apply");
1196
1356
  // Annotate the CommonJS export names for ESM import in node:
package/lib/map.d.ts CHANGED
@@ -2,7 +2,7 @@ import { Context, Session } from "koishi";
2
2
  import { Config } from ".";
3
3
  import { UserBaseAttribute } from "./users";
4
4
  /** 区域类型枚举 */
5
- declare enum AreaType {
5
+ export declare enum AreaType {
6
6
  安全区 = "\u5B89\u5168\u533A",
7
7
  冒险区 = "\u5192\u9669\u533A",
8
8
  商店 = "\u5546\u5E97",
@@ -98,6 +98,11 @@ export declare const GensokyoMap: {
98
98
  setLocalStoragePoistionData(userId: string): Promise<void>;
99
99
  /** 用户移动 */
100
100
  move(session: Session, type: MoveType, fn?: (area: AreaCallbackData) => Promise<void>): Promise<void>;
101
+ /** 查询附近玩家 */
102
+ nearbyPlayersByUserId(userId: string): {
103
+ userId: string;
104
+ playName: string;
105
+ }[];
101
106
  /** 区域信息格式化 */
102
107
  userAreaTextFormat(gameName: string, data: AreaCallbackData): string;
103
108
  };
package/lib/users.d.ts CHANGED
@@ -51,6 +51,30 @@ export type UserBaseAttribute = {
51
51
  /** 出手速度 */
52
52
  speed: number;
53
53
  };
54
+ export type UserBenchmark = {
55
+ [keys: number]: {
56
+ /** 最大经验 */
57
+ maxExp: number;
58
+ /** 最大血量 */
59
+ maxHp: number;
60
+ /** 最大蓝量 */
61
+ maxMp: number;
62
+ /** 攻击力 */
63
+ atk: number;
64
+ /** 防御力 */
65
+ def: number;
66
+ /** 暴击率 */
67
+ chr: number;
68
+ /** 暴击伤害 */
69
+ ghd: number;
70
+ /** 闪避值 */
71
+ evasion: number;
72
+ /** 命中值 */
73
+ hit: number;
74
+ /** 出手速度 */
75
+ speed: number;
76
+ };
77
+ };
54
78
  export type DatabaseUserAttribute = {
55
79
  /** 凭据ID */
56
80
  userId: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-smmcat-gensokyo",
3
3
  "description": "名为《幻想乡》的文字冒险游戏",
4
- "version": "0.0.2",
4
+ "version": "0.0.4",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [