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.
- package/README.md +248 -0
- package/dist/commands/admin.commands.d.ts +11 -0
- package/dist/commands/admin.commands.d.ts.map +1 -0
- package/dist/commands/admin.commands.js +268 -0
- package/dist/commands/bank.commands.d.ts +13 -0
- package/dist/commands/bank.commands.d.ts.map +1 -0
- package/dist/commands/bank.commands.js +211 -0
- package/dist/commands/base.commands.d.ts +12 -0
- package/dist/commands/base.commands.d.ts.map +1 -0
- package/dist/commands/base.commands.js +149 -0
- package/dist/commands/economy.commands.d.ts +13 -0
- package/dist/commands/economy.commands.d.ts.map +1 -0
- package/dist/commands/economy.commands.js +221 -0
- package/dist/commands/gameplay.commands.d.ts +15 -0
- package/dist/commands/gameplay.commands.d.ts.map +1 -0
- package/dist/commands/gameplay.commands.js +461 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +47 -0
- package/dist/commands/social.commands.d.ts +13 -0
- package/dist/commands/social.commands.d.ts.map +1 -0
- package/dist/commands/social.commands.js +305 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +35 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.mjs +57 -0
- package/dist/models/index.d.ts +10 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +40 -0
- package/dist/services/admin.service.d.ts +59 -0
- package/dist/services/admin.service.d.ts.map +1 -0
- package/dist/services/admin.service.js +164 -0
- package/dist/services/bank.service.d.ts +74 -0
- package/dist/services/bank.service.d.ts.map +1 -0
- package/dist/services/bank.service.js +354 -0
- package/dist/services/bodyguard.service.d.ts +36 -0
- package/dist/services/bodyguard.service.d.ts.map +1 -0
- package/dist/services/bodyguard.service.js +102 -0
- package/dist/services/cooldown.service.d.ts +33 -0
- package/dist/services/cooldown.service.d.ts.map +1 -0
- package/dist/services/cooldown.service.js +104 -0
- package/dist/services/farm.service.d.ts +61 -0
- package/dist/services/farm.service.d.ts.map +1 -0
- package/dist/services/farm.service.js +255 -0
- package/dist/services/index.d.ts +16 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +15 -0
- package/dist/services/market.service.d.ts +58 -0
- package/dist/services/market.service.d.ts.map +1 -0
- package/dist/services/market.service.js +286 -0
- package/dist/services/player.service.d.ts +56 -0
- package/dist/services/player.service.d.ts.map +1 -0
- package/dist/services/player.service.js +201 -0
- package/dist/services/ranking.service.d.ts +28 -0
- package/dist/services/ranking.service.d.ts.map +1 -0
- package/dist/services/ranking.service.js +71 -0
- package/dist/services/redpacket.service.d.ts +63 -0
- package/dist/services/redpacket.service.d.ts.map +1 -0
- package/dist/services/redpacket.service.js +207 -0
- package/dist/services/transaction.service.d.ts +48 -0
- package/dist/services/transaction.service.d.ts.map +1 -0
- package/dist/services/transaction.service.js +102 -0
- package/dist/services/vip.service.d.ts +41 -0
- package/dist/services/vip.service.d.ts.map +1 -0
- package/dist/services/vip.service.js +167 -0
- package/dist/services/work.service.d.ts +49 -0
- package/dist/services/work.service.d.ts.map +1 -0
- package/dist/services/work.service.js +258 -0
- package/dist/types/index.d.ts +62 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/utils/helpers.d.ts +40 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +88 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/napgram-plugin.json +15 -0
- package/package.json +56 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 保镖服务 - 雇佣保镖、防护管理
|
|
3
|
+
*/
|
|
4
|
+
import { getDatabase } from '../models';
|
|
5
|
+
// 保镖配置
|
|
6
|
+
export const BODYGUARDS = [
|
|
7
|
+
{ name: '普通保镖', price: 500, duration: 30 * 60 * 1000, defense: 0.6 }, // 30分钟,60%防御
|
|
8
|
+
{ name: '精英保镖', price: 1500, duration: 60 * 60 * 1000, defense: 0.8 }, // 1小时,80%防御
|
|
9
|
+
{ name: '专业保镖', price: 5000, duration: 120 * 60 * 1000, defense: 0.9 }, // 2小时,90%防御
|
|
10
|
+
{ name: '贴身保镖', price: 15000, duration: 360 * 60 * 1000, defense: 0.95 }, // 6小时,95%防御
|
|
11
|
+
];
|
|
12
|
+
export class BodyguardService {
|
|
13
|
+
ctx;
|
|
14
|
+
config;
|
|
15
|
+
transactionService;
|
|
16
|
+
constructor(ctx, config, transactionService) {
|
|
17
|
+
this.ctx = ctx;
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.transactionService = transactionService;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 获取保镖信息
|
|
23
|
+
*/
|
|
24
|
+
getBodyguard(name) {
|
|
25
|
+
return BODYGUARDS.find(b => b.name === name);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 雇佣保镖
|
|
29
|
+
*/
|
|
30
|
+
async hireBodyguard(userId, bodyguardName, isAdmin = false) {
|
|
31
|
+
const db = getDatabase();
|
|
32
|
+
const bodyguard = this.getBodyguard(bodyguardName);
|
|
33
|
+
if (!bodyguard) {
|
|
34
|
+
throw new Error(`未知的保镖:${bodyguardName}`);
|
|
35
|
+
}
|
|
36
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
37
|
+
if (!player) {
|
|
38
|
+
throw new Error('玩家不存在');
|
|
39
|
+
}
|
|
40
|
+
// 检查是否已有保镖
|
|
41
|
+
if (player.bodyguardEndTime && Number(player.bodyguardEndTime) > Date.now()) {
|
|
42
|
+
const remaining = Math.ceil((Number(player.bodyguardEndTime) - Date.now()) / 60000);
|
|
43
|
+
throw new Error(`当前保镖还有 ${remaining} 分钟,无需重复雇佣`);
|
|
44
|
+
}
|
|
45
|
+
const cost = isAdmin ? 0 : bodyguard.price;
|
|
46
|
+
if (!isAdmin && player.balance < cost) {
|
|
47
|
+
throw new Error(`雇佣${bodyguardName}需要 ${cost} 金币,余额不足`);
|
|
48
|
+
}
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
const endTime = now + bodyguard.duration;
|
|
51
|
+
await db.slaveMarketPlayer.update({
|
|
52
|
+
where: { userId },
|
|
53
|
+
data: {
|
|
54
|
+
balance: isAdmin ? player.balance : player.balance - cost,
|
|
55
|
+
bodyguardName: bodyguard.name,
|
|
56
|
+
bodyguardEndTime: BigInt(endTime),
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
// 记录交易
|
|
60
|
+
if (!isAdmin) {
|
|
61
|
+
await this.transactionService.createTransaction({
|
|
62
|
+
userId,
|
|
63
|
+
type: 'hire_guard',
|
|
64
|
+
amount: -cost,
|
|
65
|
+
balance: player.balance - cost,
|
|
66
|
+
description: `雇佣${bodyguardName}`,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
cost: isAdmin ? 0 : cost,
|
|
71
|
+
duration: Math.floor(bodyguard.duration / 60000), // 分钟
|
|
72
|
+
endTime,
|
|
73
|
+
newBalance: isAdmin ? player.balance : player.balance - cost,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 检查保镖是否有效
|
|
78
|
+
*/
|
|
79
|
+
async hasActiveBodyguard(userId) {
|
|
80
|
+
const db = getDatabase();
|
|
81
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
82
|
+
if (!player || !player.bodyguardEndTime) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return Number(player.bodyguardEndTime) > Date.now();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 格式化保镖列表
|
|
89
|
+
*/
|
|
90
|
+
formatBodyguardList() {
|
|
91
|
+
let list = '🛡️ 保镖市场\n\n';
|
|
92
|
+
for (const guard of BODYGUARDS) {
|
|
93
|
+
const time = Math.floor(guard.duration / 60000);
|
|
94
|
+
list += `${guard.name}\n`;
|
|
95
|
+
list += ` 价格: ${guard.price} 金币\n`;
|
|
96
|
+
list += ` 时长: ${time} 分钟\n`;
|
|
97
|
+
list += ` 防御: ${(guard.defense * 100).toFixed(0)}%\n\n`;
|
|
98
|
+
}
|
|
99
|
+
list += '💡 保镖可防止被抢劫';
|
|
100
|
+
return list;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 冷却时间服务
|
|
3
|
+
*/
|
|
4
|
+
import type { PluginContext } from '@napgram/sdk';
|
|
5
|
+
import type { SlaveMarketConfig } from '../config';
|
|
6
|
+
export type CooldownAction = '打工' | '抢劫' | '转账' | '购买' | '种地' | '收获';
|
|
7
|
+
export declare class CooldownService {
|
|
8
|
+
private ctx;
|
|
9
|
+
private config;
|
|
10
|
+
private readonly cooldownMap;
|
|
11
|
+
private readonly timeFieldMap;
|
|
12
|
+
constructor(ctx: PluginContext, config: SlaveMarketConfig);
|
|
13
|
+
/**
|
|
14
|
+
* 检查冷却时间
|
|
15
|
+
*/
|
|
16
|
+
checkCooldown(userId: string, action: CooldownAction): Promise<{
|
|
17
|
+
ready: boolean;
|
|
18
|
+
remaining: number;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* 更新冷却时间
|
|
22
|
+
*/
|
|
23
|
+
updateCooldown(userId: string, action: CooldownAction): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* 格式化剩余时间
|
|
26
|
+
*/
|
|
27
|
+
formatRemaining(seconds: number): string;
|
|
28
|
+
/**
|
|
29
|
+
* 检查并抛出错误(如果还在冷却中)
|
|
30
|
+
*/
|
|
31
|
+
ensureReady(userId: string, action: CooldownAction): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=cooldown.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cooldown.service.d.ts","sourceRoot":"","sources":["../../src/services/cooldown.service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,MAAM,MAAM,cAAc,GACpB,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,CAAC;AAEX,qBAAa,eAAe;IAoBpB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;IApBlB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAOzB;IAEH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAO1B;gBAGS,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,iBAAiB;IAGrC;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC;QACjE,KAAK,EAAE,OAAO,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;KACrB,CAAC;IAmCF;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB3E;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAsBxC;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAO3E"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 冷却时间服务
|
|
3
|
+
*/
|
|
4
|
+
import { getDatabase } from '../models';
|
|
5
|
+
export class CooldownService {
|
|
6
|
+
ctx;
|
|
7
|
+
config;
|
|
8
|
+
cooldownMap = new Map([
|
|
9
|
+
['打工', '打工'],
|
|
10
|
+
['抢劫', '抢劫'],
|
|
11
|
+
['转账', '转账'],
|
|
12
|
+
['购买', '购买'],
|
|
13
|
+
['种地', '种地'],
|
|
14
|
+
['收获', '收获'],
|
|
15
|
+
]);
|
|
16
|
+
timeFieldMap = new Map([
|
|
17
|
+
['打工', 'lastWorkTime'],
|
|
18
|
+
['抢劫', 'lastRobTime'],
|
|
19
|
+
['转账', 'lastTransferTime'],
|
|
20
|
+
['购买', 'lastBuyTime'],
|
|
21
|
+
['种地', 'lastPlantTime'],
|
|
22
|
+
['收获', 'lastHarvestTime'],
|
|
23
|
+
]);
|
|
24
|
+
constructor(ctx, config) {
|
|
25
|
+
this.ctx = ctx;
|
|
26
|
+
this.config = config;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 检查冷却时间
|
|
30
|
+
*/
|
|
31
|
+
async checkCooldown(userId, action) {
|
|
32
|
+
const db = getDatabase();
|
|
33
|
+
const player = await db.slaveMarketPlayer.findUnique({
|
|
34
|
+
where: { userId },
|
|
35
|
+
});
|
|
36
|
+
if (!player) {
|
|
37
|
+
throw new Error('玩家不存在');
|
|
38
|
+
}
|
|
39
|
+
const timeField = this.timeFieldMap.get(action);
|
|
40
|
+
if (!timeField) {
|
|
41
|
+
throw new Error(`未知的冷却动作: ${action}`);
|
|
42
|
+
}
|
|
43
|
+
const lastTime = player[timeField];
|
|
44
|
+
if (!lastTime) {
|
|
45
|
+
return { ready: true, remaining: 0 };
|
|
46
|
+
}
|
|
47
|
+
const configKey = this.cooldownMap.get(action);
|
|
48
|
+
const cooldownDuration = this.config.冷却时间[configKey];
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
const elapsed = now - Number(lastTime);
|
|
51
|
+
if (elapsed >= cooldownDuration) {
|
|
52
|
+
return { ready: true, remaining: 0 };
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
ready: false,
|
|
56
|
+
remaining: Math.ceil((cooldownDuration - elapsed) / 1000), // 剩余秒数
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 更新冷却时间
|
|
61
|
+
*/
|
|
62
|
+
async updateCooldown(userId, action) {
|
|
63
|
+
const db = getDatabase();
|
|
64
|
+
const timeField = this.timeFieldMap.get(action);
|
|
65
|
+
if (!timeField) {
|
|
66
|
+
throw new Error(`未知的冷却动作: ${action}`);
|
|
67
|
+
}
|
|
68
|
+
await db.slaveMarketPlayer.update({
|
|
69
|
+
where: { userId },
|
|
70
|
+
data: {
|
|
71
|
+
[timeField]: BigInt(Date.now()),
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 格式化剩余时间
|
|
77
|
+
*/
|
|
78
|
+
formatRemaining(seconds) {
|
|
79
|
+
if (seconds < 60) {
|
|
80
|
+
return `${seconds}秒`;
|
|
81
|
+
}
|
|
82
|
+
const minutes = Math.floor(seconds / 60);
|
|
83
|
+
const remainingSeconds = seconds % 60;
|
|
84
|
+
if (minutes < 60) {
|
|
85
|
+
return remainingSeconds > 0
|
|
86
|
+
? `${minutes}分${remainingSeconds}秒`
|
|
87
|
+
: `${minutes}分钟`;
|
|
88
|
+
}
|
|
89
|
+
const hours = Math.floor(minutes / 60);
|
|
90
|
+
const remainingMinutes = minutes % 60;
|
|
91
|
+
return remainingMinutes > 0
|
|
92
|
+
? `${hours}小时${remainingMinutes}分钟`
|
|
93
|
+
: `${hours}小时`;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 检查并抛出错误(如果还在冷却中)
|
|
97
|
+
*/
|
|
98
|
+
async ensureReady(userId, action) {
|
|
99
|
+
const { ready, remaining } = await this.checkCooldown(userId, action);
|
|
100
|
+
if (!ready) {
|
|
101
|
+
throw new Error(`操作冷却中,请 ${this.formatRemaining(remaining)} 后再试`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 种地服务 - 地块管理、作物种植、收获等
|
|
3
|
+
*/
|
|
4
|
+
import type { PluginContext } from '@napgram/sdk';
|
|
5
|
+
import { type SlaveMarketFarmLand } from '../models';
|
|
6
|
+
import type { SlaveMarketConfig } from '../config';
|
|
7
|
+
import { TransactionService } from './transaction.service';
|
|
8
|
+
import type { Crop } from '../types';
|
|
9
|
+
export declare const CROPS: Crop[];
|
|
10
|
+
export declare class FarmService {
|
|
11
|
+
private ctx;
|
|
12
|
+
private config;
|
|
13
|
+
private transactionService;
|
|
14
|
+
constructor(ctx: PluginContext, config: SlaveMarketConfig, transactionService: TransactionService);
|
|
15
|
+
/**
|
|
16
|
+
* 获取作物信息
|
|
17
|
+
*/
|
|
18
|
+
getCrop(cropName: string): Crop | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* 获取玩家的地块
|
|
21
|
+
*/
|
|
22
|
+
getPlayerLands(userId: string): Promise<SlaveMarketFarmLand[]>;
|
|
23
|
+
/**
|
|
24
|
+
* 购买新地块
|
|
25
|
+
*/
|
|
26
|
+
buyLand(userId: string, isAdmin?: boolean): Promise<{
|
|
27
|
+
plotIndex: number;
|
|
28
|
+
cost: number;
|
|
29
|
+
newBalance: number;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* 种植作物
|
|
33
|
+
*/
|
|
34
|
+
plantCrop(userId: string, cropName: string, plotIndex?: number, isAdmin?: boolean): Promise<{
|
|
35
|
+
plotsPlanted: number[];
|
|
36
|
+
cost: number;
|
|
37
|
+
newBalance: number;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* 收获作物
|
|
41
|
+
*/
|
|
42
|
+
harvestCrops(userId: string): Promise<{
|
|
43
|
+
harvested: Array<{
|
|
44
|
+
plotIndex: number;
|
|
45
|
+
cropName: string;
|
|
46
|
+
income: number;
|
|
47
|
+
}>;
|
|
48
|
+
totalIncome: number;
|
|
49
|
+
newBalance: number;
|
|
50
|
+
notReady: Array<{
|
|
51
|
+
plotIndex: number;
|
|
52
|
+
cropName: string;
|
|
53
|
+
remaining: number;
|
|
54
|
+
}>;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* 格式化作物列表
|
|
58
|
+
*/
|
|
59
|
+
formatCropList(): string;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=farm.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"farm.service.d.ts","sourceRoot":"","sources":["../../src/services/farm.service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAe,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAGrC,eAAO,MAAM,KAAK,EAAE,IAAI,EASvB,CAAC;AAEF,qBAAa,WAAW;IAEhB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,kBAAkB;gBAFlB,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,EAAE,kBAAkB;IAGlD;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAI3C;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IASpE;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,OAAe,GAAG,OAAO,CAAC;QAC7D,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IAwDF;;OAEG;IACG,SAAS,CACX,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE,OAAe,GACzB,OAAO,CAAC;QACP,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IAsFF;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QACxC,SAAS,EAAE,KAAK,CAAC;YACb,SAAS,EAAE,MAAM,CAAC;YAClB,QAAQ,EAAE,MAAM,CAAC;YACjB,MAAM,EAAE,MAAM,CAAC;SAClB,CAAC,CAAC;QACH,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,KAAK,CAAC;YACZ,SAAS,EAAE,MAAM,CAAC;YAClB,QAAQ,EAAE,MAAM,CAAC;YACjB,SAAS,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;KACN,CAAC;IAsFF;;OAEG;IACH,cAAc,IAAI,MAAM;CAa3B"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 种地服务 - 地块管理、作物种植、收获等
|
|
3
|
+
*/
|
|
4
|
+
import { getDatabase } from '../models';
|
|
5
|
+
// 作物配置
|
|
6
|
+
export const CROPS = [
|
|
7
|
+
{ name: '小麦', emoji: '🌾', price: 100, growTime: 5 * 60 * 1000, baseYield: 150, yieldRange: [120, 180] },
|
|
8
|
+
{ name: '玉米', emoji: '🌽', price: 200, growTime: 10 * 60 * 1000, baseYield: 350, yieldRange: [280, 420] },
|
|
9
|
+
{ name: '土豆', emoji: '🥔', price: 150, growTime: 8 * 60 * 1000, baseYield: 250, yieldRange: [200, 300] },
|
|
10
|
+
{ name: '胡萝卜', emoji: '🥕', price: 180, growTime: 7 * 60 * 1000, baseYield: 280, yieldRange: [220, 340] },
|
|
11
|
+
{ name: '番茄', emoji: '🍅', price: 250, growTime: 12 * 60 * 1000, baseYield: 450, yieldRange: [360, 540] },
|
|
12
|
+
{ name: '黄瓜', emoji: '🥒', price: 220, growTime: 10 * 60 * 1000, baseYield: 400, yieldRange: [320, 480] },
|
|
13
|
+
{ name: '茄子', emoji: '🍆', price: 280, growTime: 15 * 60 * 1000, baseYield: 550, yieldRange: [440, 660] },
|
|
14
|
+
{ name: '辣椒', emoji: '🌶️', price: 300, growTime: 18 * 60 * 1000, baseYield: 650, yieldRange: [520, 780] },
|
|
15
|
+
];
|
|
16
|
+
export class FarmService {
|
|
17
|
+
ctx;
|
|
18
|
+
config;
|
|
19
|
+
transactionService;
|
|
20
|
+
constructor(ctx, config, transactionService) {
|
|
21
|
+
this.ctx = ctx;
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.transactionService = transactionService;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 获取作物信息
|
|
27
|
+
*/
|
|
28
|
+
getCrop(cropName) {
|
|
29
|
+
return CROPS.find(c => c.name === cropName);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 获取玩家的地块
|
|
33
|
+
*/
|
|
34
|
+
async getPlayerLands(userId) {
|
|
35
|
+
const db = getDatabase();
|
|
36
|
+
return db.slaveMarketFarmLand.findMany({
|
|
37
|
+
where: { userId },
|
|
38
|
+
orderBy: { plotIndex: 'asc' },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 购买新地块
|
|
43
|
+
*/
|
|
44
|
+
async buyLand(userId, isAdmin = false) {
|
|
45
|
+
const db = getDatabase();
|
|
46
|
+
const lands = await this.getPlayerLands(userId);
|
|
47
|
+
const nextIndex = lands.length + 1;
|
|
48
|
+
if (nextIndex > this.config.种地系统.最大地块数) {
|
|
49
|
+
throw new Error(`最多只能拥有 ${this.config.种地系统.最大地块数} 块地`);
|
|
50
|
+
}
|
|
51
|
+
const cost = isAdmin ? 0 : this.config.种地系统.地块价格[nextIndex - 1] || 10000;
|
|
52
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
53
|
+
if (!player) {
|
|
54
|
+
throw new Error('玩家不存在');
|
|
55
|
+
}
|
|
56
|
+
if (!isAdmin && player.balance < cost) {
|
|
57
|
+
throw new Error(`开地需要 ${cost} 金币,余额不足`);
|
|
58
|
+
}
|
|
59
|
+
await db.$transaction([
|
|
60
|
+
// 扣除玩家余额
|
|
61
|
+
db.slaveMarketPlayer.update({
|
|
62
|
+
where: { userId },
|
|
63
|
+
data: {
|
|
64
|
+
balance: isAdmin ? player.balance : player.balance - cost,
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
// 创建新地块
|
|
68
|
+
db.slaveMarketFarmLand.create({
|
|
69
|
+
data: {
|
|
70
|
+
userId,
|
|
71
|
+
plotIndex: nextIndex,
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
]);
|
|
75
|
+
// 记录交易
|
|
76
|
+
if (!isAdmin) {
|
|
77
|
+
await this.transactionService.createTransaction({
|
|
78
|
+
userId,
|
|
79
|
+
type: 'buy_land',
|
|
80
|
+
amount: -cost,
|
|
81
|
+
balance: player.balance - cost,
|
|
82
|
+
description: `购买地块${nextIndex}`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
plotIndex: nextIndex,
|
|
87
|
+
cost: isAdmin ? 0 : cost,
|
|
88
|
+
newBalance: isAdmin ? player.balance : player.balance - cost,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 种植作物
|
|
93
|
+
*/
|
|
94
|
+
async plantCrop(userId, cropName, plotIndex, isAdmin = false) {
|
|
95
|
+
const db = getDatabase();
|
|
96
|
+
const crop = this.getCrop(cropName);
|
|
97
|
+
if (!crop) {
|
|
98
|
+
throw new Error(`未知的作物:${cropName}`);
|
|
99
|
+
}
|
|
100
|
+
const lands = await this.getPlayerLands(userId);
|
|
101
|
+
if (lands.length === 0) {
|
|
102
|
+
throw new Error('还没有地块,请先"开地"');
|
|
103
|
+
}
|
|
104
|
+
let targetLands;
|
|
105
|
+
if (plotIndex) {
|
|
106
|
+
// 种植指定地块
|
|
107
|
+
const land = lands.find(l => l.plotIndex === plotIndex);
|
|
108
|
+
if (!land) {
|
|
109
|
+
throw new Error(`地块${plotIndex}不存在`);
|
|
110
|
+
}
|
|
111
|
+
if (land.cropType) {
|
|
112
|
+
throw new Error(`地块${plotIndex}已种植 ${land.cropType}`);
|
|
113
|
+
}
|
|
114
|
+
targetLands = [land];
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// 种植所有空地
|
|
118
|
+
targetLands = lands.filter(l => !l.cropType);
|
|
119
|
+
if (targetLands.length === 0) {
|
|
120
|
+
throw new Error('没有空地块可以种植');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const totalCost = isAdmin ? 0 : crop.price * targetLands.length;
|
|
124
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
125
|
+
if (!player) {
|
|
126
|
+
throw new Error('玩家不存在');
|
|
127
|
+
}
|
|
128
|
+
if (!isAdmin && player.balance < totalCost) {
|
|
129
|
+
throw new Error(`种植需要 ${totalCost} 金币,余额不足`);
|
|
130
|
+
}
|
|
131
|
+
const now = Date.now();
|
|
132
|
+
const harvestTime = now + crop.growTime;
|
|
133
|
+
await db.$transaction([
|
|
134
|
+
// 扣除玩家余额
|
|
135
|
+
db.slaveMarketPlayer.update({
|
|
136
|
+
where: { userId },
|
|
137
|
+
data: {
|
|
138
|
+
balance: isAdmin ? player.balance : player.balance - totalCost,
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
141
|
+
// 更新地块
|
|
142
|
+
...targetLands.map(land => db.slaveMarketFarmLand.update({
|
|
143
|
+
where: { id: land.id },
|
|
144
|
+
data: {
|
|
145
|
+
cropType: cropName,
|
|
146
|
+
plantTime: BigInt(now),
|
|
147
|
+
harvestTime: BigInt(harvestTime),
|
|
148
|
+
},
|
|
149
|
+
})),
|
|
150
|
+
]);
|
|
151
|
+
// 记录交易
|
|
152
|
+
if (!isAdmin) {
|
|
153
|
+
await this.transactionService.createTransaction({
|
|
154
|
+
userId,
|
|
155
|
+
type: 'plant',
|
|
156
|
+
amount: -totalCost,
|
|
157
|
+
balance: player.balance - totalCost,
|
|
158
|
+
description: `种植 ${cropName} x${targetLands.length}`,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
plotsPlanted: targetLands.map(l => l.plotIndex),
|
|
163
|
+
cost: isAdmin ? 0 : totalCost,
|
|
164
|
+
newBalance: isAdmin ? player.balance : player.balance - totalCost,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 收获作物
|
|
169
|
+
*/
|
|
170
|
+
async harvestCrops(userId) {
|
|
171
|
+
const db = getDatabase();
|
|
172
|
+
const lands = await this.getPlayerLands(userId);
|
|
173
|
+
const now = Date.now();
|
|
174
|
+
const ready = lands.filter(l => l.cropType && l.harvestTime && Number(l.harvestTime) <= now);
|
|
175
|
+
const notReady = lands.filter(l => l.cropType && l.harvestTime && Number(l.harvestTime) > now);
|
|
176
|
+
if (ready.length === 0) {
|
|
177
|
+
const notReadyInfo = notReady.map(l => ({
|
|
178
|
+
plotIndex: l.plotIndex,
|
|
179
|
+
cropName: l.cropType,
|
|
180
|
+
remaining: Math.ceil((Number(l.harvestTime) - now) / 60000),
|
|
181
|
+
}));
|
|
182
|
+
throw new Error(notReadyInfo.length > 0 ? '没有成熟的作物' : '没有种植作物');
|
|
183
|
+
}
|
|
184
|
+
// 计算收益
|
|
185
|
+
const harvested = ready.map(land => {
|
|
186
|
+
const crop = this.getCrop(land.cropType);
|
|
187
|
+
if (!crop) {
|
|
188
|
+
return { plotIndex: land.plotIndex, cropName: land.cropType, income: 0 };
|
|
189
|
+
}
|
|
190
|
+
// 随机收益
|
|
191
|
+
const [min, max] = crop.yieldRange;
|
|
192
|
+
const income = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
193
|
+
return {
|
|
194
|
+
plotIndex: land.plotIndex,
|
|
195
|
+
cropName: land.cropType,
|
|
196
|
+
income,
|
|
197
|
+
};
|
|
198
|
+
});
|
|
199
|
+
const totalIncome = harvested.reduce((sum, h) => sum + h.income, 0);
|
|
200
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
201
|
+
if (!player) {
|
|
202
|
+
throw new Error('玩家不存在');
|
|
203
|
+
}
|
|
204
|
+
await db.$transaction([
|
|
205
|
+
// 增加玩家余额
|
|
206
|
+
db.slaveMarketPlayer.update({
|
|
207
|
+
where: { userId },
|
|
208
|
+
data: {
|
|
209
|
+
balance: player.balance + totalIncome,
|
|
210
|
+
},
|
|
211
|
+
}),
|
|
212
|
+
// 清空地块
|
|
213
|
+
...ready.map(land => db.slaveMarketFarmLand.update({
|
|
214
|
+
where: { id: land.id },
|
|
215
|
+
data: {
|
|
216
|
+
cropType: null,
|
|
217
|
+
plantTime: null,
|
|
218
|
+
harvestTime: null,
|
|
219
|
+
},
|
|
220
|
+
})),
|
|
221
|
+
]);
|
|
222
|
+
// 记录交易
|
|
223
|
+
await this.transactionService.createTransaction({
|
|
224
|
+
userId,
|
|
225
|
+
type: 'harvest',
|
|
226
|
+
amount: totalIncome,
|
|
227
|
+
balance: player.balance + totalIncome,
|
|
228
|
+
description: `收获作物 x${ready.length}`,
|
|
229
|
+
});
|
|
230
|
+
return {
|
|
231
|
+
harvested,
|
|
232
|
+
totalIncome,
|
|
233
|
+
newBalance: player.balance + totalIncome,
|
|
234
|
+
notReady: notReady.map(l => ({
|
|
235
|
+
plotIndex: l.plotIndex,
|
|
236
|
+
cropName: l.cropType,
|
|
237
|
+
remaining: Math.ceil((Number(l.harvestTime) - now) / 60000),
|
|
238
|
+
})),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* 格式化作物列表
|
|
243
|
+
*/
|
|
244
|
+
formatCropList() {
|
|
245
|
+
let list = '🌾 作物列表\n\n';
|
|
246
|
+
for (const crop of CROPS) {
|
|
247
|
+
const time = Math.floor(crop.growTime / 60000);
|
|
248
|
+
const [min, max] = crop.yieldRange;
|
|
249
|
+
list += `${crop.emoji} ${crop.name}\n`;
|
|
250
|
+
list += ` 成本: ${crop.price} | 时长: ${time}分钟\n`;
|
|
251
|
+
list += ` 收益: ${min}-${max} (平均${crop.baseYield})\n\n`;
|
|
252
|
+
}
|
|
253
|
+
return list;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 服务索引 - 导出所有服务
|
|
3
|
+
*/
|
|
4
|
+
export { PlayerService } from './player.service';
|
|
5
|
+
export { CooldownService, type CooldownAction } from './cooldown.service';
|
|
6
|
+
export { TransactionService, type CreateTransactionParams } from './transaction.service';
|
|
7
|
+
export { BankService } from './bank.service';
|
|
8
|
+
export { WorkService, type RobStrategy } from './work.service';
|
|
9
|
+
export { MarketService } from './market.service';
|
|
10
|
+
export { FarmService, CROPS } from './farm.service';
|
|
11
|
+
export { BodyguardService, BODYGUARDS } from './bodyguard.service';
|
|
12
|
+
export { VipService } from './vip.service';
|
|
13
|
+
export { RedPacketService } from './redpacket.service';
|
|
14
|
+
export { RankingService, type RankingItem } from './ranking.service';
|
|
15
|
+
export { AdminService } from './admin.service';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 服务索引 - 导出所有服务
|
|
3
|
+
*/
|
|
4
|
+
export { PlayerService } from './player.service';
|
|
5
|
+
export { CooldownService } from './cooldown.service';
|
|
6
|
+
export { TransactionService } from './transaction.service';
|
|
7
|
+
export { BankService } from './bank.service';
|
|
8
|
+
export { WorkService } from './work.service';
|
|
9
|
+
export { MarketService } from './market.service';
|
|
10
|
+
export { FarmService, CROPS } from './farm.service';
|
|
11
|
+
export { BodyguardService, BODYGUARDS } from './bodyguard.service';
|
|
12
|
+
export { VipService } from './vip.service';
|
|
13
|
+
export { RedPacketService } from './redpacket.service';
|
|
14
|
+
export { RankingService } from './ranking.service';
|
|
15
|
+
export { AdminService } from './admin.service';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 牛马市场服务 - 购买、放生、赎身、抢夺等
|
|
3
|
+
*/
|
|
4
|
+
import type { PluginContext } from '@napgram/sdk';
|
|
5
|
+
import { type SlaveMarketPlayer } from '../models';
|
|
6
|
+
import type { SlaveMarketConfig } from '../config';
|
|
7
|
+
import { TransactionService } from './transaction.service';
|
|
8
|
+
import { PlayerService } from './player.service';
|
|
9
|
+
export declare class MarketService {
|
|
10
|
+
private ctx;
|
|
11
|
+
private config;
|
|
12
|
+
private transactionService;
|
|
13
|
+
private playerService;
|
|
14
|
+
constructor(ctx: PluginContext, config: SlaveMarketConfig, transactionService: TransactionService, playerService: PlayerService);
|
|
15
|
+
/**
|
|
16
|
+
* 获取市场上可购买的玩家(没有主人的)
|
|
17
|
+
*/
|
|
18
|
+
getMarketPlayers(scopeKey?: string, limit?: number): Promise<SlaveMarketPlayer[]>;
|
|
19
|
+
/**
|
|
20
|
+
* 购买玩家
|
|
21
|
+
*/
|
|
22
|
+
buyPlayer(buyerId: string, targetId: string, isAdmin?: boolean): Promise<{
|
|
23
|
+
price: number;
|
|
24
|
+
newWorth: number;
|
|
25
|
+
newBalance: number;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* 放生(释放牛马)
|
|
29
|
+
*/
|
|
30
|
+
releasePlayer(ownerId: string, targetId: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* 赎身
|
|
33
|
+
*/
|
|
34
|
+
ransom(userId: string): Promise<{
|
|
35
|
+
price: number;
|
|
36
|
+
newBalance: number;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* 抢夺牛马(从其他玩家手里强制购买)
|
|
40
|
+
*/
|
|
41
|
+
snatchPlayer(snatcherId: string, targetId: string, isAdmin?: boolean): Promise<{
|
|
42
|
+
price: number;
|
|
43
|
+
compensate: number;
|
|
44
|
+
newBalance: number;
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* 获取身价排行榜
|
|
48
|
+
*/
|
|
49
|
+
getWorthRanking(limit?: number): Promise<SlaveMarketPlayer[]>;
|
|
50
|
+
/**
|
|
51
|
+
* 获取牛马数量排行榜
|
|
52
|
+
*/
|
|
53
|
+
getSlaveCountRanking(limit?: number): Promise<Array<{
|
|
54
|
+
player: SlaveMarketPlayer;
|
|
55
|
+
slaveCount: number;
|
|
56
|
+
}>>;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=market.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"market.service.d.ts","sourceRoot":"","sources":["../../src/services/market.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;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,qBAAa,aAAa;IAElB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,aAAa;gBAHb,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,EAAE,aAAa;IAGxC;;OAEG;IACG,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAoB3F;;OAEG;IACG,SAAS,CACX,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,OAAe,GACzB,OAAO,CAAC;QACP,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IAsEF;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBrE;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAClC,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IAoEF;;OAEG;IACG,YAAY,CACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,OAAe,GACzB,OAAO,CAAC;QACP,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IAkFF;;OAEG;IACG,eAAe,CAAC,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAWvE;;OAEG;IACG,oBAAoB,CAAC,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,KAAK,CAAC;QAC1D,MAAM,EAAE,iBAAiB,CAAC;QAC1B,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CAoBN"}
|