koishi-plugin-ll-brick 1.0.6 → 1.0.8
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.d.ts +1 -0
- package/lib/index.js +117 -29
- package/package.json +1 -1
- package/readme.md +15 -0
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -34,6 +34,9 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
34
34
|
specialUser: koishi_1.Schema.dict(Number)
|
|
35
35
|
.role('table')
|
|
36
36
|
.description('键为用户ID,值为被拍时的反击概率(%)<br/>不设置则使用默认概率'),
|
|
37
|
+
adminUsers: koishi_1.Schema.array(koishi_1.Schema.string())
|
|
38
|
+
.default([])
|
|
39
|
+
.description('管理员 ID 列表(openid):被加入的 ID 可以使用「充值」等管理命令'),
|
|
37
40
|
}),
|
|
38
41
|
koishi_1.Schema.object({
|
|
39
42
|
checking: koishi_1.Schema.boolean()
|
|
@@ -52,11 +55,9 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
52
55
|
])
|
|
53
56
|
]);
|
|
54
57
|
exports.inject = ["database"];
|
|
55
|
-
// QQ
|
|
56
|
-
// 因此 QQ 平台的回复直接走开放平台 internal API 发 markdown
|
|
57
|
-
//
|
|
58
|
-
const BRICK_IMG = 'https://img3.tofaka.com/autoupload/ontjZmlK09ZHnuFOv9znC7KXl_QqVl-bpSwqP4fJO68/20260624/lOIl/240X240/images.jpg';
|
|
59
|
-
const FIRE_IMG = 'https://img3.tofaka.com/autoupload/ontjZmlK09ZHnuFOv9znC7KXl_QqVl-bpSwqP4fJO68/20260624/xsnm/447X447/images_%282%29.jpg';
|
|
58
|
+
// 本插件面向 QQ 官方机器人。@ 标签(<qqbot-at-user>)只有在 markdown 消息里才渲染,
|
|
59
|
+
// 因此 QQ 平台的回复直接走开放平台 internal API 发 markdown;其他平台沿用原 h.at 文本消息。
|
|
60
|
+
// 所有通知均为 markdown 卡片(不含图片)。
|
|
60
61
|
function atUser(session, userId) {
|
|
61
62
|
if (session?.platform === 'qq') {
|
|
62
63
|
return `<qqbot-at-user id="${userId}" />`;
|
|
@@ -75,22 +76,22 @@ function stripMarkdown(md) {
|
|
|
75
76
|
.replace(/\n{3,}/g, '\n\n')
|
|
76
77
|
.trim();
|
|
77
78
|
}
|
|
78
|
-
|
|
79
|
+
function mdCard(lines) {
|
|
80
|
+
return lines.filter(Boolean).join('\n');
|
|
81
|
+
}
|
|
82
|
+
async function sendQQMarkdown(session, text) {
|
|
79
83
|
const channelId = session.guildId;
|
|
80
84
|
const internal = session.bot?.internal;
|
|
81
85
|
if (!channelId || !internal || typeof internal.sendMessage !== 'function') {
|
|
82
86
|
return false;
|
|
83
87
|
}
|
|
84
|
-
|
|
85
|
-
const img = imageUrl ? `` : '';
|
|
86
|
-
const md = [img, text].filter(Boolean).join('\n\n');
|
|
87
|
-
const plain = stripMarkdown(md) || ' ';
|
|
88
|
+
const plain = stripMarkdown(text) || ' ';
|
|
88
89
|
try {
|
|
89
90
|
await internal.sendMessage(channelId, {
|
|
90
91
|
msg_type: 2,
|
|
91
92
|
msg_seq: 0,
|
|
92
93
|
content: plain,
|
|
93
|
-
markdown: { content:
|
|
94
|
+
markdown: { content: text },
|
|
94
95
|
});
|
|
95
96
|
return true;
|
|
96
97
|
}
|
|
@@ -154,7 +155,19 @@ async function apply(ctx, config) {
|
|
|
154
155
|
return `已经在烧砖了`;
|
|
155
156
|
}
|
|
156
157
|
users[user].burning = true;
|
|
157
|
-
|
|
158
|
+
const startCard = mdCard([
|
|
159
|
+
'# 🔥 砖厂开始烧砖啦!',
|
|
160
|
+
'---',
|
|
161
|
+
'> 🏭 **工作状态**:现在开始烧砖啦!',
|
|
162
|
+
`> 💬 **烧砖规则**:群友每发送 **${config.cost}** 条消息,就能成功烧好一块新砖 🧱`,
|
|
163
|
+
'> 📢 大家快来水群,给砖窑添把火吧!',
|
|
164
|
+
]);
|
|
165
|
+
if (session.platform === 'qq') {
|
|
166
|
+
await sendQQMarkdown(session, startCard);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
await session.send(startCard);
|
|
170
|
+
}
|
|
158
171
|
let messageCount = 0;
|
|
159
172
|
const dispose = ctx.guild(session.guildId).middleware(async (session_in, next) => {
|
|
160
173
|
if (![session.selfId, session.userId].includes(session_in.userId)) {
|
|
@@ -167,12 +180,17 @@ async function apply(ctx, config) {
|
|
|
167
180
|
brick: koishi_1.$.add(row.brick, 1),
|
|
168
181
|
}], ["userId", "guildId"]);
|
|
169
182
|
users[user].burning = false;
|
|
170
|
-
const fireDone =
|
|
183
|
+
const fireDone = mdCard([
|
|
184
|
+
'# 🎉 砖厂出炉啦!',
|
|
185
|
+
'---',
|
|
186
|
+
`> 🔨 ${atUser(session, session.userId)} 砖已经烧好啦!`,
|
|
187
|
+
'> 📢 快去用 `砖头 拍人` 狠狠地拍一下吧!',
|
|
188
|
+
]);
|
|
171
189
|
if (session.platform === 'qq') {
|
|
172
|
-
await sendQQMarkdown(session,
|
|
190
|
+
await sendQQMarkdown(session, fireDone);
|
|
173
191
|
}
|
|
174
192
|
else {
|
|
175
|
-
await session.send(
|
|
193
|
+
await session.send(fireDone);
|
|
176
194
|
}
|
|
177
195
|
}
|
|
178
196
|
}
|
|
@@ -217,29 +235,36 @@ async function apply(ctx, config) {
|
|
|
217
235
|
const probability = config.specialUser[targetUserId] !== undefined
|
|
218
236
|
? config.specialUser[targetUserId] / 100
|
|
219
237
|
: config.reverse / 100;
|
|
220
|
-
const brickImg = koishi_1.h.image('https://img3.tofaka.com/autoupload/ontjZmlK09ZHnuFOv9znC7KXl_QqVl-bpSwqP4fJO68/20260624/lOIl/240X240/images.jpg');
|
|
221
238
|
const isQQ = session.platform === 'qq';
|
|
222
239
|
if (koishi_1.Random.bool(probability)) {
|
|
223
240
|
const muteErr = await tryMute(session.userId);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
241
|
+
const msg = mdCard([
|
|
242
|
+
'# 💥 群内突发事件!',
|
|
243
|
+
'---',
|
|
244
|
+
'> ⚠️ 危险警告:有人动用了板砖!',
|
|
245
|
+
`> 🎯 ${atUser(session, targetUserId)} 夺过你的砖头,把你拍晕了 **${muteTime}** 秒 🏏`,
|
|
246
|
+
muteErr ? '> ⚠️ 因为我不是群管理员,所以并没什么卵用' : '',
|
|
247
|
+
]);
|
|
227
248
|
if (isQQ) {
|
|
228
|
-
await sendQQMarkdown(session,
|
|
249
|
+
await sendQQMarkdown(session, msg);
|
|
229
250
|
return;
|
|
230
251
|
}
|
|
231
|
-
return
|
|
252
|
+
return msg;
|
|
232
253
|
}
|
|
233
254
|
else {
|
|
234
255
|
const muteErr = await tryMute(targetUserId);
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
256
|
+
const msg = mdCard([
|
|
257
|
+
'# 💥 群内突发事件!',
|
|
258
|
+
'---',
|
|
259
|
+
'> ⚠️ 危险警告:有人动用了板砖!',
|
|
260
|
+
`> 🎯 ${atUser(session, targetUserId)} 你被 ${atUser(session, session.userId)} 一砖头拍晕了 **${muteTime}** 秒 🏏`,
|
|
261
|
+
muteErr ? '> ⚠️ 因为我不是群管理员,所以并没什么卵用' : '',
|
|
262
|
+
]);
|
|
238
263
|
if (isQQ) {
|
|
239
|
-
await sendQQMarkdown(session,
|
|
264
|
+
await sendQQMarkdown(session, msg);
|
|
240
265
|
return;
|
|
241
266
|
}
|
|
242
|
-
return
|
|
267
|
+
return msg;
|
|
243
268
|
}
|
|
244
269
|
async function tryMute(slapedUserId) {
|
|
245
270
|
users[`${session.guildId}:${slapedUserId}`].muted = true;
|
|
@@ -297,6 +322,49 @@ async function apply(ctx, config) {
|
|
|
297
322
|
return `你有 ${brickData[0].brick}/${config.maxBrick} 块砖头`;
|
|
298
323
|
}
|
|
299
324
|
});
|
|
325
|
+
ctx.command("砖头.充值 <user:user> <amount:number>", "给指定用户充值砖头(仅管理员)")
|
|
326
|
+
.alias("充值")
|
|
327
|
+
.example("充值 @某人 10")
|
|
328
|
+
.action(async ({ session }, user, amount) => {
|
|
329
|
+
if (!config.adminUsers.includes(session.userId)) {
|
|
330
|
+
return '只有管理员才能使用 充值';
|
|
331
|
+
}
|
|
332
|
+
const targetUserId = user && user.split(":")[1];
|
|
333
|
+
if (!targetUserId) {
|
|
334
|
+
return '无效的用户';
|
|
335
|
+
}
|
|
336
|
+
const add = Math.floor(Number(amount));
|
|
337
|
+
if (!Number.isFinite(add) || add <= 0) {
|
|
338
|
+
return '充值数量无效';
|
|
339
|
+
}
|
|
340
|
+
const existing = await ctx.database.get('brick', {
|
|
341
|
+
userId: targetUserId,
|
|
342
|
+
guildId: session.guildId,
|
|
343
|
+
});
|
|
344
|
+
const cur = existing.length ? existing[0].brick : 0;
|
|
345
|
+
if (cur >= config.maxBrick) {
|
|
346
|
+
return `该用户砖头已满(${cur}/${config.maxBrick})`;
|
|
347
|
+
}
|
|
348
|
+
let real = add;
|
|
349
|
+
if (cur + real > config.maxBrick) {
|
|
350
|
+
real = config.maxBrick - cur;
|
|
351
|
+
}
|
|
352
|
+
if (existing.length === 0) {
|
|
353
|
+
await ctx.database.create('brick', {
|
|
354
|
+
userId: targetUserId,
|
|
355
|
+
guildId: session.guildId,
|
|
356
|
+
brick: real,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
await ctx.database.upsert('brick', (row) => [{
|
|
361
|
+
userId: targetUserId,
|
|
362
|
+
guildId: session.guildId,
|
|
363
|
+
brick: koishi_1.$.add(row.brick, real),
|
|
364
|
+
}], ["userId", "guildId"]);
|
|
365
|
+
}
|
|
366
|
+
return `已给 ${targetUserId.slice(0, 8)} 充值 ${real} 块砖头(现有 ${cur + real}/${config.maxBrick})`;
|
|
367
|
+
});
|
|
300
368
|
if (config.checking) {
|
|
301
369
|
ctx.command("砖头.签到")
|
|
302
370
|
.alias("砖头签到")
|
|
@@ -304,7 +372,6 @@ async function apply(ctx, config) {
|
|
|
304
372
|
const date = new Date();
|
|
305
373
|
const today = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
|
306
374
|
let brick = koishi_1.Random.int(config.minGain, config.maxGain + 1);
|
|
307
|
-
const signImg = koishi_1.h.image('https://img3.tofaka.com/autoupload/ontjZmlK09ZHnuFOv9znC7KXl_QqVl-bpSwqP4fJO68/20260624/yNf2/447X447/images_%281%29.jpg');
|
|
308
375
|
const userData = await ctx.database.get('brick', {
|
|
309
376
|
userId: session.userId,
|
|
310
377
|
guildId: session.guildId,
|
|
@@ -316,7 +383,17 @@ async function apply(ctx, config) {
|
|
|
316
383
|
brick: brick,
|
|
317
384
|
checkingDay: today
|
|
318
385
|
});
|
|
319
|
-
|
|
386
|
+
const card = mdCard([
|
|
387
|
+
'# 🎡 砖厂打卡成功!',
|
|
388
|
+
'---',
|
|
389
|
+
`> 😋 辛苦啦!你刚刚搬运获得了 **${brick}** 块砖头 🧱`,
|
|
390
|
+
`> 📦 **当前库存**:你现在共有 \`${brick}/${config.maxBrick}\` 块砖头。`,
|
|
391
|
+
]);
|
|
392
|
+
if (session.platform === 'qq') {
|
|
393
|
+
await sendQQMarkdown(session, card);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
return card;
|
|
320
397
|
}
|
|
321
398
|
if (userData[0].checkingDay === today) {
|
|
322
399
|
return "你今天已经签到过了";
|
|
@@ -336,7 +413,18 @@ async function apply(ctx, config) {
|
|
|
336
413
|
brick: koishi_1.$.add(row.brick, brick),
|
|
337
414
|
checkingDay: today
|
|
338
415
|
}], ["userId", "guildId"]);
|
|
339
|
-
|
|
416
|
+
const total = userData[0].brick + brick;
|
|
417
|
+
const card = mdCard([
|
|
418
|
+
'# 🎡 砖厂打卡成功!',
|
|
419
|
+
'---',
|
|
420
|
+
`> 😋 辛苦啦!你刚刚搬运获得了 **${brick}** 块砖头 🧱`,
|
|
421
|
+
`> 📦 **当前库存**:你现在共有 \`${total}/${config.maxBrick}\` 块砖头。`,
|
|
422
|
+
]);
|
|
423
|
+
if (session.platform === 'qq') {
|
|
424
|
+
await sendQQMarkdown(session, card);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
return card;
|
|
340
428
|
});
|
|
341
429
|
}
|
|
342
430
|
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -13,6 +13,21 @@
|
|
|
13
13
|
- `砖头 查看` — 查看自己的砖头数量
|
|
14
14
|
- `砖头 签到`(可选开启)— 每日签到获取随机砖头
|
|
15
15
|
|
|
16
|
+
## v1.0.8 新增
|
|
17
|
+
|
|
18
|
+
- **设置页新增「管理员 ID 列表」**(`adminUsers`):填入用户的 openid 即成为管理员,无需额外管理员命令
|
|
19
|
+
- 新增命令 **`砖头 充值 @某人 <数量>`**(仅管理员可用):给指定用户充入砖头(不会超过上限 `maxBrick`)
|
|
20
|
+
- 非管理员使用充值会提示"只有管理员才能使用 充值"
|
|
21
|
+
|
|
22
|
+
## v1.0.7 更新
|
|
23
|
+
|
|
24
|
+
- **移除所有图片**,所有通知统一改为 markdown 卡片样式(`# 标题` + `---` + `> 引用行`),加载更快
|
|
25
|
+
- 烧砖开始:「砖厂开始烧砖啦!」
|
|
26
|
+
- 烧砖完成:「砖厂出炉啦!」
|
|
27
|
+
- 拍人成功:「群内突发事件!」(两种分支)
|
|
28
|
+
- 签到打卡:「砖厂打卡成功!」
|
|
29
|
+
- `@` 保留用 `<qqbot-at-user>`,markdown 里正常渲染(与欢迎插件一致)
|
|
30
|
+
|
|
16
31
|
## v1.0.6 修复
|
|
17
32
|
|
|
18
33
|
- 修复 **`砖头 随机拍人` 报错 `not implemented: getGuildMemberList`**(QQ 官方适配器未实现群成员迭代接口):
|