koishi-plugin-smmcat-gensokyo 0.0.28 → 0.0.30

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 CHANGED
@@ -28,429 +28,6 @@ __export(src_exports, {
28
28
  module.exports = __toCommonJS(src_exports);
29
29
  var import_koishi2 = require("koishi");
30
30
 
31
- // src/map.ts
32
- var delay = /* @__PURE__ */ __name((ms) => new Promise((resolve) => setTimeout(resolve, ms)), "delay");
33
- var GensokyoMap = {
34
- config: {},
35
- ctx: {},
36
- mapLocalData: {},
37
- userCurrentLoal: {},
38
- async init(config, ctx) {
39
- GensokyoMap.config = config;
40
- GensokyoMap.ctx = ctx;
41
- ctx.database.extend("smm_gensokyo_map_position", {
42
- userId: "string",
43
- floor: "integer",
44
- areaName: "string",
45
- moveing: "boolean",
46
- playName: "string"
47
- }, {
48
- primary: "userId",
49
- autoInc: false
50
- });
51
- GensokyoMap.mapLocalData = {
52
- 1: {
53
- "地下墓穴": {
54
- floor: 1,
55
- areaName: "地下墓穴",
56
- type: "BOSS区" /* BOSS区 */,
57
- needLv: 1,
58
- down: "蜘蛛洞穴",
59
- monster: [{ name: "古明地觉", lv: 15 }]
60
- },
61
- "蜘蛛洞穴": {
62
- floor: 1,
63
- areaName: "蜘蛛洞穴",
64
- type: "冒险区" /* 冒险区 */,
65
- needLv: 1,
66
- top: "地下墓穴",
67
- down: "蜘蛛森林一"
68
- },
69
- "蜘蛛森林一": {
70
- floor: 1,
71
- areaName: "蜘蛛森林一",
72
- type: "冒险区" /* 冒险区 */,
73
- needLv: 1,
74
- monster: [{ name: "小蜘蛛", lv: 2 }],
75
- top: "蜘蛛洞穴",
76
- left: "蜘蛛森林二",
77
- right: "蜘蛛森林三",
78
- down: "蜘蛛森林通道"
79
- },
80
- "蜘蛛森林二": {
81
- floor: 1,
82
- areaName: "蜘蛛森林二",
83
- type: "冒险区" /* 冒险区 */,
84
- needLv: 1,
85
- right: "蜘蛛森林一"
86
- },
87
- "蜘蛛森林三": {
88
- floor: 1,
89
- areaName: "蜘蛛森林三",
90
- type: "冒险区" /* 冒险区 */,
91
- needLv: 1,
92
- left: "蜘蛛森林一",
93
- monster: [{ name: "大妖精", lv: 3 }]
94
- },
95
- "蜘蛛森林通道": {
96
- floor: 1,
97
- areaName: "蜘蛛森林通道",
98
- type: "冒险区" /* 冒险区 */,
99
- needLv: 1,
100
- top: "蜘蛛森林一",
101
- down: "中央广场"
102
- },
103
- "中央广场": {
104
- floor: 1,
105
- areaName: "中央广场",
106
- info: "一层的中心位置,梦开始的地方",
107
- npc: ["aipo"],
108
- type: "安全区" /* 安全区 */,
109
- needLv: 1,
110
- top: "蜘蛛森林通道",
111
- down: "新手村",
112
- left: "酒馆",
113
- right: "银行"
114
- },
115
- "酒馆": {
116
- floor: 1,
117
- areaName: "酒馆",
118
- type: "安全区" /* 安全区 */,
119
- needLv: 1,
120
- down: "传送门",
121
- right: "中央广场"
122
- },
123
- "银行": {
124
- floor: 1,
125
- areaName: "银行",
126
- type: "安全区" /* 安全区 */,
127
- needLv: 1,
128
- down: "1层-商店",
129
- left: "中央广场"
130
- },
131
- "1层-商店": {
132
- floor: 1,
133
- areaName: "1层-商店",
134
- type: "安全区" /* 安全区 */,
135
- needLv: 1,
136
- right: "农田",
137
- left: "新手村"
138
- },
139
- "传送门": {
140
- floor: 1,
141
- areaName: "传送门",
142
- type: "传送门" /* 传送门 */,
143
- needLv: 1,
144
- top: "酒馆",
145
- right: "新手村",
146
- left: "爱之湖"
147
- },
148
- "爱之湖": {
149
- floor: 1,
150
- areaName: "传送门",
151
- type: "安全区" /* 安全区 */,
152
- needLv: 1,
153
- right: "传送门"
154
- },
155
- "新手村": {
156
- floor: 1,
157
- areaName: "新手村",
158
- type: "安全区" /* 安全区 */,
159
- needLv: 1,
160
- top: "中央广场",
161
- down: "绿野平原通道",
162
- left: "传送门",
163
- right: "1层-商店"
164
- },
165
- "绿野平原通道": {
166
- floor: 1,
167
- areaName: "绿野平原通道",
168
- type: "安全区" /* 安全区 */,
169
- needLv: 1,
170
- top: "新手村",
171
- down: "绿野平原一"
172
- },
173
- "绿野平原一": {
174
- floor: 1,
175
- areaName: "绿野平原一",
176
- type: "冒险区" /* 冒险区 */,
177
- monster: [{ name: "小蜜蜂", lv: 1 }, { name: "dora", lv: 2 }],
178
- needLv: 1,
179
- top: "绿野平原通道",
180
- left: "绿野平原二",
181
- right: "绿野平原三",
182
- down: "绿野平原四"
183
- },
184
- "绿野平原二": {
185
- floor: 1,
186
- areaName: "绿野平原二",
187
- type: "冒险区" /* 冒险区 */,
188
- monster: [{ name: "dora", lv: 2 }, { name: "dora", lv: 2 }, { name: "dora", lv: 3 }, { name: "dora", lv: 2 }],
189
- needLv: 1,
190
- right: "绿野平原一",
191
- down: "绿野平原五"
192
- },
193
- "绿野平原三": {
194
- floor: 1,
195
- areaName: "绿野平原三",
196
- type: "冒险区" /* 冒险区 */,
197
- monster: [{ name: "dora", lv: 5 }],
198
- needLv: 1,
199
- left: "绿野平原一",
200
- down: "绿野平原六"
201
- },
202
- "绿野平原四": {
203
- floor: 1,
204
- areaName: "绿野平原四",
205
- type: "冒险区" /* 冒险区 */,
206
- needLv: 1,
207
- top: "绿野平原一",
208
- down: "野猪巢穴",
209
- left: "绿野平原五",
210
- right: "绿野平原六",
211
- monster: [{ name: "琪露诺", lv: 10 }]
212
- },
213
- "绿野平原五": {
214
- floor: 1,
215
- areaName: "绿野平原五",
216
- type: "冒险区" /* 冒险区 */,
217
- needLv: 1,
218
- top: "绿野平原二",
219
- right: "绿野平原四"
220
- },
221
- "绿野平原六": {
222
- floor: 1,
223
- areaName: "绿野平原六",
224
- type: "冒险区" /* 冒险区 */,
225
- needLv: 1,
226
- left: "绿野平原四",
227
- top: "绿野平原三",
228
- monster: [{ name: "绿毒蛇", lv: 12 }]
229
- },
230
- "野猪巢穴": {
231
- floor: 1,
232
- areaName: "野猪巢穴",
233
- type: "BOSS区" /* BOSS区 */,
234
- needLv: 1,
235
- top: "绿野平原四",
236
- monster: [{ name: "蓬莱山辉夜", lv: 20 }]
237
- }
238
- },
239
- 2: {
240
- "传送门": {
241
- floor: 2,
242
- areaName: "传送门",
243
- type: "传送门" /* 传送门 */,
244
- needLv: 1,
245
- right: "希望之泉"
246
- },
247
- "希望之泉": {
248
- floor: 2,
249
- areaName: "希望之泉",
250
- type: "安全区" /* 安全区 */,
251
- needLv: 1,
252
- top: "爱之湖",
253
- down: "农田",
254
- left: "传送门",
255
- right: "2层-商店"
256
- },
257
- "爱之湖": {
258
- floor: 2,
259
- areaName: "爱之湖",
260
- type: "安全区" /* 安全区 */,
261
- needLv: 1,
262
- down: "希望之泉",
263
- right: "旅馆"
264
- },
265
- "农田": {
266
- floor: 2,
267
- areaName: "农田",
268
- type: "安全区" /* 安全区 */,
269
- needLv: 1,
270
- top: "希望之泉",
271
- right: "银行"
272
- },
273
- "银行": {
274
- floor: 2,
275
- areaName: "银行",
276
- type: "安全区" /* 安全区 */,
277
- needLv: 1,
278
- top: "2层-商店",
279
- left: "农田"
280
- },
281
- "旅馆": {
282
- floor: 2,
283
- areaName: "旅馆",
284
- type: "安全区" /* 安全区 */,
285
- needLv: 1,
286
- down: "2层-商店",
287
- left: "爱之湖"
288
- },
289
- "2层-商店": {
290
- floor: 2,
291
- areaName: "2层-商店",
292
- type: "安全区" /* 安全区 */,
293
- needLv: 1,
294
- right: "大草场"
295
- },
296
- "大草场": {
297
- floor: 2,
298
- areaName: "大草场",
299
- type: "安全区" /* 安全区 */,
300
- needLv: 1,
301
- left: "2层-商店",
302
- right: "森林岔口"
303
- },
304
- "森林岔口": {
305
- floor: 2,
306
- areaName: "森林岔口",
307
- type: "安全区" /* 安全区 */,
308
- needLv: 1,
309
- left: "大草场"
310
- }
311
- }
312
- };
313
- console.log(JSON.stringify(GensokyoMap.mapLocalData));
314
- const userPoistionList = await ctx.database.get("smm_gensokyo_map_position", {});
315
- const poistionTemp = {};
316
- userPoistionList.forEach((poistion) => {
317
- poistion.moveing = false;
318
- poistionTemp[poistion.userId] = poistion;
319
- });
320
- GensokyoMap.userCurrentLoal = poistionTemp;
321
- },
322
- /** 获取层的数据 */
323
- getBaseFloorLocal(floor) {
324
- return GensokyoMap.mapLocalData[floor] || null;
325
- },
326
- /** 获取用户当前区域信息 */
327
- getUserCurrentArea(userid) {
328
- const { floor, areaName } = GensokyoMap.userCurrentLoal[userid] || {};
329
- if (!(floor && areaName)) return null;
330
- return GensokyoMap.mapLocalData[floor][areaName] || null;
331
- },
332
- /** 初始化用户位置 */
333
- initUserPoistion(session, userData) {
334
- if (!GensokyoMap.userCurrentLoal[session.userId]) {
335
- GensokyoMap.userCurrentLoal[session.userId] = {
336
- userId: session.userId,
337
- floor: 1,
338
- areaName: "传送门",
339
- moveing: false,
340
- playName: userData.playName
341
- };
342
- }
343
- GensokyoMap.setLocalStoragePoistionData(session.userId);
344
- },
345
- /** 位置信息存储到数据库 */
346
- async setLocalStoragePoistionData(userId) {
347
- const poistionData = { ...GensokyoMap.userCurrentLoal[userId] };
348
- if (poistionData) {
349
- const [localData] = await GensokyoMap.ctx.database.get("smm_gensokyo_map_position", { userId });
350
- if (!localData) {
351
- await GensokyoMap.ctx.database.create("smm_gensokyo_map_position", poistionData);
352
- return;
353
- }
354
- delete poistionData.userId;
355
- await GensokyoMap.ctx.database.set("smm_gensokyo_map_position", { userId }, poistionData);
356
- }
357
- },
358
- /** 用户移动 */
359
- async move(session, type, fn) {
360
- try {
361
- const userCurrentArea = GensokyoMap.userCurrentLoal[session.userId] || {};
362
- const { floor, areaName, moveing } = userCurrentArea;
363
- if (moveing) {
364
- await session.send("当前移动冷却中,请稍等...");
365
- return;
366
- }
367
- if (!(floor && areaName)) {
368
- await session.send("您当前位置有误,请使用(还没写好的指令)脱离卡死...");
369
- return;
370
- }
371
- userCurrentArea.moveing = true;
372
- const nowPosition = GensokyoMap.mapLocalData[floor][areaName];
373
- if (!nowPosition[type]) {
374
- await session.send("抱歉,此路不通!");
375
- userCurrentArea.moveing = false;
376
- return;
377
- }
378
- const newArea = GensokyoMap.mapLocalData[floor][nowPosition[type]];
379
- if (!newArea) {
380
- await session.send("进入失败,地图中不存在 " + nowPosition[type] + " 这个区域。");
381
- userCurrentArea.moveing = false;
382
- return;
383
- }
384
- if (newArea.type == "禁用" /* 禁用 */) {
385
- await session.send(`该区域暂时未开放...`);
386
- userCurrentArea.moveing = false;
387
- return;
388
- }
389
- if (newArea.needLv > 1) {
390
- await session.send(`当前区域由于您的等级未达到最低要求,暂时无法进入。
391
- 需要等级:${newArea.needLv}级`);
392
- userCurrentArea.moveing = false;
393
- return;
394
- }
395
- userCurrentArea.areaName = newArea.areaName;
396
- const areaInfo = {
397
- user: { ...userCurrentArea },
398
- map: { ...newArea }
399
- };
400
- fn && await fn(areaInfo);
401
- await delay(3e3);
402
- userCurrentArea.moveing = false;
403
- GensokyoMap.setLocalStoragePoistionData(session.userId);
404
- return;
405
- } catch (error) {
406
- console.log(error);
407
- if (GensokyoMap.userCurrentLoal?.[session.userId]) {
408
- GensokyoMap.userCurrentLoal[session.userId].moveing = false;
409
- }
410
- }
411
- },
412
- /** 查询附近玩家 */
413
- nearbyPlayersByUserId(userId) {
414
- const areaData = GensokyoMap.getUserCurrentArea(userId);
415
- const liveUser = [];
416
- Object.keys(GensokyoMap.userCurrentLoal).forEach((_userId) => {
417
- const userItem = GensokyoMap.userCurrentLoal[_userId];
418
- if (userItem.areaName == areaData.areaName && userItem.floor == areaData.floor) {
419
- if (userId !== userItem.userId) {
420
- liveUser.push({ userId: userItem.userId, playName: userItem.playName });
421
- }
422
- }
423
- });
424
- return liveUser;
425
- },
426
- /** 区域信息格式化 */
427
- userAreaTextFormat(gameName, data) {
428
- const liveUser = [];
429
- Object.keys(GensokyoMap.userCurrentLoal).forEach((userId) => {
430
- const areaItem = GensokyoMap.userCurrentLoal[userId];
431
- if (areaItem.areaName == data.map.areaName && areaItem.floor == data.map.floor) {
432
- if (gameName !== areaItem.playName) {
433
- liveUser.push(areaItem.playName);
434
- }
435
- }
436
- });
437
- const str = `${gameName}[萌新] 当前位置:
438
- `;
439
- const mapInfo = `区域:【${data.map.areaName}】
440
- ` + (data.map.info ? data.map.info + "\n\n" : "\n") + (data.map.top ? `上:【${data.map.top}】
441
- ` : "") + (data.map.down ? `下:【${data.map.down}】
442
- ` : "") + (data.map.left ? `左:【${data.map.left}】
443
- ` : "") + (data.map.right ? `右:【${data.map.right}】
444
- ` : "") + (data.map.type == "传送门" /* 传送门 */ ? `
445
- [!]传送门区域` : "") + (data.map.shopName ? `
446
- [!]存在商店:${data.map.shopName}` : "") + (data.map.npc ? `
447
- [!]存在npc:${data.map.npc.join("、")}` : "") + (data.map.monster ? `
448
- [!]存在野怪:${data.map.monster.map((i) => `lv.${i.lv} ${i.name}`).join("、")}` : "") + (liveUser.length ? `
449
- [!]区域玩家:${liveUser.length > 3 ? liveUser.slice(0, 3).join("、") + `...等${liveUser.length}` : liveUser.join("、")}` : "");
450
- return str + mapInfo;
451
- }
452
- };
453
-
454
31
  // src/data/benchmark.ts
455
32
  var monsterBenchmark = {
456
33
  10: {
@@ -1460,1229 +1037,1988 @@ var BattleData = {
1460
1037
  isTeamByUserId(userId) {
1461
1038
  return !!BattleData.teamTemp[userId];
1462
1039
  },
1463
- // 返回队伍信息
1464
- teamListByUser(userId) {
1465
- const teamList = [];
1466
- if (!BattleData.teamTemp[userId]) {
1467
- return [];
1040
+ // 返回队伍信息
1041
+ teamListByUser(userId) {
1042
+ const teamList = [];
1043
+ if (!BattleData.teamTemp[userId]) {
1044
+ return [];
1045
+ }
1046
+ const _userId = BattleData.teamTemp[userId].for;
1047
+ Object.keys(BattleData.teamTemp).forEach((item) => {
1048
+ if (BattleData.teamTemp[item].for == _userId) {
1049
+ teamList.push(User.getUserAttributeByUserId(item));
1050
+ }
1051
+ });
1052
+ return teamList;
1053
+ },
1054
+ /** 创建队伍 */
1055
+ async creatTeam(session) {
1056
+ const { userId } = session;
1057
+ if (BattleData.isTeamByUserId(userId)) {
1058
+ await session.send(`${User.getUserName(userId)}:你已经加入了${BattleData.teamTemp[userId].for}的队伍,需要退出才可以重新创建!`);
1059
+ return;
1060
+ }
1061
+ BattleData.teamTemp[userId] = {
1062
+ for: userId,
1063
+ identity: "队长"
1064
+ };
1065
+ await session.send("创建队伍成功!发送 /队伍邀请 昵称 \n可对周围对应昵称玩家进行组队邀请!");
1066
+ },
1067
+ /** 邀请加入队伍 */
1068
+ async invitationTeam(session, playName) {
1069
+ const { userId } = session;
1070
+ if (!BattleData.isTeamByUserId(userId)) {
1071
+ await session.send(`你还没有创建队伍,请发送 /队伍创建 创建队伍吧!`);
1072
+ return;
1073
+ }
1074
+ const teamInfo = BattleData.teamTemp[userId];
1075
+ if (teamInfo.identity !== "队长") {
1076
+ await session.send(`你不是小队队长,无法邀请玩家加入!`);
1077
+ return;
1078
+ }
1079
+ const nearUser = GensokyoMap.nearbyPlayersByUserId(userId);
1080
+ const invitationUser = nearUser.find((item) => item.playName == playName);
1081
+ if (!invitationUser) {
1082
+ await session.send(`玩家${playName}不在你附近,邀请失败!`);
1083
+ return;
1084
+ }
1085
+ if (BattleData.isTeamByUserId(invitationUser.userId)) {
1086
+ await session.send(`对方已经组队,或者已经在队伍中!`);
1087
+ return;
1088
+ }
1089
+ BattleData.invitationTemp[invitationUser.userId] = {
1090
+ time: Date.now(),
1091
+ for: userId,
1092
+ playName: User.getUserName(userId),
1093
+ seen: false
1094
+ };
1095
+ await session.send(`已经发送邀请,等待TA的 /队伍加入 操作`);
1096
+ },
1097
+ /** 加入队伍 */
1098
+ async joinTeam(session) {
1099
+ const { userId } = session;
1100
+ if (!BattleData.invitationTemp[userId]) {
1101
+ await session.send("当前最后记录中无人邀请你加入队伍...");
1102
+ return;
1103
+ }
1104
+ if (BattleData.isTeamByUserId(userId)) {
1105
+ await session.send(`你已经在队伍中,无法再次加入,若需要加入请发送 /队伍退出`);
1106
+ return;
1107
+ }
1108
+ const invInfo = BattleData.invitationTemp[userId];
1109
+ if (Date.now() - invInfo.time > 36e5) {
1110
+ await session.send(`${invInfo.playName}的邀请队伍请求已超时!`);
1111
+ delete BattleData.invitationTemp[userId];
1112
+ return;
1113
+ }
1114
+ if (BattleData.teamListByUser(invInfo.for).length >= 4) {
1115
+ await session.send(`${invInfo.playName}的队伍人员已满!无法加入`);
1116
+ return;
1117
+ }
1118
+ BattleData.teamTemp[userId] = {
1119
+ for: invInfo.for,
1120
+ identity: "队员"
1121
+ };
1122
+ await session.send(`加入${invInfo.playName}的队伍成功!
1123
+ 若后续需要退出可发送 /队伍退出`);
1124
+ },
1125
+ /** 退出队伍 */
1126
+ async exitTeam(session) {
1127
+ const { userId } = session;
1128
+ if (!BattleData.isTeamByUserId(userId)) {
1129
+ await session.send("你还没有加入任何队伍!");
1130
+ return;
1131
+ }
1132
+ if (BattleData.teamTemp[userId].identity == "队长") {
1133
+ await session.send("你是小队队长,无法退出。若要解散队伍,请发送 /队伍解散");
1134
+ return;
1135
+ }
1136
+ const teamName = User.getUserName(BattleData.teamTemp[userId].for);
1137
+ delete BattleData.teamTemp[userId];
1138
+ await session.send(`退出${teamName}的小队成功!`);
1139
+ },
1140
+ /** 解散队伍 */
1141
+ async dissolveTeam(session) {
1142
+ const { userId } = session;
1143
+ if (!BattleData.isTeamByUserId(userId)) {
1144
+ await session.send("你还没有加入任何队伍!");
1145
+ return;
1146
+ }
1147
+ if (BattleData.teamTemp[userId].identity == "队员") {
1148
+ await session.send("你不是小队队长,无法解散。");
1149
+ return;
1150
+ }
1151
+ const team = BattleData.teamListByUser(userId);
1152
+ team.forEach((item) => {
1153
+ delete BattleData.teamTemp[item.userId];
1154
+ });
1155
+ await session.send("操作成功,已经解散你创建的小队。");
1156
+ },
1157
+ /** 创建战斗-与怪物 */
1158
+ async createBattleByMonster(session, goal) {
1159
+ if (BattleData.isBattle(session)) {
1160
+ await session.send("当前正在战斗,还不能逃脱!");
1161
+ return;
1162
+ }
1163
+ const battle_user = [];
1164
+ const battle_monsterList = [];
1165
+ const playUser = [];
1166
+ if (BattleData.isTeam(session) && BattleData.teamTemp[session.userId].identity == "队员") {
1167
+ await session.send("你不是队伍的队长,无法主动操作战斗!");
1168
+ return;
1169
+ } else if (BattleData.isTeam(session)) {
1170
+ Object.keys(BattleData.teamTemp).forEach((item) => {
1171
+ if (BattleData.teamTemp[item].for == session.userId) {
1172
+ playUser.push(item);
1173
+ battle_user.push(initBattleAttribute(User.getUserAttributeByUserId(item)));
1174
+ }
1175
+ });
1176
+ } else {
1177
+ playUser.push(session.userId);
1178
+ battle_user.push(initBattleAttribute(User.getUserAttributeByUserId(session.userId)));
1179
+ }
1180
+ goal.forEach((item) => {
1181
+ battle_monsterList.push(initBattleAttribute(Monster.getMonsterAttributeData(item.name, item.lv)));
1182
+ });
1183
+ const temp = {
1184
+ self: battle_user.map((i) => ({ ...i, for: "self" })),
1185
+ goal: battle_monsterList.map((i) => ({ ...i, for: "goal" }))
1186
+ };
1187
+ playUser.forEach((userId) => {
1188
+ BattleData.lastPlay[userId] = temp;
1189
+ });
1190
+ await session.send(`开始与 ${goal.map((i) => i.name).join("、")} 进行战斗`);
1191
+ },
1192
+ /** 创建战斗-与玩家 */
1193
+ async createBattleByUser(session, goal) {
1194
+ if (BattleData.isBattle(session)) {
1195
+ await session.send("当前正在战斗,还不能逃脱!");
1196
+ return;
1197
+ }
1198
+ const battle_self = [];
1199
+ const battle_goal = [];
1200
+ const playUser = [];
1201
+ const lostMsg = [];
1202
+ goal = goal.filter((item) => {
1203
+ const isBattle = BattleData.isBattleByUserId(item.userId);
1204
+ const pyUser = User.userTempData[item.userId];
1205
+ if (isBattle) {
1206
+ lostMsg.push(`${pyUser.playName}正在参与着一场战斗,无法被PK选中。`);
1207
+ return false;
1208
+ }
1209
+ return true;
1210
+ });
1211
+ if (lostMsg.length) {
1212
+ await session.send(lostMsg.join("\n"));
1213
+ }
1214
+ if (!goal.length) {
1215
+ lostMsg.push(`PK失败,无任何目标进行PK`);
1216
+ return;
1217
+ }
1218
+ if (BattleData.isTeam(session) && BattleData.teamTemp[session.userId].identity == "队员") {
1219
+ await session.send("你不是队伍的队长,无法主动操作战斗!");
1220
+ return;
1221
+ } else if (BattleData.isTeam(session)) {
1222
+ Object.keys(BattleData.teamTemp).forEach((item) => {
1223
+ if (BattleData.teamTemp[item].for == session.userId) {
1224
+ playUser.push(item);
1225
+ battle_self.push(initBattleAttribute(User.getUserAttributeByUserId(item)));
1226
+ }
1227
+ });
1228
+ } else {
1229
+ playUser.push(session.userId);
1230
+ battle_self.push(initBattleAttribute(User.getUserAttributeByUserId(session.userId)));
1231
+ }
1232
+ goal.forEach((item) => {
1233
+ playUser.push(item.userId);
1234
+ battle_goal.push(initBattleAttribute(User.getUserAttributeByUserId(item.userId)));
1235
+ });
1236
+ const pkTemp = {
1237
+ self: battle_self.map((i) => ({ ...i, for: "self" })),
1238
+ goal: battle_goal.map((i) => ({ ...i, for: "goal" })),
1239
+ isPK: true
1240
+ };
1241
+ playUser.forEach((userId) => {
1242
+ BattleData.lastPlay[userId] = pkTemp;
1243
+ });
1244
+ await session.send(`开始与玩家 ${battle_goal.map((i) => i.name).join("、")} 进行PK战斗`);
1245
+ },
1246
+ /** 文本化当前战况 */
1247
+ battleSituationTextFormat(team) {
1248
+ const selfTemp = [];
1249
+ const goalTemp = [];
1250
+ const getBuffTemplate = /* @__PURE__ */ __name((agent) => {
1251
+ const dict = { 1: "¹", 2: "²", 3: "³", 4: "⁴", 5: "⁵", 6: "⁶", 7: "⁷", 8: "⁸", 9: "⁹" };
1252
+ const buffInfo = Object.keys(agent.buff).map((item) => {
1253
+ return `${agent.buff[item].name}${dict[agent.buff[item].timer] || "⁺"}`;
1254
+ });
1255
+ return buffInfo.length ? "(" + buffInfo.join(" ") + ")" : "";
1256
+ }, "getBuffTemplate");
1257
+ team.self.forEach((item) => {
1258
+ if (item.hp > 0) {
1259
+ selfTemp.push(`lv.${item.lv}[${item.name}]${getBuffTemplate(item)}:
1260
+ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${item.maxHp + item.gain.maxHp})
1261
+ MP:${item.mp}/${item.maxMp + item.gain.maxMp}`);
1262
+ } else {
1263
+ selfTemp.push(`lv.${item.lv}[${item.name}]:已阵亡`);
1264
+ }
1265
+ });
1266
+ team.goal.forEach((item) => {
1267
+ if (item.hp > 0) {
1268
+ goalTemp.push(`lv.${item.lv}[${item.name}]${getBuffTemplate(item)}:
1269
+ ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${item.maxHp + item.gain.maxHp})
1270
+ MP:${item.mp}/${item.maxMp + item.gain.maxMp}`);
1271
+ } else {
1272
+ goalTemp.push(`lv.${item.lv}[${item.name}]:已阵亡`);
1273
+ }
1274
+ });
1275
+ if (team.isPK) {
1276
+ return `[当前战况]
1277
+ 攻击方:
1278
+ ` + selfTemp.join("\n") + "\n\n防御方:\n" + goalTemp.join("\n");
1279
+ }
1280
+ return `[当前战况]
1281
+ 我方阵容:
1282
+ ` + selfTemp.join("\n") + "\n\n敌方阵容:\n" + goalTemp.join("\n");
1283
+ },
1284
+ /** 判断输赢 */
1285
+ playOver(team) {
1286
+ const self = team.self.every((item) => item.hp <= 0);
1287
+ const goal = team.goal.every((item) => item.hp <= 0);
1288
+ if (self && goal) {
1289
+ return { over: true, type: "平局", win: "" };
1290
+ } else if (self) {
1291
+ return { over: true, type: team.isPK ? "防御方赢" : "敌方赢", win: "goal" };
1292
+ } else if (goal) {
1293
+ return { over: true, type: team.isPK ? "攻击方赢" : "我方赢", win: "self" };
1468
1294
  }
1469
- const _userId = BattleData.teamTemp[userId].for;
1470
- Object.keys(BattleData.teamTemp).forEach((item) => {
1471
- if (BattleData.teamTemp[item].for == _userId) {
1472
- teamList.push(User.getUserAttributeByUserId(item));
1295
+ return { over: false, type: "未结束", win: "" };
1296
+ },
1297
+ /** 清理战场 */
1298
+ clearBattleData(session) {
1299
+ const currentBattle = BattleData.lastPlay[session.userId];
1300
+ const allAgentList = [...currentBattle.goal, ...currentBattle.self];
1301
+ allAgentList.forEach((item) => {
1302
+ if (item.type == "玩家") {
1303
+ delete BattleData.lastPlay[item.userId];
1473
1304
  }
1474
1305
  });
1475
- return teamList;
1476
1306
  },
1477
- /** 创建队伍 */
1478
- async creatTeam(session) {
1479
- const { userId } = session;
1480
- if (BattleData.isTeamByUserId(userId)) {
1481
- await session.send(`${User.getUserName(userId)}:你已经加入了${BattleData.teamTemp[userId].for}的队伍,需要退出才可以重新创建!`);
1307
+ async play(session, atkType, select) {
1308
+ if (!BattleData.isBattle(session)) {
1309
+ await session.send("您并没有任何参与战斗。");
1482
1310
  return;
1483
1311
  }
1484
- BattleData.teamTemp[userId] = {
1485
- for: userId,
1486
- identity: "队长"
1487
- };
1488
- await session.send("创建队伍成功!发送 /队伍邀请 昵称 \n可对周围对应昵称玩家进行组队邀请!");
1489
- },
1490
- /** 邀请加入队伍 */
1491
- async invitationTeam(session, playName) {
1492
- const { userId } = session;
1493
- if (!BattleData.isTeamByUserId(userId)) {
1494
- await session.send(`你还没有创建队伍,请发送 /队伍创建 创建队伍吧!`);
1495
- return;
1312
+ const currentBattle = BattleData.lastPlay[session.userId];
1313
+ const allAgentList = [...currentBattle.goal, ...currentBattle.self].sort((a, b) => b.speed + b.gain.speed - (a.speed + a.gain.speed));
1314
+ const msgList = [];
1315
+ for (const agent of allAgentList) {
1316
+ const buffMsg = settlementBuff(agent);
1317
+ buffMsg && msgList.push(buffMsg);
1318
+ if (agent.hp <= 0) {
1319
+ if (agent.type == "玩家" && !User.userTempData[agent.userId]?.isDie) {
1320
+ User.userTempData[agent.userId].hp = 0;
1321
+ User.userTempData[agent.userId].isDie = true;
1322
+ }
1323
+ continue;
1324
+ }
1325
+ if (!agent.gain.dizziness) {
1326
+ let lifeGoalList = [];
1327
+ let lifeSelfList = [];
1328
+ if (agent.for == "self") {
1329
+ lifeGoalList = currentBattle.goal.filter((item) => item.for == "goal" && item.hp > 0);
1330
+ lifeSelfList = currentBattle.self.filter((item) => item.for == "self" && item.hp > 0);
1331
+ } else {
1332
+ lifeGoalList = currentBattle.self.filter((item) => item.for == "self" && item.hp > 0);
1333
+ lifeSelfList = currentBattle.goal.filter((item) => item.for == "goal" && item.hp > 0);
1334
+ }
1335
+ if (!lifeGoalList.length) continue;
1336
+ let selectGoal = {};
1337
+ let isMy = false;
1338
+ let funType = "普攻";
1339
+ if (!agent.gain.chaos) {
1340
+ if (agent.type == "玩家" && agent.userId == session.userId) {
1341
+ isMy = true;
1342
+ funType = atkType;
1343
+ selectGoal = lifeGoalList.find((item) => item.name == select) || lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1344
+ } else if (agent.type == "玩家") {
1345
+ selectGoal = lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1346
+ } else {
1347
+ selectGoal = lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1348
+ if (random(0, 10) < 4 && agent.fn?.length) {
1349
+ funType = getSkillFn(agent.fn);
1350
+ }
1351
+ }
1352
+ } else {
1353
+ const fliteMyList = allAgentList.filter((item) => item.id !== agent.id && item.hp > 0);
1354
+ if (!fliteMyList.length) continue;
1355
+ selectGoal = fliteMyList[Math.random() * fliteMyList.length];
1356
+ }
1357
+ const noralAtk = /* @__PURE__ */ __name(() => {
1358
+ const damageInfo = new Damage({ self: agent, goal: selectGoal }).result();
1359
+ giveDamage(agent, selectGoal, damageInfo);
1360
+ msgList.push(
1361
+ `${getLineupName(agent)} 使用普攻攻击了 ${getLineupName(selectGoal)},造成了${damageInfo.harm}伤害。` + moreDamageInfo(damageInfo)
1362
+ );
1363
+ }, "noralAtk");
1364
+ if (funType == "普攻") {
1365
+ noralAtk();
1366
+ } else {
1367
+ if (skillFn[funType]) {
1368
+ let _selectGoal = selectGoal;
1369
+ if (["治疗技" /* 治疗技 */, "增益技" /* 增益技 */].includes(skillFn[funType].type)) {
1370
+ _selectGoal = lifeSelfList.find((item) => item.name == select) || agent;
1371
+ }
1372
+ const selectFn = skillFn[funType];
1373
+ if (selectFn.mp == 0 || agent.mp - selectFn.mp >= 0) {
1374
+ agent.mp -= selectFn.mp;
1375
+ let isNext = false;
1376
+ const fnMsg = selectFn.fn(
1377
+ { self: agent, goal: _selectGoal },
1378
+ { selfList: lifeSelfList, goalList: lifeGoalList },
1379
+ (val) => {
1380
+ switch (val.type) {
1381
+ case "伤害技" /* 伤害技 */:
1382
+ val.target.map((goal) => {
1383
+ giveDamage(agent, goal, val.damage);
1384
+ });
1385
+ break;
1386
+ case "治疗技" /* 治疗技 */:
1387
+ val.target.map((goal) => {
1388
+ giveCure(goal, val.value);
1389
+ });
1390
+ break;
1391
+ case "增益技" /* 增益技 */:
1392
+ isMy && val.err && session.send(val.err);
1393
+ break;
1394
+ case "释放失败" /* 释放失败 */:
1395
+ isMy && val.err && session.send(val.err);
1396
+ default:
1397
+ break;
1398
+ }
1399
+ isNext = val.isNext;
1400
+ }
1401
+ );
1402
+ fnMsg && msgList.push(fnMsg);
1403
+ isNext && noralAtk();
1404
+ } else {
1405
+ isMy && await session.send(`MP不足,释放失败!`);
1406
+ noralAtk();
1407
+ }
1408
+ } else {
1409
+ isMy && await session.send(`未持有该技能或者该技能不存在,释放失败!`);
1410
+ noralAtk();
1411
+ }
1412
+ }
1413
+ }
1496
1414
  }
1497
- const teamInfo = BattleData.teamTemp[userId];
1498
- if (teamInfo.identity !== "队长") {
1499
- await session.send(`你不是小队队长,无法邀请玩家加入!`);
1500
- return;
1415
+ await session.send(msgList.length ? `战斗记录:
1416
+ ` + msgList.join("\n") : "");
1417
+ await session.send(BattleData.battleSituationTextFormat(currentBattle));
1418
+ const result = BattleData.playOver(currentBattle);
1419
+ if (result.over) {
1420
+ await session.send(result.type);
1421
+ await BattleData.settlement(currentBattle, result, session);
1422
+ BattleData.clearBattleData(session);
1501
1423
  }
1502
- const nearUser = GensokyoMap.nearbyPlayersByUserId(userId);
1503
- const invitationUser = nearUser.find((item) => item.playName == playName);
1504
- if (!invitationUser) {
1505
- await session.send(`玩家${playName}不在你附近,邀请失败!`);
1506
- return;
1424
+ },
1425
+ /** 结算奖励 */
1426
+ async settlement(tempData, overInfo, session) {
1427
+ const allList = [...tempData.self, ...tempData.goal].filter((item) => item.type == "玩家");
1428
+ const selfList = tempData.self.filter((item) => item.type == "玩家");
1429
+ const goalList = tempData.goal.filter((item) => item.type == "玩家");
1430
+ const msg = /* @__PURE__ */ __name(async (val) => {
1431
+ const msgTemp = `${val.name}[升级]${val.lv}级!
1432
+ ` + (val.atk ? `攻击力↑ ${val.atk}
1433
+ ` : "") + (val.def ? `防御力↑ ${val.def}
1434
+ ` : "") + (val.maxHp ? `最大血量↑ ${val.maxHp}
1435
+ ` : "") + (val.maxMp ? `最大蓝量↑ ${val.maxMp}` : "");
1436
+ await session.send(msgTemp);
1437
+ }, "msg");
1438
+ const aynchronize = /* @__PURE__ */ __name((agent) => {
1439
+ User.userTempData[agent.userId].hp = agent.hp > 0 ? agent.hp : 0;
1440
+ User.userTempData[agent.userId].mp = agent.mp;
1441
+ if (User.userTempData[agent.userId].hp <= 0) {
1442
+ User.userTempData[agent.userId].isDie = true;
1443
+ }
1444
+ }, "aynchronize");
1445
+ if (tempData.isPK) {
1446
+ if (overInfo.win == "self") {
1447
+ await session.send("攻击方获得20EXP、5货币");
1448
+ for (const agent of allList) {
1449
+ aynchronize(agent);
1450
+ if (agent.for == "self") {
1451
+ await User.giveExp(agent.userId, 20, async (val) => await msg(val));
1452
+ await User.giveMonetary(agent.userId, 5);
1453
+ }
1454
+ }
1455
+ } else if (overInfo.win == "goal") {
1456
+ await session.send("防御方获得20EXP、5货币");
1457
+ for (const agent of allList) {
1458
+ aynchronize(agent);
1459
+ if (agent.for == "goal") {
1460
+ await User.giveExp(agent.userId, 20, async (val) => await msg(val));
1461
+ await User.giveMonetary(agent.userId, 5);
1462
+ }
1463
+ }
1464
+ }
1465
+ } else {
1466
+ let val = 0;
1467
+ let monetary = 0;
1468
+ let props = [];
1469
+ const monsterName = tempData.goal.filter((item) => item.type == "怪物").map((i) => ({ name: i.name, lv: i.lv }));
1470
+ monsterName.forEach((item) => {
1471
+ const monster = Monster.monsterTempData[item.name];
1472
+ if (monster) {
1473
+ val += Math.floor(monster.giveExp + monster.giveExp * (item.lv - 1) * 0.2);
1474
+ monetary += Math.floor(monster.giveMonetary + monster.giveExp * (item.lv - 1) * 0.1);
1475
+ monster.giveProps?.forEach((propsItem) => {
1476
+ if (item.lv >= (propsItem.lv || 1) && random(0, 100) < propsItem.radomVal) {
1477
+ props.push({
1478
+ name: propsItem.name,
1479
+ val: propsItem.const ? propsItem.val : random(1, propsItem.val)
1480
+ });
1481
+ }
1482
+ });
1483
+ }
1484
+ });
1485
+ if (overInfo.win == "self") {
1486
+ await session.send(`小队获得${val}EXP、${monetary}货币!`);
1487
+ }
1488
+ for (const agent of selfList) {
1489
+ aynchronize(agent);
1490
+ if (overInfo.win == "self") {
1491
+ await User.giveExp(agent.userId, val, async (val2) => await msg(val2));
1492
+ await User.giveMonetary(agent.userId, monetary);
1493
+ props.length && await User.giveProps(agent.userId, props, async (val2) => {
1494
+ const propsDict = {};
1495
+ val2.currentProps.forEach((item) => {
1496
+ if (!propsDict[item.name]) propsDict[item.name] = 0;
1497
+ propsDict[item.name]++;
1498
+ });
1499
+ const msg2 = Object.keys(propsDict).map((item) => {
1500
+ return `${item} ${propsDict[item]}个`;
1501
+ }).join("\n");
1502
+ await session.send(`${agent.name}在战斗中获得:` + msg2);
1503
+ });
1504
+ }
1505
+ }
1507
1506
  }
1508
- if (BattleData.isTeamByUserId(invitationUser.userId)) {
1509
- await session.send(`对方已经组队,或者已经在队伍中!`);
1510
- return;
1507
+ }
1508
+ };
1509
+ function getLineupName(agent) {
1510
+ return `[${agent.type}]${agent.name}`;
1511
+ }
1512
+ __name(getLineupName, "getLineupName");
1513
+ function getSkillFn(fnList) {
1514
+ const totalProb = fnList.reduce((sum, item) => sum + item.prob, 0);
1515
+ const random2 = Math.random() * totalProb;
1516
+ let currentProb = 0;
1517
+ for (const item of fnList) {
1518
+ currentProb += item.prob;
1519
+ if (random2 < currentProb) {
1520
+ return item.name;
1511
1521
  }
1512
- BattleData.invitationTemp[invitationUser.userId] = {
1513
- time: Date.now(),
1514
- for: userId,
1515
- playName: User.getUserName(userId),
1516
- seen: false
1522
+ }
1523
+ return fnList[fnList.length - 1].name;
1524
+ }
1525
+ __name(getSkillFn, "getSkillFn");
1526
+ function initBattleAttribute(data) {
1527
+ if ("playName" in data) {
1528
+ const userData = data;
1529
+ const temp = {
1530
+ id: Date.now(),
1531
+ userId: userData.userId,
1532
+ name: userData.playName,
1533
+ lv: userData.lv,
1534
+ type: "玩家",
1535
+ selfType: userData.type,
1536
+ hp: userData.hp,
1537
+ maxHp: userData.maxHp,
1538
+ mp: userData.mp,
1539
+ maxMp: userData.maxMp,
1540
+ atk: userData.atk,
1541
+ def: userData.def,
1542
+ chr: userData.chr,
1543
+ ghd: userData.ghd,
1544
+ csr: userData.csr,
1545
+ evasion: userData.evasion,
1546
+ hit: userData.hit,
1547
+ speed: userData.speed,
1548
+ gain: {
1549
+ maxHp: 0,
1550
+ maxMp: 0,
1551
+ atk: 0,
1552
+ def: 0,
1553
+ chr: 0,
1554
+ ghd: 0,
1555
+ evasion: 0,
1556
+ hit: 0,
1557
+ speed: 0,
1558
+ chaos: false,
1559
+ dizziness: false,
1560
+ reduction: 0
1561
+ },
1562
+ buff: {},
1563
+ fn: [],
1564
+ expand: {}
1517
1565
  };
1518
- await session.send(`已经发送邀请,等待TA的 /队伍加入 操作`);
1519
- },
1520
- /** 加入队伍 */
1521
- async joinTeam(session) {
1522
- const { userId } = session;
1523
- if (!BattleData.invitationTemp[userId]) {
1524
- await session.send("当前最后记录中无人邀请你加入队伍...");
1525
- return;
1526
- }
1527
- if (BattleData.isTeamByUserId(userId)) {
1528
- await session.send(`你已经在队伍中,无法再次加入,若需要加入请发送 /队伍退出`);
1529
- return;
1530
- }
1531
- const invInfo = BattleData.invitationTemp[userId];
1532
- if (Date.now() - invInfo.time > 36e5) {
1533
- await session.send(`${invInfo.playName}的邀请队伍请求已超时!`);
1534
- delete BattleData.invitationTemp[userId];
1535
- return;
1536
- }
1537
- if (BattleData.teamListByUser(invInfo.for).length >= 4) {
1538
- await session.send(`${invInfo.playName}的队伍人员已满!无法加入`);
1539
- return;
1540
- }
1541
- BattleData.teamTemp[userId] = {
1542
- for: invInfo.for,
1543
- identity: "队员"
1566
+ return temp;
1567
+ } else {
1568
+ const monsterData2 = data;
1569
+ const temp = {
1570
+ id: Date.now(),
1571
+ name: monsterData2.name,
1572
+ type: "怪物",
1573
+ selfType: monsterData2.type,
1574
+ lv: monsterData2.lv,
1575
+ hp: monsterData2.hp,
1576
+ maxHp: monsterData2.maxHp,
1577
+ mp: monsterData2.mp,
1578
+ maxMp: monsterData2.maxMp,
1579
+ atk: monsterData2.atk,
1580
+ def: monsterData2.def,
1581
+ chr: monsterData2.chr,
1582
+ ghd: monsterData2.ghd,
1583
+ csr: monsterData2.csr,
1584
+ evasion: monsterData2.evasion,
1585
+ hit: monsterData2.hit,
1586
+ speed: monsterData2.speed,
1587
+ gain: {
1588
+ maxHp: 0,
1589
+ maxMp: 0,
1590
+ atk: 0,
1591
+ def: 0,
1592
+ chr: 0,
1593
+ ghd: 0,
1594
+ evasion: 0,
1595
+ hit: 0,
1596
+ speed: 0,
1597
+ chaos: false,
1598
+ dizziness: false,
1599
+ reduction: 0
1600
+ },
1601
+ buff: {},
1602
+ fn: monsterData2.fn ? JSON.parse(JSON.stringify(monsterData2.fn)) : [],
1603
+ expand: {}
1544
1604
  };
1545
- await session.send(`加入${invInfo.playName}的队伍成功!
1546
- 若后续需要退出可发送 /队伍退出`);
1547
- },
1548
- /** 退出队伍 */
1549
- async exitTeam(session) {
1550
- const { userId } = session;
1551
- if (!BattleData.isTeamByUserId(userId)) {
1552
- await session.send("你还没有加入任何队伍!");
1553
- return;
1554
- }
1555
- if (BattleData.teamTemp[userId].identity == "队长") {
1556
- await session.send("你是小队队长,无法退出。若要解散队伍,请发送 /队伍解散");
1557
- return;
1558
- }
1559
- const teamName = User.getUserName(BattleData.teamTemp[userId].for);
1560
- delete BattleData.teamTemp[userId];
1561
- await session.send(`退出${teamName}的小队成功!`);
1562
- },
1563
- /** 解散队伍 */
1564
- async dissolveTeam(session) {
1565
- const { userId } = session;
1566
- if (!BattleData.isTeamByUserId(userId)) {
1567
- await session.send("你还没有加入任何队伍!");
1568
- return;
1569
- }
1570
- if (BattleData.teamTemp[userId].identity == "队员") {
1571
- await session.send("你不是小队队长,无法解散。");
1572
- return;
1573
- }
1574
- const team = BattleData.teamListByUser(userId);
1575
- team.forEach((item) => {
1576
- delete BattleData.teamTemp[item.userId];
1577
- });
1578
- await session.send("操作成功,已经解散你创建的小队。");
1579
- },
1580
- /** 创建战斗-与怪物 */
1581
- async createBattleByMonster(session, goal) {
1582
- if (BattleData.isBattle(session)) {
1583
- await session.send("当前正在战斗,还不能逃脱!");
1584
- return;
1585
- }
1586
- const battle_user = [];
1587
- const battle_monsterList = [];
1588
- const playUser = [];
1589
- if (BattleData.isTeam(session) && BattleData.teamTemp[session.userId].identity == "队员") {
1590
- await session.send("你不是队伍的队长,无法主动操作战斗!");
1591
- return;
1592
- } else if (BattleData.isTeam(session)) {
1593
- Object.keys(BattleData.teamTemp).forEach((item) => {
1594
- if (BattleData.teamTemp[item].for == session.userId) {
1595
- playUser.push(item);
1596
- battle_user.push(initBattleAttribute(User.getUserAttributeByUserId(item)));
1605
+ return temp;
1606
+ }
1607
+ }
1608
+ __name(initBattleAttribute, "initBattleAttribute");
1609
+
1610
+ // src/data/initProps.ts
1611
+ var propsData = {
1612
+ "红药": {
1613
+ name: "红药",
1614
+ type: "消耗类" /* 消耗类 */,
1615
+ info: "回复自身20HP",
1616
+ price: 10,
1617
+ fn: /* @__PURE__ */ __name(async function(session) {
1618
+ User.giveHPMP(session.userId, { hp: 20 }, async (val) => {
1619
+ if (val.err) {
1620
+ await session.send(val.err);
1621
+ return;
1597
1622
  }
1623
+ const msg = `回复成功,玩家当前血量:${val.currentHP}`;
1624
+ await session.send(msg);
1598
1625
  });
1599
- } else {
1600
- playUser.push(session.userId);
1601
- battle_user.push(initBattleAttribute(User.getUserAttributeByUserId(session.userId)));
1602
- }
1603
- goal.forEach((item) => {
1604
- battle_monsterList.push(initBattleAttribute(Monster.getMonsterAttributeData(item.name, item.lv)));
1605
- });
1606
- const temp = {
1607
- self: battle_user.map((i) => ({ ...i, for: "self" })),
1608
- goal: battle_monsterList.map((i) => ({ ...i, for: "goal" }))
1609
- };
1610
- playUser.forEach((userId) => {
1611
- BattleData.lastPlay[userId] = temp;
1612
- });
1613
- await session.send(`开始与 ${goal.map((i) => i.name).join("、")} 进行战斗`);
1626
+ }, "fn")
1614
1627
  },
1615
- /** 创建战斗-与玩家 */
1616
- async createBattleByUser(session, goal) {
1617
- if (BattleData.isBattle(session)) {
1618
- await session.send("当前正在战斗,还不能逃脱!");
1619
- return;
1620
- }
1621
- const battle_self = [];
1622
- const battle_goal = [];
1623
- const playUser = [];
1624
- const lostMsg = [];
1625
- goal = goal.filter((item) => {
1626
- const isBattle = BattleData.isBattleByUserId(item.userId);
1627
- const pyUser = User.userTempData[item.userId];
1628
- if (isBattle) {
1629
- lostMsg.push(`${pyUser.playName}正在参与着一场战斗,无法被PK选中。`);
1630
- return false;
1631
- }
1632
- return true;
1633
- });
1634
- if (lostMsg.length) {
1635
- await session.send(lostMsg.join("\n"));
1636
- }
1637
- if (!goal.length) {
1638
- lostMsg.push(`PK失败,无任何目标进行PK`);
1639
- return;
1640
- }
1641
- if (BattleData.isTeam(session) && BattleData.teamTemp[session.userId].identity == "队员") {
1642
- await session.send("你不是队伍的队长,无法主动操作战斗!");
1643
- return;
1644
- } else if (BattleData.isTeam(session)) {
1645
- Object.keys(BattleData.teamTemp).forEach((item) => {
1646
- if (BattleData.teamTemp[item].for == session.userId) {
1647
- playUser.push(item);
1648
- battle_self.push(initBattleAttribute(User.getUserAttributeByUserId(item)));
1628
+ "蓝药": {
1629
+ name: "蓝药",
1630
+ type: "消耗类" /* 消耗类 */,
1631
+ info: "回复自身20MP",
1632
+ price: 10,
1633
+ fn: /* @__PURE__ */ __name(async function(session) {
1634
+ User.giveHPMP(session.userId, { mp: 20 }, async (val) => {
1635
+ if (val.err) {
1636
+ await session.send(val.err);
1637
+ return;
1649
1638
  }
1639
+ const msg = `回复成功,玩家当前蓝量:${val.currentMP}`;
1640
+ await session.send(msg);
1650
1641
  });
1651
- } else {
1652
- playUser.push(session.userId);
1653
- battle_self.push(initBattleAttribute(User.getUserAttributeByUserId(session.userId)));
1654
- }
1655
- goal.forEach((item) => {
1656
- playUser.push(item.userId);
1657
- battle_goal.push(initBattleAttribute(User.getUserAttributeByUserId(item.userId)));
1658
- });
1659
- const pkTemp = {
1660
- self: battle_self.map((i) => ({ ...i, for: "self" })),
1661
- goal: battle_goal.map((i) => ({ ...i, for: "goal" })),
1662
- isPK: true
1663
- };
1664
- playUser.forEach((userId) => {
1665
- BattleData.lastPlay[userId] = pkTemp;
1666
- });
1667
- await session.send(`开始与玩家 ${battle_goal.map((i) => i.name).join("、")} 进行PK战斗`);
1642
+ }, "fn")
1668
1643
  },
1669
- /** 文本化当前战况 */
1670
- battleSituationTextFormat(team) {
1671
- const selfTemp = [];
1672
- const goalTemp = [];
1673
- const getBuffTemplate = /* @__PURE__ */ __name((agent) => {
1674
- const dict = { 1: "¹", 2: "²", 3: "³", 4: "⁴", 5: "⁵", 6: "⁶", 7: "⁷", 8: "⁸", 9: "⁹" };
1675
- const buffInfo = Object.keys(agent.buff).map((item) => {
1676
- return `${agent.buff[item].name}${dict[agent.buff[item].timer] || "⁺"}`;
1644
+ "初级万能药": {
1645
+ name: "初级万能药",
1646
+ type: "消耗类" /* 消耗类 */,
1647
+ info: "回复自身20MP和20HP",
1648
+ price: 20,
1649
+ fn: /* @__PURE__ */ __name(async function(session) {
1650
+ User.giveHPMP(session.userId, { hp: 20, mp: 20 }, async (val) => {
1651
+ if (val.err) {
1652
+ await session.send(val.err);
1653
+ return;
1654
+ }
1655
+ const msg = `回复成功,玩家当前血量:${val.currentHP}、蓝量:${val.currentMP}`;
1656
+ await session.send(msg);
1677
1657
  });
1678
- return buffInfo.length ? "(" + buffInfo.join(" ") + ")" : "";
1679
- }, "getBuffTemplate");
1680
- team.self.forEach((item) => {
1681
- if (item.hp > 0) {
1682
- selfTemp.push(`lv.${item.lv}[${item.name}]${getBuffTemplate(item)}:
1683
- ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${item.maxHp + item.gain.maxHp})
1684
- MP:${item.mp}/${item.maxMp + item.gain.maxMp}`);
1685
- } else {
1686
- selfTemp.push(`lv.${item.lv}[${item.name}]:已阵亡`);
1658
+ }, "fn")
1659
+ },
1660
+ "初级复活卷轴": {
1661
+ name: "初级复活卷轴",
1662
+ type: "消耗类" /* 消耗类 */,
1663
+ info: "复活玩家,复活时保留 20% 血量。(该道具使用完需要冷却 6 分钟)",
1664
+ price: 10,
1665
+ cooling: 3600,
1666
+ fn: /* @__PURE__ */ __name(async function(session) {
1667
+ if (BattleData.isBattleByUserId(session.userId)) {
1668
+ session.send(`该道具在战斗中无法使用!请在小队脱离战斗后使用。`);
1669
+ return { err: true };
1687
1670
  }
1688
- });
1689
- team.goal.forEach((item) => {
1690
- if (item.hp > 0) {
1691
- goalTemp.push(`lv.${item.lv}[${item.name}]${getBuffTemplate(item)}:
1692
- ${generateHealthDisplay(item.hp, item.maxHp + item.gain.maxHp)}(${item.hp}/${item.maxHp + item.gain.maxHp})
1693
- MP:${item.mp}/${item.maxMp + item.gain.maxMp}`);
1694
- } else {
1695
- goalTemp.push(`lv.${item.lv}[${item.name}]:已阵亡`);
1671
+ if (!User.isDie(session.userId)) {
1672
+ session.send(`您还没有阵亡,使用失败!`);
1673
+ return { err: true };
1696
1674
  }
1675
+ const { maxHp } = User.getUserAttributeByUserId(session.userId);
1676
+ User.giveLife(session.userId, Math.floor(maxHp * 0.2), async (val) => {
1677
+ await session.send(`复活成功,当前血量:${val.currentHP}`);
1678
+ });
1679
+ }, "fn")
1680
+ }
1681
+ };
1682
+
1683
+ // src/props.ts
1684
+ var Props = {
1685
+ config: {},
1686
+ ctx: {},
1687
+ userPorpsTemp: {},
1688
+ async init(config, ctx) {
1689
+ Props.config = config;
1690
+ Props.ctx = ctx;
1691
+ ctx.database.extend("smm_gensokyo_user_props", {
1692
+ userId: "string",
1693
+ props: "json"
1694
+ }, {
1695
+ primary: "userId",
1696
+ autoInc: false
1697
1697
  });
1698
- if (team.isPK) {
1699
- return `[当前战况]
1700
- 攻击方:
1701
- ` + selfTemp.join("\n") + "\n\n防御方:\n" + goalTemp.join("\n");
1702
- }
1703
- return `[当前战况]
1704
- 我方阵容:
1705
- ` + selfTemp.join("\n") + "\n\n敌方阵容:\n" + goalTemp.join("\n");
1706
- },
1707
- /** 判断输赢 */
1708
- playOver(team) {
1709
- const self = team.self.every((item) => item.hp <= 0);
1710
- const goal = team.goal.every((item) => item.hp <= 0);
1711
- if (self && goal) {
1712
- return { over: true, type: "平局", win: "" };
1713
- } else if (self) {
1714
- return { over: true, type: team.isPK ? "防御方赢" : "敌方赢", win: "goal" };
1715
- } else if (goal) {
1716
- return { over: true, type: team.isPK ? "攻击方赢" : "我方赢", win: "self" };
1717
- }
1718
- return { over: false, type: "未结束", win: "" };
1719
- },
1720
- /** 清理战场 */
1721
- clearBattleData(session) {
1722
- const currentBattle = BattleData.lastPlay[session.userId];
1723
- const allAgentList = [...currentBattle.goal, ...currentBattle.self];
1724
- allAgentList.forEach((item) => {
1725
- if (item.type == "玩家") {
1726
- delete BattleData.lastPlay[item.userId];
1727
- }
1698
+ const temp = {};
1699
+ const propsList = await ctx.database.get("smm_gensokyo_user_props", {});
1700
+ propsList.forEach((item) => {
1701
+ temp[item.userId] = item.props;
1728
1702
  });
1703
+ Props.userPorpsTemp = temp;
1729
1704
  },
1730
- async play(session, atkType, select) {
1731
- if (!BattleData.isBattle(session)) {
1732
- await session.send("您并没有任何参与战斗。");
1733
- return;
1734
- }
1735
- const currentBattle = BattleData.lastPlay[session.userId];
1736
- const allAgentList = [...currentBattle.goal, ...currentBattle.self].sort((a, b) => b.speed - a.speed);
1737
- const msgList = [];
1738
- for (const agent of allAgentList) {
1739
- const buffMsg = settlementBuff(agent);
1740
- buffMsg && msgList.push(buffMsg);
1741
- if (agent.hp <= 0) {
1742
- if (agent.type == "玩家" && !User.userTempData[agent.userId]?.isDie) {
1743
- User.userTempData[agent.userId].hp = 0;
1744
- User.userTempData[agent.userId].isDie = true;
1745
- }
1746
- continue;
1747
- }
1748
- if (!agent.gain.dizziness) {
1749
- let lifeGoalList = [];
1750
- let lifeSelfList = [];
1751
- if (agent.for == "self") {
1752
- lifeGoalList = currentBattle.goal.filter((item) => item.for == "goal" && item.hp > 0);
1753
- lifeSelfList = currentBattle.self.filter((item) => item.for == "self" && item.hp > 0);
1754
- } else {
1755
- lifeGoalList = currentBattle.self.filter((item) => item.for == "self" && item.hp > 0);
1756
- lifeSelfList = currentBattle.goal.filter((item) => item.for == "goal" && item.hp > 0);
1757
- }
1758
- if (!lifeGoalList.length) continue;
1759
- let selectGoal = {};
1760
- let isMy = false;
1761
- let funType = "普攻";
1762
- if (!agent.gain.chaos) {
1763
- if (agent.type == "玩家" && agent.userId == session.userId) {
1764
- isMy = true;
1765
- funType = atkType;
1766
- selectGoal = lifeGoalList.find((item) => item.name == select) || lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1767
- } else if (agent.type == "玩家") {
1768
- selectGoal = lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1769
- } else {
1770
- selectGoal = lifeGoalList[Math.floor(Math.random() * lifeGoalList.length)];
1771
- if (random(0, 10) < 4 && agent.fn?.length) {
1772
- funType = getSkillFn(agent.fn);
1773
- }
1774
- }
1775
- } else {
1776
- const fliteMyList = allAgentList.filter((item) => item.id !== agent.id && item.hp > 0);
1777
- if (!fliteMyList.length) continue;
1778
- selectGoal = fliteMyList[Math.random() * fliteMyList.length];
1779
- }
1780
- const noralAtk = /* @__PURE__ */ __name(() => {
1781
- const damageInfo = new Damage({ self: agent, goal: selectGoal }).result();
1782
- giveDamage(agent, selectGoal, damageInfo);
1783
- msgList.push(
1784
- `${getLineupName(agent)} 使用普攻攻击了 ${getLineupName(selectGoal)},造成了${damageInfo.harm}伤害。` + moreDamageInfo(damageInfo)
1785
- );
1786
- }, "noralAtk");
1787
- if (funType == "普攻") {
1788
- noralAtk();
1789
- } else {
1790
- if (skillFn[funType]) {
1791
- let _selectGoal = selectGoal;
1792
- if (["治疗技" /* 治疗技 */, "增益技" /* 增益技 */].includes(skillFn[funType].type)) {
1793
- _selectGoal = lifeSelfList.find((item) => item.name == select) || agent;
1794
- }
1795
- const selectFn = skillFn[funType];
1796
- if (selectFn.mp == 0 || agent.mp - selectFn.mp >= 0) {
1797
- agent.mp -= selectFn.mp;
1798
- let isNext = false;
1799
- const fnMsg = selectFn.fn(
1800
- { self: agent, goal: _selectGoal },
1801
- { selfList: lifeSelfList, goalList: lifeGoalList },
1802
- (val) => {
1803
- switch (val.type) {
1804
- case "伤害技" /* 伤害技 */:
1805
- val.target.map((goal) => {
1806
- giveDamage(agent, goal, val.damage);
1807
- });
1808
- break;
1809
- case "治疗技" /* 治疗技 */:
1810
- val.target.map((goal) => {
1811
- giveCure(goal, val.value);
1812
- });
1813
- break;
1814
- case "增益技" /* 增益技 */:
1815
- isMy && val.err && session.send(val.err);
1816
- break;
1817
- case "释放失败" /* 释放失败 */:
1818
- isMy && val.err && session.send(val.err);
1819
- default:
1820
- break;
1821
- }
1822
- isNext = val.isNext;
1823
- }
1824
- );
1825
- fnMsg && msgList.push(fnMsg);
1826
- isNext && noralAtk();
1827
- } else {
1828
- isMy && await session.send(`MP不足,释放失败!`);
1829
- noralAtk();
1830
- }
1831
- } else {
1832
- isMy && await session.send(`未持有该技能或者该技能不存在,释放失败!`);
1833
- noralAtk();
1834
- }
1835
- }
1836
- }
1837
- }
1838
- await session.send(msgList.length ? `战斗记录:
1839
- ` + msgList.join("\n") : "");
1840
- await session.send(BattleData.battleSituationTextFormat(currentBattle));
1841
- const result = BattleData.playOver(currentBattle);
1842
- if (result.over) {
1843
- await session.send(result.type);
1844
- await BattleData.settlement(currentBattle, result, session);
1845
- BattleData.clearBattleData(session);
1705
+ /** 创建本地数据 */
1706
+ async initUserPropsData(userId) {
1707
+ if (!Props.userPorpsTemp[userId]) {
1708
+ Props.userPorpsTemp[userId] = {};
1709
+ const temp = {
1710
+ userId,
1711
+ props: {}
1712
+ };
1713
+ await Props.ctx.database.create("smm_gensokyo_user_props", temp);
1846
1714
  }
1847
1715
  },
1848
- /** 结算奖励 */
1849
- async settlement(tempData, overInfo, session) {
1850
- const allList = [...tempData.self, ...tempData.goal].filter((item) => item.type == "玩家");
1851
- const selfList = tempData.self.filter((item) => item.type == "玩家");
1852
- const goalList = tempData.goal.filter((item) => item.type == "玩家");
1853
- const msg = /* @__PURE__ */ __name(async (val) => {
1854
- const msgTemp = `${val.name}[升级]${val.lv}级!
1855
- ` + (val.atk ? `攻击力↑ ${val.atk}
1856
- ` : "") + (val.def ? `防御力↑ ${val.def}
1857
- ` : "") + (val.maxHp ? `最大血量↑ ${val.maxHp}
1858
- ` : "") + (val.maxMp ? `最大蓝量↑ ${val.maxMp}` : "");
1859
- await session.send(msgTemp);
1860
- }, "msg");
1861
- const aynchronize = /* @__PURE__ */ __name((agent) => {
1862
- User.userTempData[agent.userId].hp = agent.hp > 0 ? agent.hp : 0;
1863
- User.userTempData[agent.userId].mp = agent.mp;
1864
- if (User.userTempData[agent.userId].hp <= 0) {
1865
- User.userTempData[agent.userId].isDie = true;
1716
+ /** 获取持有道具信息 */
1717
+ async getPropsDataByUserId(userId) {
1718
+ await Props.initUserPropsData(userId);
1719
+ const userProps = Props.userPorpsTemp[userId];
1720
+ const msgList = Object.keys(userProps).map((item) => {
1721
+ return `${userProps[item].name}:${userProps[item].value}个`;
1722
+ });
1723
+ return msgList.length ? `当前您持有如下道具:
1724
+
1725
+ ` + msgList.join("\n") : "您没有任何道具...";
1726
+ },
1727
+ /** 更新本地数据库对应数据 */
1728
+ async setDatabasePropsData(userId) {
1729
+ const propsData2 = Props.userPorpsTemp[userId];
1730
+ if (propsData2) {
1731
+ const temp = {
1732
+ props: propsData2
1733
+ };
1734
+ await Props.ctx.database.set("smm_gensokyo_user_props", { userId }, temp);
1735
+ }
1736
+ },
1737
+ /** 使用指定道具 */
1738
+ async userProps(session, propsName) {
1739
+ const userId = session.userId;
1740
+ const userPropsData = Props.userPorpsTemp[userId];
1741
+ if (!userPropsData) return;
1742
+ if (!userPropsData[propsName]) {
1743
+ await session.send(`您似乎没有${propsName}这个道具...`);
1744
+ return;
1745
+ }
1746
+ if (propsData[propsName].cooling) {
1747
+ if (!coolingTemp[userId]) coolingTemp[userId] = {};
1748
+ if (!coolingTemp[userId][propsName]) coolingTemp[userId][propsName] = 0;
1749
+ const gapTime = Date.now() - coolingTemp[userId][propsName];
1750
+ if (gapTime < propsData[propsName].cooling) {
1751
+ await session.send(`该道具冷却还未结束,请等待${Math.ceil((coolingTemp[userId][propsName] - gapTime) / 60)}秒!`);
1752
+ return;
1753
+ } else {
1754
+ coolingTemp[userId][propsName] = Date.now();
1866
1755
  }
1867
- }, "aynchronize");
1868
- if (tempData.isPK) {
1869
- if (overInfo.win == "self") {
1870
- await session.send("攻击方获得20EXP、5货币");
1871
- for (const agent of allList) {
1872
- aynchronize(agent);
1873
- if (agent.for == "self") {
1874
- await User.giveExp(agent.userId, 20, async (val) => await msg(val));
1875
- await User.giveMonetary(agent.userId, 5);
1876
- }
1877
- }
1878
- } else if (overInfo.win == "goal") {
1879
- await session.send("防御方获得20EXP、5货币");
1880
- for (const agent of allList) {
1881
- aynchronize(agent);
1882
- if (agent.for == "goal") {
1883
- await User.giveExp(agent.userId, 20, async (val) => await msg(val));
1884
- await User.giveMonetary(agent.userId, 5);
1885
- }
1886
- }
1756
+ }
1757
+ User.loseProps(userId, { name: propsName, val: 1 }, async (val) => {
1758
+ if (val.err) {
1759
+ await session.send(val.err);
1760
+ return;
1887
1761
  }
1888
- } else {
1889
- let val = 0;
1890
- let monetary = 0;
1891
- let props = [];
1892
- const monsterName = tempData.goal.filter((item) => item.type == "怪物").map((i) => ({ name: i.name, lv: i.lv }));
1893
- monsterName.forEach((item) => {
1894
- const monster = Monster.monsterTempData[item.name];
1895
- if (monster) {
1896
- val += Math.floor(monster.giveExp + monster.giveExp * (item.lv - 1) * 0.2);
1897
- monetary += Math.floor(monster.giveMonetary + monster.giveExp * (item.lv - 1) * 0.1);
1898
- monster.giveProps?.forEach((propsItem) => {
1899
- if (item.lv >= (propsItem.lv || 1) && random(0, 100) < propsItem.radomVal) {
1900
- props.push({
1901
- name: propsItem.name,
1902
- val: propsItem.const ? propsItem.val : random(1, propsItem.val)
1903
- });
1904
- }
1905
- });
1762
+ if (propsData[propsName].cooling) {
1763
+ coolingTemp[userId];
1764
+ }
1765
+ const result = await propsData[propsName].fn(session);
1766
+ if (result && typeof result === "object" && "err" in result) {
1767
+ if (result.err) {
1768
+ await User.giveProps(userId, [{ name: propsName, val: 1 }]);
1906
1769
  }
1907
- });
1908
- if (overInfo.win == "self") {
1909
- await session.send(`小队获得${val}EXP、${monetary}货币!`);
1910
1770
  }
1911
- for (const agent of selfList) {
1912
- aynchronize(agent);
1913
- if (overInfo.win == "self") {
1914
- await User.giveExp(agent.userId, val, async (val2) => await msg(val2));
1915
- await User.giveMonetary(agent.userId, monetary);
1916
- props.length && await User.giveProps(agent.userId, props, async (val2) => {
1917
- const propsDict = {};
1918
- val2.currentProps.forEach((item) => {
1919
- if (!propsDict[item.name]) propsDict[item.name] = 0;
1920
- propsDict[item.name]++;
1921
- });
1922
- const msg2 = Object.keys(propsDict).map((item) => {
1923
- return `${item} ${propsDict[item]}个`;
1924
- }).join("\n");
1925
- await session.send(`${agent.name}在战斗中获得:` + msg2);
1926
- });
1771
+ });
1772
+ }
1773
+ };
1774
+ var coolingTemp = {};
1775
+
1776
+ // src/users.ts
1777
+ var UserOccDict = {
1778
+ ["剑士" /* 剑士 */]: {
1779
+ info: "擅长近战攻击,拥有强大的属性能力",
1780
+ initStatus: {
1781
+ userId: "",
1782
+ playName: "",
1783
+ type: "剑士" /* 剑士 */,
1784
+ exp: 0,
1785
+ maxExp: 100,
1786
+ lv: 1,
1787
+ hp: 120,
1788
+ maxHp: 120,
1789
+ mp: 80,
1790
+ maxMp: 80,
1791
+ pp: 100,
1792
+ maxPp: 100,
1793
+ atk: 12,
1794
+ def: 5,
1795
+ chr: 50,
1796
+ csr: 0,
1797
+ ghd: 1.2,
1798
+ speed: 5,
1799
+ evasion: 100,
1800
+ hit: 100
1801
+ }
1802
+ },
1803
+ ["法师" /* 法师 */]: {
1804
+ info: "精通元素魔法,能够打出爆发伤害",
1805
+ initStatus: {
1806
+ userId: "",
1807
+ playName: "",
1808
+ type: "法师" /* 法师 */,
1809
+ exp: 0,
1810
+ maxExp: 100,
1811
+ lv: 1,
1812
+ hp: 100,
1813
+ maxHp: 100,
1814
+ mp: 100,
1815
+ maxMp: 100,
1816
+ pp: 100,
1817
+ maxPp: 100,
1818
+ atk: 10,
1819
+ def: 2,
1820
+ chr: 50,
1821
+ csr: 0,
1822
+ ghd: 1.2,
1823
+ speed: 5,
1824
+ evasion: 100,
1825
+ hit: 100
1826
+ }
1827
+ },
1828
+ ["刺客" /* 刺客 */]: {
1829
+ info: "迅捷攻击,高闪避值的高敏玩家",
1830
+ initStatus: {
1831
+ userId: "",
1832
+ playName: "",
1833
+ type: "刺客" /* 刺客 */,
1834
+ exp: 0,
1835
+ maxExp: 100,
1836
+ lv: 1,
1837
+ hp: 90,
1838
+ maxHp: 90,
1839
+ mp: 70,
1840
+ maxMp: 70,
1841
+ pp: 100,
1842
+ maxPp: 100,
1843
+ atk: 8,
1844
+ def: 2,
1845
+ chr: 80,
1846
+ csr: 0,
1847
+ ghd: 1.3,
1848
+ speed: 6,
1849
+ evasion: 120,
1850
+ hit: 100
1851
+ }
1852
+ }
1853
+ };
1854
+ var User = {
1855
+ config: {},
1856
+ ctx: {},
1857
+ userTempData: {},
1858
+ async init(config, ctx) {
1859
+ User.config = config;
1860
+ User.ctx = ctx;
1861
+ ctx.model.extend(
1862
+ "smm_gensokyo_user_attribute",
1863
+ {
1864
+ userId: "string",
1865
+ playName: "string",
1866
+ type: "string",
1867
+ exp: "integer",
1868
+ lv: "integer",
1869
+ hp: "integer",
1870
+ mp: "integer",
1871
+ pp: "integer",
1872
+ isDie: "boolean"
1873
+ },
1874
+ {
1875
+ primary: "userId",
1876
+ autoInc: false
1877
+ }
1878
+ );
1879
+ const userData = await ctx.database.get("smm_gensokyo_user_attribute", {});
1880
+ const temp = {};
1881
+ userData.forEach((item) => {
1882
+ temp[item.userId] = item;
1883
+ });
1884
+ User.userTempData = temp;
1885
+ },
1886
+ /** 获取玩家名字 */
1887
+ getUserName(userId) {
1888
+ return User.userTempData[userId].playName || null;
1889
+ },
1890
+ /** 获取角色基础属性 */
1891
+ async getUserAttribute(session) {
1892
+ if (!User.userTempData[session.userId]) {
1893
+ await session.send("未创建账户,请发送 /开始注册 完成账号的注册!");
1894
+ return null;
1895
+ }
1896
+ return User.getUserAddLvAttribute(session.userId);
1897
+ },
1898
+ /** 获取角色实际等级属性数据 */
1899
+ getUserAddLvAttribute(userId) {
1900
+ const UserDict = User.userTempData[userId];
1901
+ if (!UserDict) return null;
1902
+ const UserData = {
1903
+ ...UserOccDict[UserDict.type].initStatus,
1904
+ lv: UserDict.lv,
1905
+ hp: UserDict.hp,
1906
+ mp: UserDict.mp,
1907
+ exp: UserDict.exp,
1908
+ pp: UserDict.pp,
1909
+ playName: UserDict.playName,
1910
+ userId: UserDict.userId
1911
+ };
1912
+ const lv = UserData.lv;
1913
+ const temp = {};
1914
+ const lvScope = Object.keys(userBenchmark).reverse().find((item) => Number(item) < lv) || 10;
1915
+ const useBenchmark = userBenchmark[lvScope];
1916
+ Object.keys(UserData).forEach((i) => {
1917
+ temp[i] = UserData[i];
1918
+ if (useBenchmark[i]) {
1919
+ if (i == "maxExp") {
1920
+ temp[i] = Math.floor(100 * useBenchmark[i] * (lv - 1)) || 100;
1921
+ } else {
1922
+ temp[i] += Math.floor(temp[i] * (useBenchmark[i] - 1) * (lv - 1));
1927
1923
  }
1928
1924
  }
1925
+ });
1926
+ return temp;
1927
+ },
1928
+ /** 通过 userId 获取角色属性 */
1929
+ getUserAttributeByUserId(userId) {
1930
+ return User.getUserAddLvAttribute(userId) || null;
1931
+ },
1932
+ /** 创建游戏账号 */
1933
+ async createPlayUser(session) {
1934
+ const [data] = await User.ctx.database.get("smm_gensokyo_user_attribute", { userId: session.userId });
1935
+ if (data) {
1936
+ await session.send("已存在账号,请勿重复创建!");
1937
+ return;
1929
1938
  }
1930
- }
1931
- };
1932
- function getLineupName(agent) {
1933
- return `[${agent.type}]${agent.name}`;
1934
- }
1935
- __name(getLineupName, "getLineupName");
1936
- function getSkillFn(fnList) {
1937
- const totalProb = fnList.reduce((sum, item) => sum + item.prob, 0);
1938
- const random2 = Math.random() * totalProb;
1939
- let currentProb = 0;
1940
- for (const item of fnList) {
1941
- currentProb += item.prob;
1942
- if (random2 < currentProb) {
1943
- return item.name;
1939
+ await session.send("请输入自己的游戏昵称:(60s)");
1940
+ const playname = await session.prompt(6e4);
1941
+ if (playname == void 0) return;
1942
+ const [repeat] = await User.ctx.database.get("smm_gensokyo_user_attribute", { playName: playname.trim() });
1943
+ if (repeat) {
1944
+ await session.send("名字重复,请更换一个名字。");
1945
+ return;
1946
+ }
1947
+ if (Object.keys(monsterData).includes(playname?.trim())) {
1948
+ await session.send("请不要设置怪物的名字!");
1949
+ return;
1950
+ }
1951
+ if (playname.trim().length > 6 || playname.trim().length < 1) {
1952
+ await session.send("名字长度有问题,要求小于 6个字,大于 1个字");
1953
+ return;
1954
+ }
1955
+ await session.send(`请输入要专职的职业:(60s)
1956
+ ${Object.keys(UserOccDict).map((i) => `【${i}】:${UserOccDict[i].info}`).join("\n")}`);
1957
+ let jobType = await session.prompt(6e4);
1958
+ if (jobType == void 0) return;
1959
+ while (!Object.keys(UserOccDict).includes(jobType)) {
1960
+ await session.send("未找到该职业,请重新选择!");
1961
+ jobType = await session.prompt(6e4);
1944
1962
  }
1945
- }
1946
- return fnList[fnList.length - 1].name;
1947
- }
1948
- __name(getSkillFn, "getSkillFn");
1949
- function initBattleAttribute(data) {
1950
- if ("playName" in data) {
1951
- const userData = data;
1952
1963
  const temp = {
1953
- id: Date.now(),
1954
- userId: userData.userId,
1955
- name: userData.playName,
1956
- lv: userData.lv,
1957
- type: "玩家",
1958
- selfType: userData.type,
1959
- hp: userData.hp,
1960
- maxHp: userData.maxHp,
1961
- mp: userData.mp,
1962
- maxMp: userData.maxMp,
1963
- atk: userData.atk,
1964
- def: userData.def,
1965
- chr: userData.chr,
1966
- ghd: userData.ghd,
1967
- csr: userData.csr,
1968
- evasion: userData.evasion,
1969
- hit: userData.hit,
1970
- speed: userData.speed,
1971
- gain: {
1972
- maxHp: 0,
1973
- maxMp: 0,
1974
- atk: 0,
1975
- def: 0,
1976
- chr: 0,
1977
- ghd: 0,
1978
- evasion: 0,
1979
- hit: 0,
1980
- speed: 0,
1981
- chaos: false,
1982
- dizziness: false,
1983
- reduction: 0
1984
- },
1985
- buff: {},
1986
- fn: [],
1987
- expand: {}
1964
+ userId: session.userId,
1965
+ playName: playname.trim(),
1966
+ type: jobType,
1967
+ hp: UserOccDict[jobType].initStatus.hp,
1968
+ pp: UserOccDict[jobType].initStatus.pp,
1969
+ mp: UserOccDict[jobType].initStatus.mp,
1970
+ lv: 1,
1971
+ exp: 0,
1972
+ isDie: false
1988
1973
  };
1989
- return temp;
1990
- } else {
1991
- const monsterData2 = data;
1974
+ User.ctx.database.create("smm_gensokyo_user_attribute", temp);
1975
+ User.userTempData[session.userId] = temp;
1976
+ await Props.initUserPropsData(session.userId);
1977
+ await session.send("创建成功!\n" + User.userAttributeTextFormat(session.userId));
1978
+ },
1979
+ /** 信息格式化 */
1980
+ userAttributeTextFormat(userId) {
1981
+ if (!User.userTempData[userId]) {
1982
+ return "没有找到您的角色信息";
1983
+ }
1984
+ const temp = User.getUserAttributeByUserId(userId);
1985
+ return `昵称:${temp.playName}
1986
+ 职位:${temp.type}
1987
+ 等级:${temp.lv} (${temp.exp}/${temp.maxExp})
1988
+ -----------------
1989
+ 【生命值】${temp.hp}/${temp.maxHp}
1990
+ 【魔法值】${temp.mp}/${temp.maxMp}
1991
+ 【活力值】${temp.pp}/${temp.maxPp}
1992
+ -----------------
1993
+ 【攻击力】${temp.atk} (+0)
1994
+ 【防御力】${temp.def} (+0)
1995
+ 【速度值】${temp.speed} (+0)
1996
+ 【闪避值】${temp.evasion} (+0)
1997
+ 【命中率】${(temp.hit / 10 + 100).toFixed(1)}% (+0%)
1998
+ 【暴击率】${(temp.chr / 10).toFixed(1)}% (+0%)
1999
+ 【暴击伤害】${(temp.ghd * 100).toFixed(1)}% (+0%)` + (temp.csr > 0 ? `
2000
+ 【暴击抵抗】${temp.csr}` : "");
2001
+ },
2002
+ /** 写入用户数据到数据库 */
2003
+ async setDatabaseUserAttribute(userId) {
2004
+ const userInfo = User.userTempData[userId];
2005
+ if (!userInfo) return;
1992
2006
  const temp = {
1993
- id: Date.now(),
1994
- name: monsterData2.name,
1995
- type: "怪物",
1996
- selfType: monsterData2.type,
1997
- lv: monsterData2.lv,
1998
- hp: monsterData2.hp,
1999
- maxHp: monsterData2.maxHp,
2000
- mp: monsterData2.mp,
2001
- maxMp: monsterData2.maxMp,
2002
- atk: monsterData2.atk,
2003
- def: monsterData2.def,
2004
- chr: monsterData2.chr,
2005
- ghd: monsterData2.ghd,
2006
- csr: monsterData2.csr,
2007
- evasion: monsterData2.evasion,
2008
- hit: monsterData2.hit,
2009
- speed: monsterData2.speed,
2010
- gain: {
2011
- maxHp: 0,
2012
- maxMp: 0,
2013
- atk: 0,
2014
- def: 0,
2015
- chr: 0,
2016
- ghd: 0,
2017
- evasion: 0,
2018
- hit: 0,
2019
- speed: 0,
2020
- chaos: false,
2021
- dizziness: false,
2022
- reduction: 0
2023
- },
2024
- buff: {},
2025
- fn: monsterData2.fn ? JSON.parse(JSON.stringify(monsterData2.fn)) : [],
2026
- expand: {}
2007
+ playName: userInfo.playName.trim(),
2008
+ hp: userInfo.hp,
2009
+ pp: userInfo.pp,
2010
+ mp: userInfo.mp,
2011
+ lv: userInfo.lv,
2012
+ exp: userInfo.exp
2027
2013
  };
2028
- return temp;
2029
- }
2030
- }
2031
- __name(initBattleAttribute, "initBattleAttribute");
2032
-
2033
- // src/data/initProps.ts
2034
- var propsData = {
2035
- "红药": {
2036
- name: "红药",
2037
- type: "消耗类" /* 消耗类 */,
2038
- info: "回复自身20HP",
2039
- price: 10,
2040
- fn: /* @__PURE__ */ __name(async function(session) {
2041
- User.giveHPMP(session.userId, { hp: 20 }, async (val) => {
2042
- if (val.err) {
2043
- await session.send(val.err);
2044
- return;
2045
- }
2046
- const msg = `回复成功,玩家当前血量:${val.currentHP}`;
2047
- await session.send(msg);
2048
- });
2049
- }, "fn")
2014
+ User.ctx.database.set("smm_gensokyo_user_attribute", { userId }, temp);
2015
+ },
2016
+ /** 给予玩家经验 */
2017
+ async giveExp(userId, value, fn) {
2018
+ const userInfo = User.userTempData[userId];
2019
+ if (!userInfo) return;
2020
+ const beforData = { ...User.getUserAttributeByUserId(userId) };
2021
+ let isUp = false;
2022
+ userInfo.exp += value;
2023
+ while (true) {
2024
+ const { maxExp } = User.getUserAttributeByUserId(userId);
2025
+ if (userInfo.exp < maxExp) break;
2026
+ userInfo.lv += 1;
2027
+ userInfo.exp -= maxExp;
2028
+ isUp = true;
2029
+ }
2030
+ if (isUp) {
2031
+ const afterData = User.getUserAttributeByUserId(userId);
2032
+ const upTemp = {
2033
+ name: afterData.playName,
2034
+ lv: afterData.lv,
2035
+ maxHp: afterData.maxHp - beforData.maxHp,
2036
+ maxMp: afterData.maxMp = beforData.maxMp,
2037
+ atk: afterData.atk - beforData.atk,
2038
+ def: afterData.def - beforData.def
2039
+ };
2040
+ fn && await fn(upTemp);
2041
+ }
2042
+ await User.setDatabaseUserAttribute(userId);
2043
+ },
2044
+ /** 给予玩家死亡 */
2045
+ async giveDie(userId) {
2046
+ const userInfo = User.userTempData[userId];
2047
+ userInfo.hp = 0;
2048
+ userInfo.isDie = true;
2049
+ await User.setDatabaseUserAttribute(userId);
2050
2050
  },
2051
- "蓝药": {
2052
- name: "蓝药",
2053
- type: "消耗类" /* 消耗类 */,
2054
- info: "回复自身20MP",
2055
- price: 10,
2056
- fn: /* @__PURE__ */ __name(async function(session) {
2057
- User.giveHPMP(session.userId, { mp: 20 }, async (val) => {
2058
- if (val.err) {
2059
- await session.send(val.err);
2060
- return;
2061
- }
2062
- const msg = `回复成功,玩家当前蓝量:${val.currentMP}`;
2063
- await session.send(msg);
2064
- });
2065
- }, "fn")
2051
+ /** 给予玩家复活 */
2052
+ async giveLife(userId, val, fn) {
2053
+ const userInfo = User.userTempData[userId];
2054
+ if (!val) {
2055
+ const { maxHp } = User.getUserAttributeByUserId(userId);
2056
+ userInfo.hp = maxHp;
2057
+ } else {
2058
+ userInfo.hp = val;
2059
+ }
2060
+ await User.setDatabaseUserAttribute(userId);
2061
+ fn && await fn({ currentHP: userInfo.hp });
2066
2062
  },
2067
- "初级万能药": {
2068
- name: "初级万能药",
2069
- type: "消耗类" /* 消耗类 */,
2070
- info: "回复自身20MP和20HP",
2071
- price: 20,
2072
- fn: /* @__PURE__ */ __name(async function(session) {
2073
- User.giveHPMP(session.userId, { hp: 20, mp: 20 }, async (val) => {
2074
- if (val.err) {
2075
- await session.send(val.err);
2076
- return;
2077
- }
2078
- const msg = `回复成功,玩家当前血量:${val.currentHP}、蓝量:${val.currentMP}`;
2079
- await session.send(msg);
2063
+ /** 给予玩家血量或者蓝量 */
2064
+ async giveHPMP(userId, value, fn) {
2065
+ const userInfo = User.userTempData[userId];
2066
+ if (!userInfo) return;
2067
+ if (userInfo.isDie) {
2068
+ fn && await fn({
2069
+ currentHP: 0,
2070
+ currentMP: 0,
2071
+ err: "角色已死亡,无法使用恢复道具。"
2080
2072
  });
2081
- }, "fn")
2082
- },
2083
- "初级复活卷轴": {
2084
- name: "初级复活卷轴",
2085
- type: "消耗类" /* 消耗类 */,
2086
- info: "复活玩家,复活时保留 20% 血量。(该道具使用完需要冷却 6 分钟)",
2087
- price: 10,
2088
- cooling: 3600,
2089
- fn: /* @__PURE__ */ __name(async function(session) {
2090
- if (BattleData.isBattleByUserId(session.userId)) {
2091
- session.send(`该道具在战斗中无法使用!请在小队脱离战斗后使用。`);
2092
- return { err: true };
2073
+ return;
2074
+ }
2075
+ if (BattleData.isBattleByUserId(userId)) {
2076
+ const { goal, self } = BattleData.lastPlay[userId];
2077
+ const agentAll = [...goal, ...self];
2078
+ const agent = agentAll.find((item) => item?.userId == userId);
2079
+ if (!agent) return;
2080
+ if (agent.hp + (value.hp || 0) < agent.maxHp) {
2081
+ agent.hp += value.hp || 0;
2082
+ } else {
2083
+ agent.hp = agent.maxHp;
2093
2084
  }
2094
- if (!User.isDie(session.userId)) {
2095
- session.send(`您还没有阵亡,使用失败!`);
2096
- return { err: true };
2085
+ if (agent.mp + (value.mp || 0) < agent.maxMp) {
2086
+ agent.mp += value.mp || 0;
2087
+ } else {
2088
+ agent.mp = agent.maxMp;
2097
2089
  }
2098
- const { maxHp } = User.getUserAttributeByUserId(session.userId);
2099
- User.giveLife(session.userId, Math.floor(maxHp * 0.2), async (val) => {
2100
- await session.send(`复活成功,当前血量:${val.currentHP}`);
2090
+ fn && await fn({
2091
+ currentHP: agent.hp,
2092
+ currentMP: agent.mp
2101
2093
  });
2102
- }, "fn")
2103
- }
2104
- };
2105
-
2106
- // src/props.ts
2107
- var Props = {
2108
- config: {},
2109
- ctx: {},
2110
- userPorpsTemp: {},
2111
- async init(config, ctx) {
2112
- Props.config = config;
2113
- Props.ctx = ctx;
2114
- ctx.database.extend("smm_gensokyo_user_props", {
2115
- userId: "string",
2116
- props: "json"
2117
- }, {
2118
- primary: "userId",
2119
- autoInc: false
2120
- });
2121
- const temp = {};
2122
- const propsList = await ctx.database.get("smm_gensokyo_user_props", {});
2123
- propsList.forEach((item) => {
2124
- temp[item.userId] = item.props;
2125
- });
2126
- Props.userPorpsTemp = temp;
2127
- },
2128
- /** 创建本地数据 */
2129
- async initUserPropsData(userId) {
2130
- if (!Props.userPorpsTemp[userId]) {
2131
- Props.userPorpsTemp[userId] = {};
2132
- const temp = {
2133
- userId,
2134
- props: {}
2135
- };
2136
- await Props.ctx.database.create("smm_gensokyo_user_props", temp);
2094
+ return;
2137
2095
  }
2138
- },
2139
- /** 获取持有道具信息 */
2140
- async getPropsDataByUserId(userId) {
2141
- await Props.initUserPropsData(userId);
2142
- const userProps = Props.userPorpsTemp[userId];
2143
- const msgList = Object.keys(userProps).map((item) => {
2144
- return `${userProps[item].name}:${userProps[item].value}个`;
2096
+ const { maxHp, maxMp } = User.getUserAttributeByUserId(userId);
2097
+ if (value.hp && !value.mp && userInfo.hp == maxHp) {
2098
+ fn && await fn({
2099
+ currentHP: userInfo.hp,
2100
+ currentMP: userInfo.mp,
2101
+ err: "当前血量已满,无需回复。"
2102
+ });
2103
+ return;
2104
+ }
2105
+ if (value.mp && !value.hp && userInfo.mp == maxMp) {
2106
+ fn && await fn({
2107
+ currentHP: userInfo.hp,
2108
+ currentMP: userInfo.mp,
2109
+ err: "当前蓝量已满,无需回复。"
2110
+ });
2111
+ return;
2112
+ }
2113
+ if (value.mp && value.hp && userInfo.mp == maxMp && userInfo.hp == maxHp) {
2114
+ fn && await fn({
2115
+ currentHP: userInfo.hp,
2116
+ currentMP: userInfo.mp,
2117
+ err: "当前状态全满,无需回复。"
2118
+ });
2119
+ return;
2120
+ }
2121
+ if (userInfo.hp + (value.hp || 0) < maxHp) {
2122
+ userInfo.hp += value.hp || 0;
2123
+ } else {
2124
+ userInfo.hp = maxHp;
2125
+ }
2126
+ if (userInfo.mp + (value.mp || 0) < maxHp) {
2127
+ userInfo.mp += value.mp || 0;
2128
+ } else {
2129
+ userInfo.mp = maxMp;
2130
+ }
2131
+ fn && await fn({
2132
+ currentHP: userInfo.hp,
2133
+ currentMP: userInfo.mp
2145
2134
  });
2146
- return msgList.length ? `当前您持有如下道具:
2147
-
2148
- ` + msgList.join("\n") : "您没有任何道具...";
2135
+ await User.setDatabaseUserAttribute(userId);
2149
2136
  },
2150
- /** 更新本地数据库对应数据 */
2151
- async setDatabasePropsData(userId) {
2152
- const propsData2 = Props.userPorpsTemp[userId];
2153
- if (propsData2) {
2154
- const temp = {
2155
- props: propsData2
2156
- };
2157
- await Props.ctx.database.set("smm_gensokyo_user_props", { userId }, temp);
2137
+ /** 给予玩家PP值 */
2138
+ async givePP(userId, value, fn) {
2139
+ const userInfo = User.userTempData[userId];
2140
+ if (!userInfo) return;
2141
+ const { maxPp } = User.getUserAttributeByUserId(userId);
2142
+ if (userInfo.pp + value < maxPp) {
2143
+ userInfo.pp += value;
2144
+ } else {
2145
+ userInfo.pp = maxPp;
2158
2146
  }
2147
+ fn && await fn({
2148
+ currentPP: userInfo.pp
2149
+ });
2150
+ await User.setDatabaseUserAttribute(userId);
2159
2151
  },
2160
- /** 使用指定道具 */
2161
- async userProps(session, propsName) {
2162
- const userId = session.userId;
2163
- const userPropsData = Props.userPorpsTemp[userId];
2164
- if (!userPropsData) return;
2165
- if (!userPropsData[propsName]) {
2166
- await session.send(`您似乎没有${propsName}这个道具...`);
2152
+ async lostPP(userId, value, fn) {
2153
+ const userInfo = User.userTempData[userId];
2154
+ if (!userInfo) return;
2155
+ if (userInfo.pp - value < 0) {
2156
+ fn && await fn({
2157
+ currentPP: userInfo.pp,
2158
+ err: "PP值不够,消耗失败!"
2159
+ });
2167
2160
  return;
2168
2161
  }
2169
- if (propsData[propsName].cooling) {
2170
- if (!coolingTemp[userId]) coolingTemp[userId] = {};
2171
- if (!coolingTemp[userId][propsName]) coolingTemp[userId][propsName] = 0;
2172
- const gapTime = Date.now() - coolingTemp[userId][propsName];
2173
- if (gapTime < propsData[propsName].cooling) {
2174
- await session.send(`该道具冷却还未结束,请等待${Math.ceil((coolingTemp[userId][propsName] - gapTime) / 60)}秒!`);
2175
- return;
2176
- } else {
2177
- coolingTemp[userId][propsName] = Date.now();
2178
- }
2162
+ userInfo.pp -= value;
2163
+ fn && await fn({
2164
+ currentPP: userInfo.pp
2165
+ });
2166
+ await User.setDatabaseUserAttribute(userId);
2167
+ },
2168
+ /** 给予玩家货币 */
2169
+ async giveMonetary(userId, val, fn) {
2170
+ const [bindData] = await User.ctx.database.get("binding", { pid: userId });
2171
+ if (bindData && val) {
2172
+ const [currentM] = await User.ctx.database.get("monetary", { uid: bindData.aid });
2173
+ await User.ctx.monetary.gain(bindData.aid, val);
2174
+ fn && await fn({ val, currentVal: currentM.value += val });
2179
2175
  }
2180
- User.loseProps(userId, { name: propsName, val: 1 }, async (val) => {
2181
- if (val.err) {
2182
- await session.send(val.err);
2183
- return;
2184
- }
2185
- if (propsData[propsName].cooling) {
2186
- coolingTemp[userId];
2187
- }
2188
- const result = await propsData[propsName].fn(session);
2189
- if (result && typeof result === "object" && "err" in result) {
2190
- if (result.err) {
2191
- await User.giveProps(userId, [{ name: propsName, val: 1 }]);
2192
- }
2176
+ },
2177
+ /** 收取玩家货币 */
2178
+ async lostMonetary(userId, val, fn) {
2179
+ const [bindData] = await User.ctx.database.get("binding", { pid: userId });
2180
+ if (bindData && val) {
2181
+ const [currentM] = await User.ctx.database.get("monetary", { uid: bindData.aid });
2182
+ if (currentM.value - val < 0) {
2183
+ fn && await fn({
2184
+ val: Math.abs(val),
2185
+ currentVal: currentM.value,
2186
+ err: "余额不足!"
2187
+ });
2188
+ return;
2193
2189
  }
2194
- });
2195
- }
2196
- };
2197
- var coolingTemp = {};
2198
-
2199
- // src/users.ts
2200
- var UserOccDict = {
2201
- ["剑士" /* 剑士 */]: {
2202
- info: "擅长近战攻击,拥有强大的属性能力",
2203
- initStatus: {
2204
- userId: "",
2205
- playName: "",
2206
- type: "剑士" /* 剑士 */,
2207
- exp: 0,
2208
- maxExp: 100,
2209
- lv: 1,
2210
- hp: 120,
2211
- maxHp: 120,
2212
- mp: 80,
2213
- maxMp: 80,
2214
- pp: 100,
2215
- maxPp: 100,
2216
- atk: 12,
2217
- def: 5,
2218
- chr: 50,
2219
- csr: 0,
2220
- ghd: 1.2,
2221
- speed: 5,
2222
- evasion: 100,
2223
- hit: 100
2190
+ await User.ctx.monetary.cost(bindData.aid, val);
2191
+ fn && await fn({
2192
+ val: Math.abs(val),
2193
+ currentVal: currentM.value - val
2194
+ });
2224
2195
  }
2225
2196
  },
2226
- ["法师" /* 法师 */]: {
2227
- info: "精通元素魔法,能够打出爆发伤害",
2228
- initStatus: {
2229
- userId: "",
2230
- playName: "",
2231
- type: "法师" /* 法师 */,
2232
- exp: 0,
2233
- maxExp: 100,
2234
- lv: 1,
2235
- hp: 100,
2236
- maxHp: 100,
2237
- mp: 100,
2238
- maxMp: 100,
2239
- pp: 100,
2240
- maxPp: 100,
2241
- atk: 10,
2242
- def: 2,
2243
- chr: 50,
2244
- csr: 0,
2245
- ghd: 1.2,
2246
- speed: 5,
2247
- evasion: 100,
2248
- hit: 100
2197
+ /** 给予玩家指定道具 */
2198
+ async giveProps(userId, props, fn) {
2199
+ const userProps = Props.userPorpsTemp[userId];
2200
+ if (!userProps) return;
2201
+ const upProps = [];
2202
+ for (const item of props) {
2203
+ const propsItem = propsData[item.name];
2204
+ if (!propsData[item.name]) continue;
2205
+ if (!userProps[item.name]) {
2206
+ userProps[item.name] = {
2207
+ name: propsItem.name,
2208
+ type: propsItem.type,
2209
+ value: 0
2210
+ };
2211
+ }
2212
+ userProps[item.name].value += item.val || 1;
2213
+ upProps.push({ name: item.name, val: userProps[item.name].value });
2249
2214
  }
2215
+ await Props.setDatabasePropsData(userId);
2216
+ fn && await fn({
2217
+ currentProps: upProps
2218
+ });
2250
2219
  },
2251
- ["刺客" /* 刺客 */]: {
2252
- info: "迅捷攻击,高闪避值的高敏玩家",
2253
- initStatus: {
2254
- userId: "",
2255
- playName: "",
2256
- type: "刺客" /* 刺客 */,
2257
- exp: 0,
2258
- maxExp: 100,
2259
- lv: 1,
2260
- hp: 90,
2261
- maxHp: 90,
2262
- mp: 70,
2263
- maxMp: 70,
2264
- pp: 100,
2265
- maxPp: 100,
2266
- atk: 8,
2267
- def: 2,
2268
- chr: 80,
2269
- csr: 0,
2270
- ghd: 1.3,
2271
- speed: 6,
2272
- evasion: 120,
2273
- hit: 100
2220
+ /** 去除玩家指定道具 */
2221
+ async loseProps(userId, props, fn) {
2222
+ const userProps = Props.userPorpsTemp[userId];
2223
+ const propsItem = propsData[props.name];
2224
+ if (!userProps) return;
2225
+ if (!propsItem) {
2226
+ fn && await fn({
2227
+ currentProps: { name: props.name, val: 0 },
2228
+ err: "该道具信息不存在!"
2229
+ });
2230
+ return;
2231
+ }
2232
+ if (!userProps[props.name]) {
2233
+ userProps[props.name] = {
2234
+ name: propsItem.name,
2235
+ type: propsItem.type,
2236
+ value: 0
2237
+ };
2238
+ }
2239
+ if (userProps[props.name].value - (props.val || 1) < 0) {
2240
+ fn && await fn({
2241
+ currentProps: { name: props.name, val: userProps[props.name].value },
2242
+ err: `道具数量不足!剩余${userProps[props.name].value}个。`
2243
+ });
2244
+ return;
2274
2245
  }
2246
+ userProps[props.name].value -= props.val || 1;
2247
+ if (userProps[props.name].value == 0) delete userProps[props.name];
2248
+ await Props.setDatabasePropsData(userId);
2249
+ fn && await fn({
2250
+ currentProps: { name: props.name, val: userProps[props.name]?.value || 0 }
2251
+ });
2252
+ },
2253
+ /** 目标是否死亡 */
2254
+ isDie(userId) {
2255
+ return User.userTempData[userId]?.isDie;
2275
2256
  }
2276
2257
  };
2277
- var User = {
2258
+
2259
+ // src/map.ts
2260
+ var delay = /* @__PURE__ */ __name((ms) => new Promise((resolve) => setTimeout(resolve, ms)), "delay");
2261
+ var GensokyoMap = {
2278
2262
  config: {},
2279
2263
  ctx: {},
2280
- userTempData: {},
2264
+ mapLocalData: {},
2265
+ userCurrentLoal: {},
2281
2266
  async init(config, ctx) {
2282
- User.config = config;
2283
- User.ctx = ctx;
2284
- ctx.model.extend(
2285
- "smm_gensokyo_user_attribute",
2286
- {
2287
- userId: "string",
2288
- playName: "string",
2289
- type: "string",
2290
- exp: "integer",
2291
- lv: "integer",
2292
- hp: "integer",
2293
- mp: "integer",
2294
- pp: "integer",
2295
- isDie: "boolean"
2296
- },
2297
- {
2298
- primary: "userId",
2299
- autoInc: false
2300
- }
2301
- );
2302
- const userData = await ctx.database.get("smm_gensokyo_user_attribute", {});
2303
- const temp = {};
2304
- userData.forEach((item) => {
2305
- temp[item.userId] = item;
2267
+ GensokyoMap.config = config;
2268
+ GensokyoMap.ctx = ctx;
2269
+ ctx.database.extend("smm_gensokyo_map_position", {
2270
+ userId: "string",
2271
+ floor: "integer",
2272
+ areaName: "string",
2273
+ moveing: "boolean",
2274
+ playName: "string"
2275
+ }, {
2276
+ primary: "userId",
2277
+ autoInc: false
2306
2278
  });
2307
- User.userTempData = temp;
2308
- },
2309
- /** 获取玩家名字 */
2310
- getUserName(userId) {
2311
- return User.userTempData[userId].playName || null;
2312
- },
2313
- /** 获取角色基础属性 */
2314
- async getUserAttribute(session) {
2315
- if (!User.userTempData[session.userId]) {
2316
- await session.send("未创建账户,请发送 /开始注册 完成账号的注册!");
2317
- return null;
2318
- }
2319
- return User.getUserAddLvAttribute(session.userId);
2320
- },
2321
- /** 获取角色实际等级属性数据 */
2322
- getUserAddLvAttribute(userId) {
2323
- const UserDict = User.userTempData[userId];
2324
- if (!UserDict) return null;
2325
- const UserData = {
2326
- ...UserOccDict[UserDict.type].initStatus,
2327
- lv: UserDict.lv,
2328
- hp: UserDict.hp,
2329
- mp: UserDict.mp,
2330
- exp: UserDict.exp,
2331
- pp: UserDict.pp,
2332
- playName: UserDict.playName,
2333
- userId: UserDict.userId
2334
- };
2335
- const lv = UserData.lv;
2336
- const temp = {};
2337
- const lvScope = Object.keys(userBenchmark).reverse().find((item) => Number(item) < lv) || 10;
2338
- const useBenchmark = userBenchmark[lvScope];
2339
- Object.keys(UserData).forEach((i) => {
2340
- temp[i] = UserData[i];
2341
- if (useBenchmark[i]) {
2342
- if (i == "maxExp") {
2343
- temp[i] = Math.floor(100 * useBenchmark[i] * (lv - 1)) || 100;
2344
- } else {
2345
- temp[i] += Math.floor(temp[i] * (useBenchmark[i] - 1) * (lv - 1));
2279
+ GensokyoMap.mapLocalData = {
2280
+ 1: {
2281
+ "地下墓穴": {
2282
+ floor: 1,
2283
+ areaName: "地下墓穴",
2284
+ type: "BOSS区" /* BOSS区 */,
2285
+ needLv: 10,
2286
+ down: "蜘蛛洞穴",
2287
+ monster: [{ name: "古明地觉", lv: 15 }]
2288
+ },
2289
+ "蜘蛛洞穴": {
2290
+ floor: 1,
2291
+ areaName: "蜘蛛洞穴",
2292
+ type: "冒险区" /* 冒险区 */,
2293
+ needLv: 1,
2294
+ top: "地下墓穴",
2295
+ down: "蜘蛛森林一"
2296
+ },
2297
+ "蜘蛛森林一": {
2298
+ floor: 1,
2299
+ areaName: "蜘蛛森林一",
2300
+ type: "冒险区" /* 冒险区 */,
2301
+ needLv: 1,
2302
+ monster: [{ name: "小蜘蛛", lv: 2 }],
2303
+ top: "蜘蛛洞穴",
2304
+ left: "蜘蛛森林二",
2305
+ right: "蜘蛛森林三",
2306
+ down: "蜘蛛森林通道"
2307
+ },
2308
+ "蜘蛛森林二": {
2309
+ floor: 1,
2310
+ areaName: "蜘蛛森林二",
2311
+ type: "冒险区" /* 冒险区 */,
2312
+ needLv: 1,
2313
+ right: "蜘蛛森林一"
2314
+ },
2315
+ "蜘蛛森林三": {
2316
+ floor: 1,
2317
+ areaName: "蜘蛛森林三",
2318
+ type: "冒险区" /* 冒险区 */,
2319
+ needLv: 1,
2320
+ left: "蜘蛛森林一",
2321
+ monster: [{ name: "大妖精", lv: 3 }]
2322
+ },
2323
+ "蜘蛛森林通道": {
2324
+ floor: 1,
2325
+ areaName: "蜘蛛森林通道",
2326
+ type: "冒险区" /* 冒险区 */,
2327
+ needLv: 1,
2328
+ top: "蜘蛛森林一",
2329
+ down: "中央广场"
2330
+ },
2331
+ "中央广场": {
2332
+ floor: 1,
2333
+ areaName: "中央广场",
2334
+ info: "一层的中心位置,梦开始的地方",
2335
+ npc: ["aipo"],
2336
+ type: "安全区" /* 安全区 */,
2337
+ needLv: 1,
2338
+ top: "蜘蛛森林通道",
2339
+ down: "新手村",
2340
+ left: "酒馆",
2341
+ right: "银行"
2342
+ },
2343
+ "酒馆": {
2344
+ floor: 1,
2345
+ areaName: "酒馆",
2346
+ type: "安全区" /* 安全区 */,
2347
+ needLv: 1,
2348
+ down: "传送门",
2349
+ right: "中央广场"
2350
+ },
2351
+ "银行": {
2352
+ floor: 1,
2353
+ areaName: "银行",
2354
+ type: "安全区" /* 安全区 */,
2355
+ needLv: 1,
2356
+ down: "1层-商店",
2357
+ left: "中央广场"
2358
+ },
2359
+ "1层-商店": {
2360
+ floor: 1,
2361
+ areaName: "1层-商店",
2362
+ type: "安全区" /* 安全区 */,
2363
+ needLv: 1,
2364
+ right: "农田",
2365
+ left: "新手村"
2366
+ },
2367
+ "传送门": {
2368
+ floor: 1,
2369
+ areaName: "传送门",
2370
+ type: "传送门" /* 传送门 */,
2371
+ needLv: 1,
2372
+ top: "酒馆",
2373
+ right: "新手村",
2374
+ left: "爱之湖"
2375
+ },
2376
+ "爱之湖": {
2377
+ floor: 1,
2378
+ areaName: "传送门",
2379
+ type: "安全区" /* 安全区 */,
2380
+ needLv: 1,
2381
+ right: "传送门"
2382
+ },
2383
+ "新手村": {
2384
+ floor: 1,
2385
+ areaName: "新手村",
2386
+ type: "安全区" /* 安全区 */,
2387
+ needLv: 1,
2388
+ top: "中央广场",
2389
+ down: "绿野平原通道",
2390
+ left: "传送门",
2391
+ right: "1层-商店"
2392
+ },
2393
+ "绿野平原通道": {
2394
+ floor: 1,
2395
+ areaName: "绿野平原通道",
2396
+ type: "安全区" /* 安全区 */,
2397
+ needLv: 1,
2398
+ top: "新手村",
2399
+ down: "绿野平原一"
2400
+ },
2401
+ "绿野平原一": {
2402
+ floor: 1,
2403
+ areaName: "绿野平原一",
2404
+ type: "冒险区" /* 冒险区 */,
2405
+ monster: [{ name: "小蜜蜂", lv: 1 }, { name: "dora", lv: 2 }],
2406
+ needLv: 1,
2407
+ top: "绿野平原通道",
2408
+ left: "绿野平原二",
2409
+ right: "绿野平原三",
2410
+ down: "绿野平原四"
2411
+ },
2412
+ "绿野平原二": {
2413
+ floor: 1,
2414
+ areaName: "绿野平原二",
2415
+ type: "冒险区" /* 冒险区 */,
2416
+ monster: [{ name: "dora", lv: 2 }, { name: "dora", lv: 2 }, { name: "dora", lv: 3 }, { name: "dora", lv: 2 }],
2417
+ needLv: 1,
2418
+ right: "绿野平原一",
2419
+ down: "绿野平原五"
2420
+ },
2421
+ "绿野平原三": {
2422
+ floor: 1,
2423
+ areaName: "绿野平原三",
2424
+ type: "冒险区" /* 冒险区 */,
2425
+ monster: [{ name: "dora", lv: 5 }],
2426
+ needLv: 1,
2427
+ left: "绿野平原一",
2428
+ down: "绿野平原六"
2429
+ },
2430
+ "绿野平原四": {
2431
+ floor: 1,
2432
+ areaName: "绿野平原四",
2433
+ type: "冒险区" /* 冒险区 */,
2434
+ needLv: 1,
2435
+ top: "绿野平原一",
2436
+ down: "野猪巢穴",
2437
+ left: "绿野平原五",
2438
+ right: "绿野平原六",
2439
+ monster: [{ name: "琪露诺", lv: 10 }]
2440
+ },
2441
+ "绿野平原五": {
2442
+ floor: 1,
2443
+ areaName: "绿野平原五",
2444
+ type: "冒险区" /* 冒险区 */,
2445
+ needLv: 1,
2446
+ top: "绿野平原二",
2447
+ right: "绿野平原四"
2448
+ },
2449
+ "绿野平原六": {
2450
+ floor: 1,
2451
+ areaName: "绿野平原六",
2452
+ type: "冒险区" /* 冒险区 */,
2453
+ needLv: 1,
2454
+ left: "绿野平原四",
2455
+ top: "绿野平原三",
2456
+ monster: [{ name: "绿毒蛇", lv: 12 }]
2457
+ },
2458
+ "野猪巢穴": {
2459
+ floor: 1,
2460
+ areaName: "野猪巢穴",
2461
+ type: "BOSS区" /* BOSS区 */,
2462
+ needLv: 15,
2463
+ top: "绿野平原四",
2464
+ monster: [{ name: "蓬莱山辉夜", lv: 20 }]
2346
2465
  }
2347
- }
2348
- });
2349
- return temp;
2350
- },
2351
- /** 通过 userId 获取角色属性 */
2352
- getUserAttributeByUserId(userId) {
2353
- return User.getUserAddLvAttribute(userId) || null;
2354
- },
2355
- /** 创建游戏账号 */
2356
- async createPlayUser(session) {
2357
- const [data] = await User.ctx.database.get("smm_gensokyo_user_attribute", { userId: session.userId });
2358
- if (data) {
2359
- await session.send("已存在账号,请勿重复创建!");
2360
- return;
2361
- }
2362
- await session.send("请输入自己的游戏昵称:(60s)");
2363
- const playname = await session.prompt(6e4);
2364
- if (playname == void 0) return;
2365
- const [repeat] = await User.ctx.database.get("smm_gensokyo_user_attribute", { playName: playname.trim() });
2366
- if (repeat) {
2367
- await session.send("名字重复,请更换一个名字。");
2368
- return;
2369
- }
2370
- if (Object.keys(monsterData).includes(playname?.trim())) {
2371
- await session.send("请不要设置怪物的名字!");
2372
- return;
2373
- }
2374
- if (playname.trim().length < 6 || playname.trim().length > 1) {
2375
- await session.send("名字长度有问题,要求小于 6个字,大于 1个字");
2376
- return;
2377
- }
2378
- await session.send(`请输入要专职的职业:(60s)
2379
- ${Object.keys(UserOccDict).map((i) => `【${i}】:${UserOccDict[i].info}`).join("\n")}`);
2380
- let jobType = await session.prompt(6e4);
2381
- if (jobType == void 0) return;
2382
- while (!Object.keys(UserOccDict).includes(jobType)) {
2383
- await session.send("未找到该职业,请重新选择!");
2384
- jobType = await session.prompt(6e4);
2385
- }
2386
- const temp = {
2387
- userId: session.userId,
2388
- playName: playname.trim(),
2389
- type: jobType,
2390
- hp: UserOccDict[jobType].initStatus.hp,
2391
- pp: UserOccDict[jobType].initStatus.pp,
2392
- mp: UserOccDict[jobType].initStatus.mp,
2393
- lv: 1,
2394
- exp: 0,
2395
- isDie: false
2466
+ },
2467
+ 2: {
2468
+ "传送门": {
2469
+ floor: 2,
2470
+ areaName: "传送门",
2471
+ type: "传送门" /* 传送门 */,
2472
+ needLv: 1,
2473
+ right: "希望之泉"
2474
+ },
2475
+ "希望之泉": {
2476
+ floor: 2,
2477
+ areaName: "希望之泉",
2478
+ type: "安全区" /* 安全区 */,
2479
+ needLv: 1,
2480
+ top: "爱之湖",
2481
+ down: "农田",
2482
+ left: "传送门",
2483
+ right: "2层-商店"
2484
+ },
2485
+ "爱之湖": {
2486
+ floor: 2,
2487
+ areaName: "爱之湖",
2488
+ type: "安全区" /* 安全区 */,
2489
+ needLv: 1,
2490
+ down: "希望之泉",
2491
+ right: "旅馆"
2492
+ },
2493
+ "农田": {
2494
+ floor: 2,
2495
+ areaName: "农田",
2496
+ type: "安全区" /* 安全区 */,
2497
+ needLv: 1,
2498
+ top: "希望之泉",
2499
+ right: "银行"
2500
+ },
2501
+ "银行": {
2502
+ floor: 2,
2503
+ areaName: "银行",
2504
+ type: "安全区" /* 安全区 */,
2505
+ needLv: 1,
2506
+ top: "2层-商店",
2507
+ left: "农田"
2508
+ },
2509
+ "旅馆": {
2510
+ floor: 2,
2511
+ areaName: "旅馆",
2512
+ type: "安全区" /* 安全区 */,
2513
+ needLv: 1,
2514
+ down: "2层-商店",
2515
+ left: "爱之湖"
2516
+ },
2517
+ "2层-商店": {
2518
+ floor: 2,
2519
+ areaName: "2层-商店",
2520
+ type: "安全区" /* 安全区 */,
2521
+ needLv: 1,
2522
+ right: "大草场"
2523
+ },
2524
+ "大草场": {
2525
+ floor: 2,
2526
+ areaName: "大草场",
2527
+ type: "安全区" /* 安全区 */,
2528
+ needLv: 1,
2529
+ left: "2层-商店",
2530
+ right: "森林岔口"
2531
+ },
2532
+ "森林岔口": {
2533
+ floor: 2,
2534
+ areaName: "森林岔口",
2535
+ type: "安全区" /* 安全区 */,
2536
+ needLv: 1,
2537
+ left: "大草场"
2538
+ }
2539
+ }
2396
2540
  };
2397
- User.ctx.database.create("smm_gensokyo_user_attribute", temp);
2398
- User.userTempData[session.userId] = temp;
2399
- await Props.initUserPropsData(session.userId);
2400
- await session.send("创建成功!\n" + User.userAttributeTextFormat(session.userId));
2541
+ console.log(JSON.stringify(GensokyoMap.mapLocalData));
2542
+ const userPoistionList = await ctx.database.get("smm_gensokyo_map_position", {});
2543
+ const poistionTemp = {};
2544
+ userPoistionList.forEach((poistion) => {
2545
+ poistion.moveing = false;
2546
+ poistionTemp[poistion.userId] = poistion;
2547
+ });
2548
+ GensokyoMap.userCurrentLoal = poistionTemp;
2401
2549
  },
2402
- /** 信息格式化 */
2403
- userAttributeTextFormat(userId) {
2404
- if (!User.userTempData[userId]) {
2405
- return "没有找到您的角色信息";
2406
- }
2407
- const temp = User.getUserAttributeByUserId(userId);
2408
- return `昵称:${temp.playName}
2409
- 职位:${temp.type}
2410
- 等级:${temp.lv} (${temp.exp}/${temp.maxExp})
2411
- -----------------
2412
- 【生命值】${temp.hp}/${temp.maxHp}
2413
- 【魔法值】${temp.mp}/${temp.maxMp}
2414
- 【活力值】${temp.pp}/${temp.maxPp}
2415
- -----------------
2416
- 【攻击力】${temp.atk} (+0)
2417
- 【防御力】${temp.def} (+0)
2418
- 【速度值】${temp.speed} (+0)
2419
- 【闪避值】${temp.evasion} (+0)
2420
- 【命中率】${(temp.hit / 10 + 100).toFixed(1)}% (+0%)
2421
- 【暴击率】${(temp.chr / 10).toFixed(1)}% (+0%)
2422
- 【暴击伤害】${(temp.ghd * 100).toFixed(1)}% (+0%)` + (temp.csr > 0 ? `
2423
- 【暴击抵抗】${temp.csr}` : "");
2550
+ /** 获取层的数据 */
2551
+ getBaseFloorLocal(floor) {
2552
+ return GensokyoMap.mapLocalData[floor] || null;
2424
2553
  },
2425
- /** 写入用户数据到数据库 */
2426
- async setDatabaseUserAttribute(userId) {
2427
- const userInfo = User.userTempData[userId];
2428
- if (!userInfo) return;
2429
- const temp = {
2430
- playName: userInfo.playName.trim(),
2431
- hp: userInfo.hp,
2432
- pp: userInfo.pp,
2433
- mp: userInfo.mp,
2434
- lv: userInfo.lv,
2435
- exp: userInfo.exp
2436
- };
2437
- User.ctx.database.set("smm_gensokyo_user_attribute", { userId }, temp);
2554
+ /** 获取用户当前区域信息 */
2555
+ getUserCurrentArea(userid) {
2556
+ const { floor, areaName } = GensokyoMap.userCurrentLoal[userid] || {};
2557
+ if (!(floor && areaName)) return null;
2558
+ return GensokyoMap.mapLocalData[floor][areaName] || null;
2438
2559
  },
2439
- /** 给予玩家经验 */
2440
- async giveExp(userId, value, fn) {
2441
- const userInfo = User.userTempData[userId];
2442
- if (!userInfo) return;
2443
- const beforData = { ...User.getUserAttributeByUserId(userId) };
2444
- let isUp = false;
2445
- userInfo.exp += value;
2446
- while (true) {
2447
- const { maxExp } = User.getUserAttributeByUserId(userId);
2448
- if (userInfo.exp < maxExp) break;
2449
- userInfo.lv += 1;
2450
- userInfo.exp -= maxExp;
2451
- isUp = true;
2452
- }
2453
- if (isUp) {
2454
- const afterData = User.getUserAttributeByUserId(userId);
2455
- const upTemp = {
2456
- name: afterData.playName,
2457
- lv: afterData.lv,
2458
- maxHp: afterData.maxHp - beforData.maxHp,
2459
- maxMp: afterData.maxMp = beforData.maxMp,
2460
- atk: afterData.atk - beforData.atk,
2461
- def: afterData.def - beforData.def
2560
+ /** 初始化用户位置 */
2561
+ initUserPoistion(session, userData) {
2562
+ if (!GensokyoMap.userCurrentLoal[session.userId]) {
2563
+ GensokyoMap.userCurrentLoal[session.userId] = {
2564
+ userId: session.userId,
2565
+ floor: 1,
2566
+ areaName: "传送门",
2567
+ moveing: false,
2568
+ playName: userData.playName
2462
2569
  };
2463
- fn && await fn(upTemp);
2464
2570
  }
2465
- await User.setDatabaseUserAttribute(userId);
2466
- },
2467
- /** 给予玩家死亡 */
2468
- async giveDie(userId) {
2469
- const userInfo = User.userTempData[userId];
2470
- userInfo.hp = 0;
2471
- userInfo.isDie = true;
2472
- await User.setDatabaseUserAttribute(userId);
2571
+ GensokyoMap.setLocalStoragePoistionData(session.userId);
2473
2572
  },
2474
- /** 给予玩家复活 */
2475
- async giveLife(userId, val, fn) {
2476
- const userInfo = User.userTempData[userId];
2477
- if (!val) {
2478
- const { maxHp } = User.getUserAttributeByUserId(userId);
2479
- userInfo.hp = maxHp;
2480
- } else {
2481
- userInfo.hp = val;
2573
+ /** 位置信息存储到数据库 */
2574
+ async setLocalStoragePoistionData(userId) {
2575
+ const poistionData = { ...GensokyoMap.userCurrentLoal[userId] };
2576
+ if (poistionData) {
2577
+ const [localData] = await GensokyoMap.ctx.database.get("smm_gensokyo_map_position", { userId });
2578
+ if (!localData) {
2579
+ await GensokyoMap.ctx.database.create("smm_gensokyo_map_position", poistionData);
2580
+ return;
2581
+ }
2582
+ delete poistionData.userId;
2583
+ await GensokyoMap.ctx.database.set("smm_gensokyo_map_position", { userId }, poistionData);
2482
2584
  }
2483
- await User.setDatabaseUserAttribute(userId);
2484
- fn && await fn({ currentHP: userInfo.hp });
2485
2585
  },
2486
- /** 给予玩家血量或者蓝量 */
2487
- async giveHPMP(userId, value, fn) {
2488
- const userInfo = User.userTempData[userId];
2489
- if (!userInfo) return;
2490
- if (userInfo.isDie) {
2491
- fn && await fn({
2492
- currentHP: 0,
2493
- currentMP: 0,
2494
- err: "角色已死亡,无法使用恢复道具。"
2495
- });
2496
- return;
2497
- }
2498
- if (BattleData.isBattleByUserId(userId)) {
2499
- const { goal, self } = BattleData.lastPlay[userId];
2500
- const agentAll = [...goal, ...self];
2501
- const agent = agentAll.find((item) => item?.userId == userId);
2502
- if (!agent) return;
2503
- if (agent.hp + (value.hp || 0) < agent.maxHp) {
2504
- agent.hp += value.hp || 0;
2505
- } else {
2506
- agent.hp = agent.maxHp;
2586
+ /** 用户移动 */
2587
+ async move(session, type, fn) {
2588
+ try {
2589
+ const userCurrentArea = GensokyoMap.userCurrentLoal[session.userId] || {};
2590
+ const { floor, areaName, moveing } = userCurrentArea;
2591
+ if (moveing) {
2592
+ await session.send("当前移动冷却中,请稍等...");
2593
+ return;
2507
2594
  }
2508
- if (agent.mp + (value.mp || 0) < agent.maxMp) {
2509
- agent.mp += value.mp || 0;
2510
- } else {
2511
- agent.mp = agent.maxMp;
2595
+ if (!(floor && areaName)) {
2596
+ await session.send("您当前位置有误,请使用(还没写好的指令)脱离卡死...");
2597
+ return;
2512
2598
  }
2513
- fn && await fn({
2514
- currentHP: agent.hp,
2515
- currentMP: agent.mp
2516
- });
2517
- return;
2518
- }
2519
- const { maxHp, maxMp } = User.getUserAttributeByUserId(userId);
2520
- if (value.hp && !value.mp && userInfo.hp == maxHp) {
2521
- fn && await fn({
2522
- currentHP: userInfo.hp,
2523
- currentMP: userInfo.mp,
2524
- err: "当前血量已满,无需回复。"
2525
- });
2526
- return;
2527
- }
2528
- if (value.mp && !value.hp && userInfo.mp == maxMp) {
2529
- fn && await fn({
2530
- currentHP: userInfo.hp,
2531
- currentMP: userInfo.mp,
2532
- err: "当前蓝量已满,无需回复。"
2533
- });
2534
- return;
2535
- }
2536
- if (value.mp && value.hp && userInfo.mp == maxMp && userInfo.hp == maxHp) {
2537
- fn && await fn({
2538
- currentHP: userInfo.hp,
2539
- currentMP: userInfo.mp,
2540
- err: "当前状态全满,无需回复。"
2541
- });
2599
+ userCurrentArea.moveing = true;
2600
+ const nowPosition = GensokyoMap.mapLocalData[floor][areaName];
2601
+ if (!nowPosition[type]) {
2602
+ await session.send("抱歉,此路不通!");
2603
+ userCurrentArea.moveing = false;
2604
+ return;
2605
+ }
2606
+ const newArea = GensokyoMap.mapLocalData[floor][nowPosition[type]];
2607
+ if (!newArea) {
2608
+ await session.send("进入失败,地图中不存在 " + nowPosition[type] + " 这个区域。");
2609
+ userCurrentArea.moveing = false;
2610
+ return;
2611
+ }
2612
+ if (newArea.type == "禁用" /* 禁用 */) {
2613
+ await session.send(`该区域暂时未开放...`);
2614
+ userCurrentArea.moveing = false;
2615
+ return;
2616
+ }
2617
+ if (newArea.needLv > User.userTempData[session.userId].lv) {
2618
+ await session.send(`当前区域由于您的等级未达到最低要求,暂时无法进入。
2619
+ 需要等级:${newArea.needLv}级`);
2620
+ userCurrentArea.moveing = false;
2621
+ return;
2622
+ }
2623
+ if (BattleData.isTeam(session)) {
2624
+ const { userId } = session;
2625
+ const myTeamList = [];
2626
+ Object.keys(BattleData.teamTemp).forEach((_userId) => {
2627
+ if (BattleData.teamTemp[userId].for == userId && userId !== _userId) {
2628
+ myTeamList.push(_userId);
2629
+ }
2630
+ });
2631
+ const belowUser = myTeamList.filter((teamUserId) => newArea.needLv > User.userTempData[teamUserId].lv);
2632
+ if (belowUser.length) {
2633
+ await session.send(
2634
+ `移动失败!队伍存在限制进入等级(lv.${newArea.needLv})玩家,
2635
+ 目前限制进入的玩家:
2636
+ ${belowUser.map((item) => {
2637
+ return `Lv.${User.userTempData[item].lv} ${User.userTempData[item].playName}`;
2638
+ }).join("\n")}`
2639
+ );
2640
+ userCurrentArea.moveing = false;
2641
+ return;
2642
+ }
2643
+ for (const moveTeamUserId of myTeamList) {
2644
+ GensokyoMap.userCurrentLoal[moveTeamUserId].areaName = newArea.areaName;
2645
+ GensokyoMap.userCurrentLoal[moveTeamUserId].floor = newArea.floor;
2646
+ GensokyoMap.userCurrentLoal[moveTeamUserId].moveing = false;
2647
+ await GensokyoMap.setLocalStoragePoistionData(moveTeamUserId);
2648
+ }
2649
+ }
2650
+ userCurrentArea.areaName = newArea.areaName;
2651
+ const areaInfo = {
2652
+ user: { ...userCurrentArea },
2653
+ map: { ...newArea }
2654
+ };
2655
+ fn && await fn(areaInfo);
2656
+ await delay(3e3);
2657
+ userCurrentArea.moveing = false;
2658
+ GensokyoMap.setLocalStoragePoistionData(session.userId);
2542
2659
  return;
2660
+ } catch (error) {
2661
+ console.log(error);
2662
+ if (GensokyoMap.userCurrentLoal?.[session.userId]) {
2663
+ GensokyoMap.userCurrentLoal[session.userId].moveing = false;
2664
+ }
2543
2665
  }
2544
- if (userInfo.hp + (value.hp || 0) < maxHp) {
2545
- userInfo.hp += value.hp || 0;
2546
- } else {
2547
- userInfo.hp = maxHp;
2548
- }
2549
- if (userInfo.mp + (value.mp || 0) < maxHp) {
2550
- userInfo.mp += value.mp || 0;
2551
- } else {
2552
- userInfo.mp = maxMp;
2553
- }
2554
- fn && await fn({
2555
- currentHP: userInfo.hp,
2556
- currentMP: userInfo.mp
2557
- });
2558
- await User.setDatabaseUserAttribute(userId);
2559
2666
  },
2560
- /** 给予玩家PP值 */
2561
- async givePP(userId, value, fn) {
2562
- const userInfo = User.userTempData[userId];
2563
- if (!userInfo) return;
2564
- const { maxPp } = User.getUserAttributeByUserId(userId);
2565
- if (userInfo.pp + value < maxPp) {
2566
- userInfo.pp += value;
2567
- } else {
2568
- userInfo.pp = maxPp;
2569
- }
2570
- fn && await fn({
2571
- currentPP: userInfo.pp
2667
+ /** 查询附近玩家 */
2668
+ nearbyPlayersByUserId(userId) {
2669
+ const areaData = GensokyoMap.getUserCurrentArea(userId);
2670
+ const liveUser = [];
2671
+ Object.keys(GensokyoMap.userCurrentLoal).forEach((_userId) => {
2672
+ const userItem = GensokyoMap.userCurrentLoal[_userId];
2673
+ if (userItem.areaName == areaData.areaName && userItem.floor == areaData.floor) {
2674
+ if (userId !== userItem.userId) {
2675
+ liveUser.push({ userId: userItem.userId, playName: userItem.playName });
2676
+ }
2677
+ }
2572
2678
  });
2573
- await User.setDatabaseUserAttribute(userId);
2679
+ return liveUser;
2574
2680
  },
2575
- async lostPP(userId, value, fn) {
2576
- const userInfo = User.userTempData[userId];
2577
- if (!userInfo) return;
2578
- if (userInfo.pp - value < 0) {
2579
- fn && await fn({
2580
- currentPP: userInfo.pp,
2581
- err: "PP值不够,消耗失败!"
2582
- });
2583
- return;
2584
- }
2585
- userInfo.pp -= value;
2586
- fn && await fn({
2587
- currentPP: userInfo.pp
2681
+ /** 区域信息格式化 */
2682
+ userAreaTextFormat(gameName, data) {
2683
+ const liveUser = [];
2684
+ Object.keys(GensokyoMap.userCurrentLoal).forEach((userId) => {
2685
+ const areaItem = GensokyoMap.userCurrentLoal[userId];
2686
+ if (areaItem.areaName == data.map.areaName && areaItem.floor == data.map.floor) {
2687
+ if (gameName !== areaItem.playName) {
2688
+ liveUser.push(areaItem.playName);
2689
+ }
2690
+ }
2588
2691
  });
2589
- await User.setDatabaseUserAttribute(userId);
2590
- },
2591
- /** 给予玩家货币 */
2592
- async giveMonetary(userId, val, fn) {
2593
- const [bindData] = await User.ctx.database.get("binding", { pid: userId });
2594
- if (bindData && val) {
2595
- const [currentM] = await User.ctx.database.get("monetary", { uid: bindData.aid });
2596
- await User.ctx.monetary.gain(bindData.aid, val);
2597
- fn && await fn({ val, currentVal: currentM.value += val });
2692
+ const str = `${gameName}[萌新] 当前位置:
2693
+ `;
2694
+ const mapInfo = `区域:【${data.map.areaName}】
2695
+ ` + (data.map.info ? data.map.info + "\n\n" : "\n") + (data.map.top ? `上:【${data.map.top}】
2696
+ ` : "") + (data.map.down ? `下:【${data.map.down}
2697
+ ` : "") + (data.map.left ? `左:【${data.map.left}】
2698
+ ` : "") + (data.map.right ? `右:【${data.map.right}
2699
+ ` : "") + (data.map.type == "传送门" /* 传送门 */ ? `
2700
+ [!]传送门区域` : "") + (data.map.shopName ? `
2701
+ [!]存在商店:${data.map.shopName}` : "") + (data.map.npc ? `
2702
+ [!]存在npc:${data.map.npc.join("、")}` : "") + (data.map.monster ? `
2703
+ [!]存在野怪:${data.map.monster.map((i) => `lv.${i.lv} ${i.name}`).join("、")}` : "") + (liveUser.length ? `
2704
+ [!]区域玩家:${liveUser.length > 3 ? liveUser.slice(0, 3).join("、") + `...等${liveUser.length}` : liveUser.join("、")}` : "");
2705
+ return str + mapInfo;
2706
+ }
2707
+ };
2708
+
2709
+ // src/mapHtml.ts
2710
+ function generateMapHTML(mapData, currentAreaName) {
2711
+ const centerKey = Object.keys(mapData).find((key) => mapData[key].type === "传送门");
2712
+ if (!centerKey) {
2713
+ return "<div>未找到传送门区域</div>";
2714
+ }
2715
+ const visited = /* @__PURE__ */ new Set();
2716
+ const grid = {};
2717
+ let minRow = 0, maxRow = 0, minCol = 0, maxCol = 0;
2718
+ function placeArea(key, row, col) {
2719
+ if (visited.has(key)) return;
2720
+ visited.add(key);
2721
+ const area = mapData[key];
2722
+ if (!area) return;
2723
+ const connections = {
2724
+ top: false,
2725
+ left: false,
2726
+ right: false,
2727
+ down: false
2728
+ };
2729
+ if (!grid[row]) grid[row] = {};
2730
+ grid[row][col] = { area, key, row, col, connections };
2731
+ minRow = Math.min(minRow, row);
2732
+ maxRow = Math.max(maxRow, row);
2733
+ minCol = Math.min(minCol, col);
2734
+ maxCol = Math.max(maxCol, col);
2735
+ if (area.top) {
2736
+ placeArea(area.top, row - 1, col);
2737
+ connections.top = true;
2738
+ if (grid[row - 1]?.[col]) {
2739
+ grid[row - 1][col].connections.down = true;
2740
+ }
2598
2741
  }
2599
- },
2600
- /** 收取玩家货币 */
2601
- async lostMonetary(userId, val, fn) {
2602
- const [bindData] = await User.ctx.database.get("binding", { pid: userId });
2603
- if (bindData && val) {
2604
- const [currentM] = await User.ctx.database.get("monetary", { uid: bindData.aid });
2605
- if (currentM.value - val < 0) {
2606
- fn && await fn({
2607
- val: Math.abs(val),
2608
- currentVal: currentM.value,
2609
- err: "余额不足!"
2610
- });
2611
- return;
2742
+ if (area.left) {
2743
+ placeArea(area.left, row, col - 1);
2744
+ connections.left = true;
2745
+ if (grid[row]?.[col - 1]) {
2746
+ grid[row][col - 1].connections.right = true;
2612
2747
  }
2613
- await User.ctx.monetary.cost(bindData.aid, val);
2614
- fn && await fn({
2615
- val: Math.abs(val),
2616
- currentVal: currentM.value - val
2617
- });
2618
2748
  }
2619
- },
2620
- /** 给予玩家指定道具 */
2621
- async giveProps(userId, props, fn) {
2622
- const userProps = Props.userPorpsTemp[userId];
2623
- if (!userProps) return;
2624
- const upProps = [];
2625
- for (const item of props) {
2626
- const propsItem = propsData[item.name];
2627
- if (!propsData[item.name]) continue;
2628
- if (!userProps[item.name]) {
2629
- userProps[item.name] = {
2630
- name: propsItem.name,
2631
- type: propsItem.type,
2632
- value: 0
2633
- };
2749
+ if (area.right) {
2750
+ placeArea(area.right, row, col + 1);
2751
+ connections.right = true;
2752
+ if (grid[row]?.[col + 1]) {
2753
+ grid[row][col + 1].connections.left = true;
2634
2754
  }
2635
- userProps[item.name].value += item.val || 1;
2636
- upProps.push({ name: item.name, val: userProps[item.name].value });
2637
2755
  }
2638
- await Props.setDatabasePropsData(userId);
2639
- fn && await fn({
2640
- currentProps: upProps
2641
- });
2642
- },
2643
- /** 去除玩家指定道具 */
2644
- async loseProps(userId, props, fn) {
2645
- const userProps = Props.userPorpsTemp[userId];
2646
- const propsItem = propsData[props.name];
2647
- if (!userProps) return;
2648
- if (!propsItem) {
2649
- fn && await fn({
2650
- currentProps: { name: props.name, val: 0 },
2651
- err: "该道具信息不存在!"
2652
- });
2653
- return;
2756
+ if (area.down) {
2757
+ placeArea(area.down, row + 1, col);
2758
+ connections.down = true;
2759
+ if (grid[row + 1]?.[col]) {
2760
+ grid[row + 1][col].connections.top = true;
2761
+ }
2654
2762
  }
2655
- if (!userProps[props.name]) {
2656
- userProps[props.name] = {
2657
- name: propsItem.name,
2658
- type: propsItem.type,
2659
- value: 0
2660
- };
2763
+ }
2764
+ __name(placeArea, "placeArea");
2765
+ placeArea(centerKey, 0, 0);
2766
+ const cellWidth = 160;
2767
+ const cellHeight = 120;
2768
+ const svgWidth = (maxCol - minCol + 1) * cellWidth;
2769
+ const svgHeight = (maxRow - minRow + 1) * cellHeight;
2770
+ let html = `
2771
+ <style>
2772
+ .map-container {
2773
+ display: inline-block;
2774
+ position: relative;
2775
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
2776
+ font-size: 12px;
2777
+ background-color: transparent;
2778
+ padding: 20px;
2779
+ border-radius: 12px;
2780
+ min-width: 100vw;
2781
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
2782
+ }
2783
+ .map-table {
2784
+ border-collapse: separate;
2785
+ border-spacing: 0;
2786
+ position: relative;
2787
+ z-index: 2;
2788
+ }
2789
+ .map-cell {
2790
+ width: ${cellWidth}px;
2791
+ height: ${cellHeight}px;
2792
+ border: none;
2793
+ padding: 12px;
2794
+ vertical-align: top;
2795
+ text-align: center;
2796
+ background: rgba(255, 255, 255, 0.95);
2797
+ border-radius: 8px;
2798
+ transition: all 0.3s ease;
2799
+ position: relative;
2800
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
2801
+ backdrop-filter: blur(10px);
2802
+ }
2803
+ .map-cell:hover {
2804
+ transform: translateY(-2px);
2805
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
2806
+ }
2807
+ .empty-cell {
2808
+ background: transparent !important;
2809
+ box-shadow: none !important;
2810
+ border: none !important;
2811
+ }
2812
+ .area-name {
2813
+ font-weight: 700;
2814
+ margin-bottom: 6px;
2815
+ color: #2d3748;
2816
+ font-size: 14px;
2817
+ letter-spacing: 0.5px;
2818
+ }
2819
+ .area-type {
2820
+ font-size: 11px;
2821
+ color: #718096;
2822
+ margin-bottom: 6px;
2823
+ padding: 2px 8px;
2824
+ background: rgba(237, 242, 247, 0.8);
2825
+ border-radius: 12px;
2826
+ display: inline-block;
2827
+ }
2828
+ .area-info {
2829
+ font-size: 10px;
2830
+ color: #4a5568;
2831
+ margin-bottom: 6px;
2832
+ font-style: italic;
2833
+ }
2834
+ .monster-list, .npc-list {
2835
+ font-size: 10px;
2836
+ color: #2d3748;
2837
+ text-align: left;
2838
+ margin-top: 6px;
2839
+ padding-left: 8px;
2840
+ }
2841
+ .monster-list {
2842
+ border-left: 2px solid #e53e3e;
2843
+ }
2844
+ .npc-list {
2845
+ border-left: 2px solid #38a169;
2846
+ }
2847
+ .safe {
2848
+ background: linear-gradient(135deg, rgba(224, 247, 250, 0.95), rgba(129, 230, 217, 0.95));
2849
+ border: 2px solid #38b2ac;
2850
+ }
2851
+ .boss {
2852
+ background: linear-gradient(135deg, rgba(255, 235, 238, 0.95), rgba(254, 178, 178, 0.95));
2853
+ border: 2px solid #e53e3e;
2854
+ }
2855
+ .adventure {
2856
+ background: linear-gradient(135deg, rgba(241, 248, 233, 0.95), rgba(154, 230, 180, 0.95));
2857
+ border: 2px solid #38a169;
2858
+ }
2859
+ .portal {
2860
+ background: linear-gradient(135deg, rgba(255, 243, 224, 0.95), rgba(251, 211, 141, 0.95));
2861
+ border: 2px solid #ed8936;
2862
+ }
2863
+ .current {
2864
+ background: linear-gradient(135deg, rgba(255, 249, 196, 0.95), rgba(254, 240, 138, 0.95)) !important;
2865
+ border: 3px solid #d69e2e !important;
2866
+ box-shadow: 0 0 20px rgba(214, 158, 46, 0.4), 0 8px 16px rgba(0, 0, 0, 0.2);
2867
+ transform: scale(1.08);
2868
+ z-index: 10;
2869
+ animation: glow 2s ease-in-out infinite alternate;
2870
+ }
2871
+ @keyframes glow {
2872
+ from {
2873
+ box-shadow: 0 0 20px rgba(214, 158, 46, 0.4), 0 8px 16px rgba(0, 0, 0, 0.2);
2661
2874
  }
2662
- if (userProps[props.name].value - (props.val || 1) < 0) {
2663
- fn && await fn({
2664
- currentProps: { name: props.name, val: userProps[props.name].value },
2665
- err: `道具数量不足!剩余${userProps[props.name].value}个。`
2666
- });
2667
- return;
2875
+ to {
2876
+ box-shadow: 0 0 30px rgba(214, 158, 46, 0.6), 0 10px 20px rgba(0, 0, 0, 0.3);
2877
+ }
2878
+ }
2879
+ .current .area-name {
2880
+ color: #744210;
2881
+ font-weight: 900;
2882
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
2883
+ }
2884
+ .current-marker {
2885
+ display: inline-block;
2886
+ width: 10px;
2887
+ height: 10px;
2888
+ background: linear-gradient(135deg, #d69e2e, #744210);
2889
+ border-radius: 50%;
2890
+ margin-right: 6px;
2891
+ animation: pulse 1.5s ease-in-out infinite;
2892
+ box-shadow: 0 0 8px rgba(214, 158, 46, 0.8);
2893
+ }
2894
+ @keyframes pulse {
2895
+ 0% { transform: scale(1); opacity: 1; }
2896
+ 50% { transform: scale(1.4); opacity: 0.8; }
2897
+ 100% { transform: scale(1); opacity: 1; }
2898
+ }
2899
+ .connection-lines {
2900
+ position: absolute;
2901
+ top: 0;
2902
+ left: 0;
2903
+ width: 100%;
2904
+ height: 100%;
2905
+ z-index: 1;
2906
+ pointer-events: none;
2907
+ }
2908
+ .connection-line {
2909
+ stroke: rgba(255, 255, 255, 0.7);
2910
+ stroke-width: 3;
2911
+ stroke-linecap: round;
2912
+ filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
2913
+ }
2914
+ .connection-line-dotted {
2915
+ stroke-dasharray: 5, 5;
2916
+ }
2917
+ .connection-line-solid {
2918
+ stroke-dasharray: none;
2919
+ }
2920
+ .connection-dot {
2921
+ fill: rgba(255, 255, 255, 0.9);
2922
+ stroke: #4a5568;
2923
+ stroke-width: 1;
2924
+ filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.2));
2925
+ }
2926
+ </style>
2927
+ <div class="map-container">
2928
+ <svg class="connection-lines" width="${svgWidth}" height="${svgHeight}">
2929
+ `;
2930
+ for (let r = minRow; r <= maxRow; r++) {
2931
+ for (let c = minCol; c <= maxCol; c++) {
2932
+ const cell = grid[r]?.[c];
2933
+ if (cell) {
2934
+ const { connections } = cell;
2935
+ const x = (c - minCol) * cellWidth + cellWidth / 2;
2936
+ const y = (r - minRow) * cellHeight + cellHeight / 2;
2937
+ html += `<circle class="connection-dot" cx="${x}" cy="${y}" r="4" />`;
2938
+ if (connections.top) {
2939
+ const targetX = x;
2940
+ const targetY = y - cellHeight;
2941
+ html += `<line class="connection-line connection-line-dotted"
2942
+ x1="${x}" y1="${y}"
2943
+ x2="${targetX}" y2="${targetY}" />`;
2944
+ }
2945
+ if (connections.down) {
2946
+ const targetX = x;
2947
+ const targetY = y + cellHeight;
2948
+ html += `<line class="connection-line connection-line-dotted"
2949
+ x1="${x}" y1="${y}"
2950
+ x2="${targetX}" y2="${targetY}" />`;
2951
+ }
2952
+ if (connections.left) {
2953
+ const targetX = x - cellWidth;
2954
+ const targetY = y;
2955
+ html += `<line class="connection-line connection-line-dotted"
2956
+ x1="${x}" y1="${y}"
2957
+ x2="${targetX}" y2="${targetY}" />`;
2958
+ }
2959
+ if (connections.right) {
2960
+ const targetX = x + cellWidth;
2961
+ const targetY = y;
2962
+ html += `<line class="connection-line connection-line-dotted"
2963
+ x1="${x}" y1="${y}"
2964
+ x2="${targetX}" y2="${targetY}" />`;
2965
+ }
2966
+ }
2668
2967
  }
2669
- userProps[props.name].value -= props.val || 1;
2670
- if (userProps[props.name].value == 0) delete userProps[props.name];
2671
- await Props.setDatabasePropsData(userId);
2672
- fn && await fn({
2673
- currentProps: { name: props.name, val: userProps[props.name]?.value || 0 }
2674
- });
2675
- },
2676
- /** 目标是否死亡 */
2677
- isDie(userId) {
2678
- return User.userTempData[userId]?.isDie;
2679
2968
  }
2680
- };
2969
+ html += `</svg><table class="map-table">`;
2970
+ for (let r = minRow; r <= maxRow; r++) {
2971
+ html += "<tr>";
2972
+ for (let c = minCol; c <= maxCol; c++) {
2973
+ const cell = grid[r]?.[c];
2974
+ if (cell) {
2975
+ const { area, key } = cell;
2976
+ const isCurrent = currentAreaName === area.areaName;
2977
+ const typeClass = area.type === "安全区" ? "safe" : area.type === "BOSS区" ? "boss" : area.type === "冒险区" ? "adventure" : area.type === "传送门" ? "portal" : "";
2978
+ const currentClass = isCurrent ? "current" : "";
2979
+ html += `<td class="map-cell ${typeClass} ${currentClass}">`;
2980
+ html += `<div class="area-name">`;
2981
+ if (isCurrent) {
2982
+ html += `<span class="current-marker"></span>`;
2983
+ }
2984
+ html += `${area.areaName}`;
2985
+ if (isCurrent) {
2986
+ html += ` <span style="color:#744210;font-size:11px;font-weight:600;">(当前位置)</span>`;
2987
+ }
2988
+ html += `</div>`;
2989
+ html += `<div class="area-type">${area.type} (Lv.${area.needLv}+)</div>`;
2990
+ if (area.info) {
2991
+ html += `<div class="area-info">${area.info}</div>`;
2992
+ }
2993
+ if (area.npc && area.npc.length > 0) {
2994
+ html += `<div class="npc-list">NPC: ${area.npc.join(", ")}</div>`;
2995
+ }
2996
+ if (area.monster && area.monster.length > 0) {
2997
+ html += `<div class="monster-list">`;
2998
+ area.monster.forEach((m) => {
2999
+ html += `<div style="margin: 2px 0;">${m.name} <span style="color:#e53e3e">Lv.${m.lv}</span></div>`;
3000
+ });
3001
+ html += `</div>`;
3002
+ }
3003
+ html += `</td>`;
3004
+ } else {
3005
+ html += `<td class="map-cell empty-cell"></td>`;
3006
+ }
3007
+ }
3008
+ html += "</tr>";
3009
+ }
3010
+ html += `
3011
+ </table>
3012
+ </div>
3013
+ `;
3014
+ return html;
3015
+ }
3016
+ __name(generateMapHTML, "generateMapHTML");
2681
3017
 
2682
3018
  // src/index.ts
2683
3019
  var name = "smmcat-gensokyo";
2684
3020
  var inject = {
2685
- required: ["monetary", "database"]
3021
+ required: ["monetary", "database", "puppeteer"]
2686
3022
  };
2687
3023
  var Config = import_koishi2.Schema.object({});
2688
3024
  function apply(ctx, config) {
@@ -2709,17 +3045,6 @@ function apply(ctx, config) {
2709
3045
  return `你已经阵亡,请发送 /补给 进行治疗。`;
2710
3046
  }
2711
3047
  GensokyoMap.move(session, "top" /* 上 */, async (val) => {
2712
- if (BattleData.isTeam(session)) {
2713
- const { userId } = session;
2714
- Object.keys(BattleData.teamTemp).forEach((_userId) => {
2715
- if (BattleData.teamTemp[userId].for == userId && userId !== _userId) {
2716
- GensokyoMap.userCurrentLoal[_userId].areaName = GensokyoMap.userCurrentLoal[userId].areaName;
2717
- GensokyoMap.userCurrentLoal[_userId].floor = GensokyoMap.userCurrentLoal[userId].floor;
2718
- GensokyoMap.userCurrentLoal[_userId].moveing = false;
2719
- GensokyoMap.setLocalStoragePoistionData(_userId);
2720
- }
2721
- });
2722
- }
2723
3048
  await session.send(GensokyoMap.userAreaTextFormat(userData.playName, val));
2724
3049
  if (val.map.type == "冒险区" /* 冒险区 */ && val.map.monster?.length) {
2725
3050
  if (random(0, 10) <= 2) {
@@ -2746,17 +3071,6 @@ function apply(ctx, config) {
2746
3071
  return `你已经阵亡,请发送 /补给 进行治疗。`;
2747
3072
  }
2748
3073
  GensokyoMap.move(session, "down" /* 下 */, async (val) => {
2749
- if (BattleData.isTeam(session)) {
2750
- const { userId } = session;
2751
- Object.keys(BattleData.teamTemp).forEach((_userId) => {
2752
- if (BattleData.teamTemp[userId].for == userId && userId !== _userId) {
2753
- GensokyoMap.userCurrentLoal[_userId].areaName = GensokyoMap.userCurrentLoal[userId].areaName;
2754
- GensokyoMap.userCurrentLoal[_userId].floor = GensokyoMap.userCurrentLoal[userId].floor;
2755
- GensokyoMap.userCurrentLoal[_userId].moveing = false;
2756
- GensokyoMap.setLocalStoragePoistionData(_userId);
2757
- }
2758
- });
2759
- }
2760
3074
  await session.send(GensokyoMap.userAreaTextFormat(userData.playName, val));
2761
3075
  if (val.map.type == "冒险区" /* 冒险区 */ && val.map.monster?.length) {
2762
3076
  if (random(0, 10) <= 2) {
@@ -2783,17 +3097,6 @@ function apply(ctx, config) {
2783
3097
  return `你已经阵亡,请发送 /补给 进行治疗。`;
2784
3098
  }
2785
3099
  GensokyoMap.move(session, "left" /* 左 */, async (val) => {
2786
- if (BattleData.isTeam(session)) {
2787
- const { userId } = session;
2788
- Object.keys(BattleData.teamTemp).forEach((_userId) => {
2789
- if (BattleData.teamTemp[userId].for == userId && userId !== _userId) {
2790
- GensokyoMap.userCurrentLoal[_userId].areaName = GensokyoMap.userCurrentLoal[userId].areaName;
2791
- GensokyoMap.userCurrentLoal[_userId].floor = GensokyoMap.userCurrentLoal[userId].floor;
2792
- GensokyoMap.userCurrentLoal[_userId].moveing = false;
2793
- GensokyoMap.setLocalStoragePoistionData(_userId);
2794
- }
2795
- });
2796
- }
2797
3100
  await session.send(GensokyoMap.userAreaTextFormat(userData.playName, val));
2798
3101
  if (val.map.type == "冒险区" /* 冒险区 */ && val.map.monster?.length) {
2799
3102
  if (random(0, 10) <= 2) {
@@ -2820,17 +3123,6 @@ function apply(ctx, config) {
2820
3123
  return `你已经阵亡,请发送 /补给 进行治疗。`;
2821
3124
  }
2822
3125
  GensokyoMap.move(session, "right" /* 右 */, async (val) => {
2823
- if (BattleData.isTeam(session)) {
2824
- const { userId } = session;
2825
- Object.keys(BattleData.teamTemp).forEach((_userId) => {
2826
- if (BattleData.teamTemp[userId].for == userId && userId !== _userId) {
2827
- GensokyoMap.userCurrentLoal[_userId].areaName = GensokyoMap.userCurrentLoal[userId].areaName;
2828
- GensokyoMap.userCurrentLoal[_userId].floor = GensokyoMap.userCurrentLoal[userId].floor;
2829
- GensokyoMap.userCurrentLoal[_userId].moveing = false;
2830
- GensokyoMap.setLocalStoragePoistionData(_userId);
2831
- }
2832
- });
2833
- }
2834
3126
  await session.send(GensokyoMap.userAreaTextFormat(userData.playName, val));
2835
3127
  if (val.map.type == "冒险区" /* 冒险区 */ && val.map.monster?.length) {
2836
3128
  if (random(0, 10) <= 2) {
@@ -2962,12 +3254,16 @@ function apply(ctx, config) {
2962
3254
  const userData = await User.getUserAttribute(session);
2963
3255
  if (!userData) return;
2964
3256
  GensokyoMap.initUserPoistion(session, userData);
3257
+ if (BattleData.isBattle(session)) {
3258
+ await session.send("当前正在战斗,请结束后再使用改");
3259
+ return;
3260
+ }
2965
3261
  if (temp[session.userId] == void 0) {
2966
3262
  temp[session.userId] = 0;
2967
3263
  }
2968
3264
  const useTime = Date.now() - temp[session.userId];
2969
3265
  if (useTime < 36e4) {
2970
- return `请等待下一个补给时间!剩余${Math.floor(36e4 - useTime / 6e4)}分钟。`;
3266
+ return `请等待下一个补给时间!剩余${Math.floor((36e4 - useTime) / 6e4)}分钟。`;
2971
3267
  }
2972
3268
  temp[session.userId] = Date.now();
2973
3269
  const { maxHp, maxMp, playName } = User.getUserAttributeByUserId(session.userId);
@@ -2981,18 +3277,27 @@ function apply(ctx, config) {
2981
3277
  });
2982
3278
  ctx.command("幻想乡/队伍操作");
2983
3279
  ctx.command("队伍操作/队伍创建").action(async ({ session }) => {
3280
+ const userData = await User.getUserAttribute(session);
3281
+ if (!userData) return;
3282
+ GensokyoMap.initUserPoistion(session, userData);
2984
3283
  if (BattleData.isBattle(session)) {
2985
3284
  return `战斗中无法进行队伍创建操作!`;
2986
3285
  }
2987
3286
  await BattleData.creatTeam(session);
2988
3287
  });
2989
3288
  ctx.command("队伍操作/队伍信息").action(async ({ session }) => {
3289
+ const userData = await User.getUserAttribute(session);
3290
+ if (!userData) return;
3291
+ GensokyoMap.initUserPoistion(session, userData);
2990
3292
  const team = BattleData.teamListByUser(session.userId);
2991
3293
  if (!team.length) return `你还没有队伍...`;
2992
3294
  return `当前队伍信息如下:
2993
3295
  ` + team.map((item) => `lv.${item.lv} ${item.playName} [${BattleData.teamTemp[item.userId].identity}]`).join("\n");
2994
3296
  });
2995
3297
  ctx.command("队伍操作/队伍邀请 <playName>").action(async ({ session }, playName) => {
3298
+ const userData = await User.getUserAttribute(session);
3299
+ if (!userData) return;
3300
+ GensokyoMap.initUserPoistion(session, userData);
2996
3301
  if (BattleData.isBattle(session)) {
2997
3302
  return `战斗中无法进行队伍邀请操作!`;
2998
3303
  }
@@ -3002,23 +3307,42 @@ function apply(ctx, config) {
3002
3307
  await BattleData.invitationTeam(session, playName);
3003
3308
  });
3004
3309
  ctx.command("队伍操作/队伍加入").action(async ({ session }) => {
3310
+ const userData = await User.getUserAttribute(session);
3311
+ if (!userData) return;
3312
+ GensokyoMap.initUserPoistion(session, userData);
3005
3313
  if (BattleData.isBattle(session)) {
3006
3314
  return `战斗中无法进行队伍创建操作!`;
3007
3315
  }
3008
3316
  await BattleData.joinTeam(session);
3009
3317
  });
3010
3318
  ctx.command("队伍操作/队伍退出").action(async ({ session }) => {
3319
+ const userData = await User.getUserAttribute(session);
3320
+ if (!userData) return;
3321
+ GensokyoMap.initUserPoistion(session, userData);
3011
3322
  if (BattleData.isBattle(session)) {
3012
3323
  return `战斗中无法进行队伍退出操作!`;
3013
3324
  }
3014
3325
  await BattleData.exitTeam(session);
3015
3326
  });
3016
3327
  ctx.command("队伍操作/队伍解散").action(async ({ session }) => {
3328
+ const userData = await User.getUserAttribute(session);
3329
+ if (!userData) return;
3330
+ GensokyoMap.initUserPoistion(session, userData);
3017
3331
  if (BattleData.isBattle(session)) {
3018
3332
  return `战斗中无法进行队伍解散操作!`;
3019
3333
  }
3020
3334
  await BattleData.dissolveTeam(session);
3021
3335
  });
3336
+ ctx.command("幻想乡/地图").action(async ({ session }) => {
3337
+ const userData = await User.getUserAttribute(session);
3338
+ if (!userData) return;
3339
+ GensokyoMap.initUserPoistion(session, userData);
3340
+ const { areaName, floor } = GensokyoMap.userCurrentLoal[session.userId];
3341
+ const mapLocal = GensokyoMap.mapLocalData[floor];
3342
+ const html = generateMapHTML(mapLocal, areaName);
3343
+ console.log(html);
3344
+ await session.send(await ctx.puppeteer.render(html));
3345
+ });
3022
3346
  }
3023
3347
  __name(apply, "apply");
3024
3348
  // Annotate the CommonJS export names for ESM import in node: