napgram-plugin-slave-market 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +248 -0
  2. package/dist/commands/admin.commands.d.ts +11 -0
  3. package/dist/commands/admin.commands.d.ts.map +1 -0
  4. package/dist/commands/admin.commands.js +268 -0
  5. package/dist/commands/bank.commands.d.ts +13 -0
  6. package/dist/commands/bank.commands.d.ts.map +1 -0
  7. package/dist/commands/bank.commands.js +211 -0
  8. package/dist/commands/base.commands.d.ts +12 -0
  9. package/dist/commands/base.commands.d.ts.map +1 -0
  10. package/dist/commands/base.commands.js +149 -0
  11. package/dist/commands/economy.commands.d.ts +13 -0
  12. package/dist/commands/economy.commands.d.ts.map +1 -0
  13. package/dist/commands/economy.commands.js +221 -0
  14. package/dist/commands/gameplay.commands.d.ts +15 -0
  15. package/dist/commands/gameplay.commands.d.ts.map +1 -0
  16. package/dist/commands/gameplay.commands.js +461 -0
  17. package/dist/commands/index.d.ts +7 -0
  18. package/dist/commands/index.d.ts.map +1 -0
  19. package/dist/commands/index.js +47 -0
  20. package/dist/commands/social.commands.d.ts +13 -0
  21. package/dist/commands/social.commands.d.ts.map +1 -0
  22. package/dist/commands/social.commands.js +305 -0
  23. package/dist/config.d.ts +37 -0
  24. package/dist/config.d.ts.map +1 -0
  25. package/dist/config.js +35 -0
  26. package/dist/index.d.ts +22 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +57 -0
  29. package/dist/index.mjs +57 -0
  30. package/dist/models/index.d.ts +10 -0
  31. package/dist/models/index.d.ts.map +1 -0
  32. package/dist/models/index.js +40 -0
  33. package/dist/services/admin.service.d.ts +59 -0
  34. package/dist/services/admin.service.d.ts.map +1 -0
  35. package/dist/services/admin.service.js +164 -0
  36. package/dist/services/bank.service.d.ts +74 -0
  37. package/dist/services/bank.service.d.ts.map +1 -0
  38. package/dist/services/bank.service.js +354 -0
  39. package/dist/services/bodyguard.service.d.ts +36 -0
  40. package/dist/services/bodyguard.service.d.ts.map +1 -0
  41. package/dist/services/bodyguard.service.js +102 -0
  42. package/dist/services/cooldown.service.d.ts +33 -0
  43. package/dist/services/cooldown.service.d.ts.map +1 -0
  44. package/dist/services/cooldown.service.js +104 -0
  45. package/dist/services/farm.service.d.ts +61 -0
  46. package/dist/services/farm.service.d.ts.map +1 -0
  47. package/dist/services/farm.service.js +255 -0
  48. package/dist/services/index.d.ts +16 -0
  49. package/dist/services/index.d.ts.map +1 -0
  50. package/dist/services/index.js +15 -0
  51. package/dist/services/market.service.d.ts +58 -0
  52. package/dist/services/market.service.d.ts.map +1 -0
  53. package/dist/services/market.service.js +286 -0
  54. package/dist/services/player.service.d.ts +56 -0
  55. package/dist/services/player.service.d.ts.map +1 -0
  56. package/dist/services/player.service.js +201 -0
  57. package/dist/services/ranking.service.d.ts +28 -0
  58. package/dist/services/ranking.service.d.ts.map +1 -0
  59. package/dist/services/ranking.service.js +71 -0
  60. package/dist/services/redpacket.service.d.ts +63 -0
  61. package/dist/services/redpacket.service.d.ts.map +1 -0
  62. package/dist/services/redpacket.service.js +207 -0
  63. package/dist/services/transaction.service.d.ts +48 -0
  64. package/dist/services/transaction.service.d.ts.map +1 -0
  65. package/dist/services/transaction.service.js +102 -0
  66. package/dist/services/vip.service.d.ts +41 -0
  67. package/dist/services/vip.service.d.ts.map +1 -0
  68. package/dist/services/vip.service.js +167 -0
  69. package/dist/services/work.service.d.ts +49 -0
  70. package/dist/services/work.service.d.ts.map +1 -0
  71. package/dist/services/work.service.js +258 -0
  72. package/dist/types/index.d.ts +62 -0
  73. package/dist/types/index.d.ts.map +1 -0
  74. package/dist/types/index.js +4 -0
  75. package/dist/utils/helpers.d.ts +40 -0
  76. package/dist/utils/helpers.d.ts.map +1 -0
  77. package/dist/utils/helpers.js +88 -0
  78. package/dist/utils/index.d.ts +5 -0
  79. package/dist/utils/index.d.ts.map +1 -0
  80. package/dist/utils/index.js +4 -0
  81. package/napgram-plugin.json +15 -0
  82. package/package.json +56 -0
@@ -0,0 +1,286 @@
1
+ /**
2
+ * 牛马市场服务 - 购买、放生、赎身、抢夺等
3
+ */
4
+ import { getDatabase } from '../models';
5
+ export class MarketService {
6
+ ctx;
7
+ config;
8
+ transactionService;
9
+ playerService;
10
+ constructor(ctx, config, transactionService, playerService) {
11
+ this.ctx = ctx;
12
+ this.config = config;
13
+ this.transactionService = transactionService;
14
+ this.playerService = playerService;
15
+ }
16
+ /**
17
+ * 获取市场上可购买的玩家(没有主人的)
18
+ */
19
+ async getMarketPlayers(scopeKey, limit = 20) {
20
+ const db = getDatabase();
21
+ const where = {
22
+ ownerId: null,
23
+ };
24
+ if (scopeKey) {
25
+ where.registerSource = scopeKey;
26
+ }
27
+ return db.slaveMarketPlayer.findMany({
28
+ where,
29
+ orderBy: {
30
+ worth: 'desc',
31
+ },
32
+ take: limit,
33
+ });
34
+ }
35
+ /**
36
+ * 购买玩家
37
+ */
38
+ async buyPlayer(buyerId, targetId, isAdmin = false) {
39
+ const db = getDatabase();
40
+ if (buyerId === targetId) {
41
+ throw new Error('不能购买自己');
42
+ }
43
+ const [buyer, target] = await Promise.all([
44
+ db.slaveMarketPlayer.findUnique({ where: { userId: buyerId } }),
45
+ db.slaveMarketPlayer.findUnique({ where: { userId: targetId } }),
46
+ ]);
47
+ if (!buyer || !target) {
48
+ throw new Error('玩家不存在');
49
+ }
50
+ if (target.ownerId) {
51
+ throw new Error('该玩家已被购买');
52
+ }
53
+ const price = target.worth;
54
+ // 管理员免费购买
55
+ if (!isAdmin) {
56
+ if (buyer.balance < price) {
57
+ throw new Error(`余额不足,需要 ${price} 金币`);
58
+ }
59
+ }
60
+ const ownedTime = BigInt(Date.now());
61
+ const newWorth = Math.floor(price * 1.1); // 身价上涨10%
62
+ await db.$transaction([
63
+ // 扣除购买者余额(管理员不扣钱)
64
+ db.slaveMarketPlayer.update({
65
+ where: { userId: buyerId },
66
+ data: {
67
+ balance: isAdmin ? buyer.balance : buyer.balance - price,
68
+ },
69
+ }),
70
+ // 设置目标的主人,提升身价
71
+ db.slaveMarketPlayer.update({
72
+ where: { userId: targetId },
73
+ data: {
74
+ ownerId: buyerId,
75
+ ownedTime,
76
+ worth: newWorth,
77
+ },
78
+ }),
79
+ ]);
80
+ // 记录交易
81
+ if (!isAdmin) {
82
+ await this.transactionService.createTransaction({
83
+ userId: buyerId,
84
+ type: 'buy_player',
85
+ amount: -price,
86
+ balance: buyer.balance - price,
87
+ targetId,
88
+ description: `购买玩家 ${target.nickname}`,
89
+ });
90
+ }
91
+ return {
92
+ price: isAdmin ? 0 : price,
93
+ newWorth,
94
+ newBalance: isAdmin ? buyer.balance : buyer.balance - price,
95
+ };
96
+ }
97
+ /**
98
+ * 放生(释放牛马)
99
+ */
100
+ async releasePlayer(ownerId, targetId) {
101
+ const db = getDatabase();
102
+ const target = await db.slaveMarketPlayer.findUnique({
103
+ where: { userId: targetId },
104
+ });
105
+ if (!target) {
106
+ throw new Error('玩家不存在');
107
+ }
108
+ if (target.ownerId !== ownerId) {
109
+ throw new Error('该玩家不是你的牛马');
110
+ }
111
+ await db.slaveMarketPlayer.update({
112
+ where: { userId: targetId },
113
+ data: {
114
+ ownerId: null,
115
+ },
116
+ });
117
+ }
118
+ /**
119
+ * 赎身
120
+ */
121
+ async ransom(userId) {
122
+ const db = getDatabase();
123
+ const player = await db.slaveMarketPlayer.findUnique({
124
+ where: { userId },
125
+ include: { owner: true },
126
+ });
127
+ if (!player) {
128
+ throw new Error('玩家不存在');
129
+ }
130
+ if (!player.ownerId || !player.owner) {
131
+ throw new Error('你是自由身,无需赎身');
132
+ }
133
+ // 赎身价格 = 身价 * 1.2
134
+ const price = Math.floor(player.worth * 1.2);
135
+ if (player.balance < price) {
136
+ throw new Error(`赎身需要 ${price} 金币,余额不足`);
137
+ }
138
+ await db.$transaction([
139
+ // 扣除玩家余额
140
+ db.slaveMarketPlayer.update({
141
+ where: { userId },
142
+ data: {
143
+ balance: player.balance - price,
144
+ ownerId: null,
145
+ },
146
+ }),
147
+ // 给主人加钱
148
+ db.slaveMarketPlayer.update({
149
+ where: { userId: player.ownerId },
150
+ data: {
151
+ balance: {
152
+ increment: price,
153
+ },
154
+ },
155
+ }),
156
+ ]);
157
+ // 记录交易
158
+ await Promise.all([
159
+ this.transactionService.createTransaction({
160
+ userId,
161
+ type: 'ransom',
162
+ amount: -price,
163
+ balance: player.balance - price,
164
+ targetId: player.ownerId,
165
+ description: `赎身`,
166
+ }),
167
+ this.transactionService.createTransaction({
168
+ userId: player.ownerId,
169
+ type: 'ransom',
170
+ amount: price,
171
+ balance: player.owner.balance + price,
172
+ targetId: userId,
173
+ description: `牛马赎身(${player.nickname})`,
174
+ }),
175
+ ]);
176
+ return {
177
+ price,
178
+ newBalance: player.balance - price,
179
+ };
180
+ }
181
+ /**
182
+ * 抢夺牛马(从其他玩家手里强制购买)
183
+ */
184
+ async snatchPlayer(snatcherId, targetId, isAdmin = false) {
185
+ const db = getDatabase();
186
+ if (snatcherId === targetId) {
187
+ throw new Error('不能抢夺自己');
188
+ }
189
+ const [snatcher, target] = await Promise.all([
190
+ db.slaveMarketPlayer.findUnique({ where: { userId: snatcherId } }),
191
+ db.slaveMarketPlayer.findUnique({ where: { userId: targetId }, include: { owner: true } }),
192
+ ]);
193
+ if (!snatcher || !target) {
194
+ throw new Error('玩家不存在');
195
+ }
196
+ if (!target.ownerId || !target.owner) {
197
+ throw new Error('该玩家是自由身,请使用"购买玩家"命令');
198
+ }
199
+ if (target.ownerId === snatcherId) {
200
+ throw new Error('这已经是你的牛马了');
201
+ }
202
+ // 抢夺价格 = 身价 * 2
203
+ const price = Math.floor(target.worth * 2);
204
+ if (!isAdmin && snatcher.balance < price) {
205
+ throw new Error(`余额不足,抢夺需要 ${price} 金币`);
206
+ }
207
+ // 补偿原主人 = 身价 * 1.5
208
+ const compensate = Math.floor(target.worth * 1.5);
209
+ const ownedTime = BigInt(Date.now());
210
+ await db.$transaction([
211
+ // 扣除抢夺者余额
212
+ db.slaveMarketPlayer.update({
213
+ where: { userId: snatcherId },
214
+ data: {
215
+ balance: isAdmin ? snatcher.balance : snatcher.balance - price,
216
+ },
217
+ }),
218
+ // 补偿原主人
219
+ db.slaveMarketPlayer.update({
220
+ where: { userId: target.ownerId },
221
+ data: {
222
+ balance: {
223
+ increment: compensate,
224
+ },
225
+ },
226
+ }),
227
+ // 转移所有权,提升身价
228
+ db.slaveMarketPlayer.update({
229
+ where: { userId: targetId },
230
+ data: {
231
+ ownerId: snatcherId,
232
+ ownedTime,
233
+ worth: Math.floor(target.worth * 1.2),
234
+ },
235
+ }),
236
+ ]);
237
+ // 记录交易
238
+ if (!isAdmin) {
239
+ await this.transactionService.createTransaction({
240
+ userId: snatcherId,
241
+ type: 'buy_player',
242
+ amount: -price,
243
+ balance: snatcher.balance - price,
244
+ targetId,
245
+ description: `抢夺牛马 ${target.nickname}`,
246
+ });
247
+ }
248
+ return {
249
+ price: isAdmin ? 0 : price,
250
+ compensate,
251
+ newBalance: isAdmin ? snatcher.balance : snatcher.balance - price,
252
+ };
253
+ }
254
+ /**
255
+ * 获取身价排行榜
256
+ */
257
+ async getWorthRanking(limit = 10) {
258
+ const db = getDatabase();
259
+ return db.slaveMarketPlayer.findMany({
260
+ orderBy: {
261
+ worth: 'desc',
262
+ },
263
+ take: limit,
264
+ });
265
+ }
266
+ /**
267
+ * 获取牛马数量排行榜
268
+ */
269
+ async getSlaveCountRanking(limit = 10) {
270
+ const db = getDatabase();
271
+ const players = await db.slaveMarketPlayer.findMany({
272
+ include: {
273
+ slaves: true,
274
+ },
275
+ });
276
+ const ranked = players
277
+ .map((p) => ({
278
+ player: p,
279
+ slaveCount: p.slaves.length,
280
+ }))
281
+ .filter((r) => r.slaveCount > 0)
282
+ .sort((a, b) => b.slaveCount - a.slaveCount)
283
+ .slice(0, limit);
284
+ return ranked;
285
+ }
286
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * 玩家服务 - 管理玩家数据的核心服务
3
+ */
4
+ import type { PluginContext } from '@napgram/sdk';
5
+ import { type SlaveMarketPlayer } from '../models';
6
+ import type { SlaveMarketConfig } from '../config';
7
+ export declare class PlayerService {
8
+ private ctx;
9
+ private config;
10
+ constructor(ctx: PluginContext, config: SlaveMarketConfig);
11
+ /**
12
+ * 获取或创建玩家
13
+ */
14
+ getOrCreatePlayer(userId: string, nickname: string, groupId?: string): Promise<SlaveMarketPlayer>;
15
+ /**
16
+ * 根据 userId 获取玩家
17
+ */
18
+ getPlayer(userId: string): Promise<SlaveMarketPlayer | null>;
19
+ /**
20
+ * 更新玩家数据
21
+ */
22
+ updatePlayer(userId: string, data: Partial<SlaveMarketPlayer>): Promise<SlaveMarketPlayer>;
23
+ /**
24
+ * 增加余额
25
+ */
26
+ addBalance(userId: string, amount: number): Promise<SlaveMarketPlayer>;
27
+ /**
28
+ * 扣除余额
29
+ */
30
+ deductBalance(userId: string, amount: number): Promise<SlaveMarketPlayer>;
31
+ /**
32
+ * 检查是否为管理员
33
+ */
34
+ isAdmin(userId: string): Promise<boolean>;
35
+ /**
36
+ * 检查是否为VIP
37
+ */
38
+ isVip(userId: string): Promise<boolean>;
39
+ /**
40
+ * 获取玩家的主人
41
+ */
42
+ getOwner(userId: string): Promise<SlaveMarketPlayer | null>;
43
+ /**
44
+ * 获取玩家拥有的奴隶列表
45
+ */
46
+ getSlaves(userId: string): Promise<SlaveMarketPlayer[]>;
47
+ /**
48
+ * 购买玩家
49
+ */
50
+ buyPlayer(buyerId: string, targetId: string, price: number): Promise<void>;
51
+ /**
52
+ * 释放玩家
53
+ */
54
+ releasePlayer(ownerId: string, targetId: string): Promise<void>;
55
+ }
56
+ //# sourceMappingURL=player.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player.service.d.ts","sourceRoot":"","sources":["../../src/services/player.service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAe,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,qBAAa,aAAa;IAElB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;gBADN,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,iBAAiB;IAGrC;;OAEG;IACG,iBAAiB,CACnB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IA8B7B;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAOlE;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAQhG;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAY5E;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsB/E;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsB/C;;OAEG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB7C;;OAEG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAUjE;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAQ7D;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsChF;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUxE"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * 玩家服务 - 管理玩家数据的核心服务
3
+ */
4
+ import { getDatabase } from '../models';
5
+ export class PlayerService {
6
+ ctx;
7
+ config;
8
+ constructor(ctx, config) {
9
+ this.ctx = ctx;
10
+ this.config = config;
11
+ }
12
+ /**
13
+ * 获取或创建玩家
14
+ */
15
+ async getOrCreatePlayer(userId, nickname, groupId) {
16
+ const db = getDatabase();
17
+ let player = await db.slaveMarketPlayer.findUnique({
18
+ where: { userId },
19
+ });
20
+ if (!player) {
21
+ // 提取平台原始ID
22
+ const plainUserId = userId.includes(':') ? userId.split(':')[1] : userId;
23
+ player = await db.slaveMarketPlayer.create({
24
+ data: {
25
+ userId,
26
+ plainUserId,
27
+ nickname,
28
+ balance: this.config.初始余额,
29
+ worth: this.config.初始身价,
30
+ depositLimit: this.config.初始存款上限,
31
+ registerTime: BigInt(Date.now()),
32
+ registerSource: groupId,
33
+ },
34
+ });
35
+ this.ctx.logger.info(`[slave-market] New player registered: ${nickname} (${userId})`);
36
+ }
37
+ return player;
38
+ }
39
+ /**
40
+ * 根据 userId 获取玩家
41
+ */
42
+ async getPlayer(userId) {
43
+ const db = getDatabase();
44
+ return db.slaveMarketPlayer.findUnique({
45
+ where: { userId },
46
+ });
47
+ }
48
+ /**
49
+ * 更新玩家数据
50
+ */
51
+ async updatePlayer(userId, data) {
52
+ const db = getDatabase();
53
+ return db.slaveMarketPlayer.update({
54
+ where: { userId },
55
+ data,
56
+ });
57
+ }
58
+ /**
59
+ * 增加余额
60
+ */
61
+ async addBalance(userId, amount) {
62
+ const db = getDatabase();
63
+ return db.slaveMarketPlayer.update({
64
+ where: { userId },
65
+ data: {
66
+ balance: {
67
+ increment: amount,
68
+ },
69
+ },
70
+ });
71
+ }
72
+ /**
73
+ * 扣除余额
74
+ */
75
+ async deductBalance(userId, amount) {
76
+ const db = getDatabase();
77
+ const player = await this.getPlayer(userId);
78
+ if (!player) {
79
+ throw new Error('玩家不存在');
80
+ }
81
+ if (player.balance < amount) {
82
+ throw new Error('余额不足');
83
+ }
84
+ return db.slaveMarketPlayer.update({
85
+ where: { userId },
86
+ data: {
87
+ balance: {
88
+ decrement: amount,
89
+ },
90
+ },
91
+ });
92
+ }
93
+ /**
94
+ * 检查是否为管理员
95
+ */
96
+ async isAdmin(userId) {
97
+ const db = getDatabase();
98
+ const plainUserId = userId.includes(':') ? userId.split(':')[1] : userId;
99
+ const adminList = this.config.管理员列表 || [];
100
+ if (adminList.includes(userId) || adminList.includes(plainUserId)) {
101
+ return true;
102
+ }
103
+ const player = await this.getPlayer(userId);
104
+ if (player?.isAdmin) {
105
+ return true;
106
+ }
107
+ // 检查管理员表
108
+ const admin = await db.slaveMarketAdmin.findUnique({
109
+ where: { userId },
110
+ });
111
+ return !!admin;
112
+ }
113
+ /**
114
+ * 检查是否为VIP
115
+ */
116
+ async isVip(userId) {
117
+ const player = await this.getPlayer(userId);
118
+ if (!player) {
119
+ return false;
120
+ }
121
+ // 管理员永久VIP
122
+ if (this.config.VIP配置.管理员永久VIP && await this.isAdmin(userId)) {
123
+ return true;
124
+ }
125
+ // 检查VIP到期时间
126
+ if (player.vipEndTime && player.vipEndTime > BigInt(Date.now())) {
127
+ return true;
128
+ }
129
+ return false;
130
+ }
131
+ /**
132
+ * 获取玩家的主人
133
+ */
134
+ async getOwner(userId) {
135
+ const db = getDatabase();
136
+ const player = await db.slaveMarketPlayer.findUnique({
137
+ where: { userId },
138
+ include: { owner: true },
139
+ });
140
+ return player?.owner || null;
141
+ }
142
+ /**
143
+ * 获取玩家拥有的奴隶列表
144
+ */
145
+ async getSlaves(userId) {
146
+ const db = getDatabase();
147
+ return db.slaveMarketPlayer.findMany({
148
+ where: { ownerId: userId },
149
+ orderBy: { worth: 'desc' },
150
+ });
151
+ }
152
+ /**
153
+ * 购买玩家
154
+ */
155
+ async buyPlayer(buyerId, targetId, price) {
156
+ const db = getDatabase();
157
+ await db.$transaction(async (tx) => {
158
+ // 扣除购买者余额
159
+ await tx.slaveMarketPlayer.update({
160
+ where: { userId: buyerId },
161
+ data: {
162
+ balance: {
163
+ decrement: price,
164
+ },
165
+ },
166
+ });
167
+ // 设置目标玩家的主人
168
+ await tx.slaveMarketPlayer.update({
169
+ where: { userId: targetId },
170
+ data: {
171
+ ownerId: buyerId,
172
+ ownedTime: BigInt(Date.now()),
173
+ worth: Math.floor(price * 1.1), // 身价上涨10%
174
+ },
175
+ });
176
+ // 记录交易
177
+ await tx.slaveMarketTransaction.create({
178
+ data: {
179
+ userId: buyerId,
180
+ type: 'buy_player',
181
+ amount: -price,
182
+ balance: 0, // 将在外部更新
183
+ targetId,
184
+ description: `购买玩家`,
185
+ },
186
+ });
187
+ });
188
+ }
189
+ /**
190
+ * 释放玩家
191
+ */
192
+ async releasePlayer(ownerId, targetId) {
193
+ const db = getDatabase();
194
+ await db.slaveMarketPlayer.update({
195
+ where: { userId: targetId, ownerId },
196
+ data: {
197
+ ownerId: null,
198
+ },
199
+ });
200
+ }
201
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 排行榜服务
3
+ */
4
+ import type { PluginContext } from '@napgram/sdk';
5
+ import { type SlaveMarketPlayer } from '../models';
6
+ export interface RankingItem {
7
+ rank: number;
8
+ player: SlaveMarketPlayer;
9
+ value: number;
10
+ extra?: any;
11
+ }
12
+ export declare class RankingService {
13
+ private ctx;
14
+ constructor(ctx: PluginContext);
15
+ /**
16
+ * 身价排行榜
17
+ */
18
+ getWorthRanking(limit?: number): Promise<RankingItem[]>;
19
+ /**
20
+ * 资产排行榜(余额+存款)
21
+ */
22
+ getAssetRanking(limit?: number): Promise<RankingItem[]>;
23
+ /**
24
+ * 牛马数量排行榜
25
+ */
26
+ getSlaveCountRanking(limit?: number): Promise<RankingItem[]>;
27
+ }
28
+ //# sourceMappingURL=ranking.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranking.service.d.ts","sourceRoot":"","sources":["../../src/services/ranking.service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAe,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEhE,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,GAAG,CAAC;CACf;AAED,qBAAa,cAAc;IACX,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,aAAa;IAEtC;;OAEG;IACG,eAAe,CAAC,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAiBjE;;OAEG;IACG,eAAe,CAAC,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAoBjE;;OAEG;IACG,oBAAoB,CAAC,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CAyBzE"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * 排行榜服务
3
+ */
4
+ import { getDatabase } from '../models';
5
+ export class RankingService {
6
+ ctx;
7
+ constructor(ctx) {
8
+ this.ctx = ctx;
9
+ }
10
+ /**
11
+ * 身价排行榜
12
+ */
13
+ async getWorthRanking(limit = 10) {
14
+ const db = getDatabase();
15
+ const players = await db.slaveMarketPlayer.findMany({
16
+ orderBy: {
17
+ worth: 'desc',
18
+ },
19
+ take: limit,
20
+ });
21
+ return players.map((p, i) => ({
22
+ rank: i + 1,
23
+ player: p,
24
+ value: p.worth,
25
+ }));
26
+ }
27
+ /**
28
+ * 资产排行榜(余额+存款)
29
+ */
30
+ async getAssetRanking(limit = 10) {
31
+ const db = getDatabase();
32
+ const players = await db.slaveMarketPlayer.findMany();
33
+ const ranked = players
34
+ .map((p) => ({
35
+ player: p,
36
+ asset: p.balance + p.deposit,
37
+ }))
38
+ .sort((a, b) => b.asset - a.asset)
39
+ .slice(0, limit);
40
+ return ranked.map((item, i) => ({
41
+ rank: i + 1,
42
+ player: item.player,
43
+ value: item.asset,
44
+ }));
45
+ }
46
+ /**
47
+ * 牛马数量排行榜
48
+ */
49
+ async getSlaveCountRanking(limit = 10) {
50
+ const db = getDatabase();
51
+ const players = await db.slaveMarketPlayer.findMany({
52
+ include: {
53
+ slaves: true,
54
+ },
55
+ });
56
+ const ranked = players
57
+ .map((p) => ({
58
+ player: p,
59
+ count: p.slaves.length,
60
+ }))
61
+ .filter((item) => item.count > 0)
62
+ .sort((a, b) => b.count - a.count)
63
+ .slice(0, limit);
64
+ return ranked.map((item, i) => ({
65
+ rank: i + 1,
66
+ player: item.player,
67
+ value: item.count,
68
+ extra: { slaves: item.player.slaves },
69
+ }));
70
+ }
71
+ }