koishi-plugin-satori-ai 1.3.4 → 1.3.5

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.
@@ -0,0 +1,24 @@
1
+ import { Context, Session } from 'koishi';
2
+ import { Sat } from './types';
3
+ export declare class BroadcastManager {
4
+ private ctx;
5
+ private config;
6
+ private idCounter;
7
+ private broadcastMessages;
8
+ constructor(ctx: Context, cfg: Sat.Config);
9
+ createBroadcast(message: string, img: boolean): Promise<string>;
10
+ deleteBroadcast(id: string): Promise<string>;
11
+ seedBroadcast(session: Session): Promise<void>;
12
+ getBroadcastList(): Promise<string>;
13
+ }
14
+ export declare class broadcastMessage {
15
+ private ctx;
16
+ private config;
17
+ message: string;
18
+ private alreadySentChannels;
19
+ setTime: Date;
20
+ private img;
21
+ constructor(ctx: Context, cfg: Sat.Config, message: string, img: boolean);
22
+ sendMessage(session: Session): Promise<void>;
23
+ getAlreadySentChannels(): string;
24
+ }
@@ -30,8 +30,7 @@ declare class OneTouchSingleGame extends abstractGameSingleGame {
30
30
  private buildMyTurnBonusMessage;
31
31
  private processAiTurn;
32
32
  private buildAiTurnBonusMessage;
33
- private applyEffectToEnemy;
34
- private applyEffectToSelf;
33
+ private applyEffect;
35
34
  private checkCombo;
36
35
  private buildResultMessage;
37
36
  private aiSearchEntrance;
package/lib/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Context, Session } from 'koishi';
2
2
  import { Sat, User } from './types';
3
3
  import Puppeteer from 'koishi-plugin-puppeteer';
4
+ import { BroadcastManager } from './broadcast';
4
5
  export declare let puppeteer: Puppeteer | null;
5
6
  export declare function refreshPuppeteer(ctx: Context): void;
6
7
  export declare class SAT extends Sat {
@@ -11,6 +12,7 @@ export declare class SAT extends Sat {
11
12
  private ChannelParallelCount;
12
13
  private onlineUsers;
13
14
  private moodManager;
15
+ broadcastManager: BroadcastManager;
14
16
  private usersToWarn;
15
17
  private game;
16
18
  constructor(ctx: Context, config: Sat.Config);
package/lib/index.js CHANGED
@@ -33,7 +33,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
33
33
  // src/locales/zh.yml
34
34
  var require_zh = __commonJS({
35
35
  "src/locales/zh.yml"(exports, module2) {
36
- module2.exports = { commands: { sat: { description: "AI聊天", messages: { "no-prompt": "你好。使用说明可以看我的空间哦。", tooManyEnglishLetters: "请不要用这么多英文......", err: "寄!{0}", tooLong: "你的话太多了。", content_tooLong: "这个问题有点复杂,你还是去问别人吧。", "duplicate-dialogue": "这个刚刚说过了吧......", online: "思考中,请再等一会!", "no-response": "我不知道你在说什么……", update_level_succeed: "用户等级已更新为{0}", exceeds: "已经差不多够了吧?请明天再来。", usage: "今日次数{0}/{1}", hatMan: "叮!帽子先生保护了你的好感度,快说谢谢帽子先生吧!", rockBottom: "叮!谷底小石保护了你的好感度,快说谢谢谷底小石吧!", not_good_mood: "别得寸进尺……(好感↓)", pocket_money: "心情不错,给你点零花钱吧~(获得了{0}p点)", warning: "<at id={0}/>", block1: "我讨厌你!", block2: "我讨厌你们!" } }, "sat.clear": { description: "清空当前频道会话", messages: { clean: "已清空当前会话。", Allclean: "已清空所有会话。" } }, "sat.common_sense": { description: "添加常识", messages: { "no-prompt": "你想让我知道什么?", succeed: "我知道了,{0}" } } } };
36
+ module2.exports = { commands: { sat: { description: "AI聊天", messages: { "no-prompt": "你好。使用说明可以看我的空间哦。", tooManyEnglishLetters: "请不要用这么多英文......", err: "寄!{0}", tooLong: "你的话太多了。", content_tooLong: "这个问题有点复杂,你还是去问别人吧。", "duplicate-dialogue": "这个刚刚说过了吧......", online: "思考中,请再等一会!", "no-response": "我不知道你在说什么……", update_level_succeed: "用户等级已更新为{0}", exceeds: "已经差不多够了吧?请明天再来。", usage: "今日次数{0}/{1}", hatMan: "叮!帽子先生保护了你的好感度,快说谢谢帽子先生吧!", rockBottom: "叮!谷底小石保护了你的好感度,快说谢谢谷底小石吧!", not_good_mood: "别得寸进尺……(好感↓)", pocket_money: "心情不错,给你点零花钱吧~(获得了{0}p点)", warning: "<at id={0}/>", block1: "我讨厌你!", block2: "我讨厌你们!" } }, "sat.clear": { description: "清空当前频道会话", messages: { clean: "已清空当前会话。", Allclean: "已清空所有会话。" } }, "sat.common_sense": { description: "添加常识", messages: { "no-prompt": "你想让我知道什么?", succeed: "我知道了,{0}" } }, "sat.broadcast": { description: "广播一条消息,在每个生效群收到首条消息时会推送", options: { delete: "删除一条广播,参数为广播的ID", list: "查看当前所有广播", img: "使用puppeteer图片化广播消息" } } } };
37
37
  }
38
38
  });
39
39
 
@@ -46,7 +46,7 @@ __export(src_exports, {
46
46
  refreshPuppeteer: () => refreshPuppeteer
47
47
  });
48
48
  module.exports = __toCommonJS(src_exports);
49
- var import_koishi13 = require("koishi");
49
+ var import_koishi14 = require("koishi");
50
50
  var path7 = __toESM(require("path"));
51
51
 
52
52
  // src/api.ts
@@ -255,7 +255,7 @@ function processPrompt(prompt) {
255
255
  prompt = prompt.replace(/\*\*/g, "");
256
256
  if (!prompt)
257
257
  return "**";
258
- return prompt;
258
+ return prompt.trim();
259
259
  }
260
260
  __name(processPrompt, "processPrompt");
261
261
  function filterResponse(prompt, words) {
@@ -1028,6 +1028,7 @@ function createMiddleware(ctx, sat, config) {
1028
1028
  return async (session, next) => {
1029
1029
  if (config.enable_favorability && config.enable_warning && session.channelId === config.warning_group)
1030
1030
  sat.getWarningList(session);
1031
+ sat.broadcastManager.seedBroadcast(session);
1031
1032
  if (!isSpecialMessage(session))
1032
1033
  await sat.handleChannelMemoryManager(session);
1033
1034
  if (config.private && isPrivateSession(session)) {
@@ -1217,6 +1218,10 @@ var Sat = class extends import_koishi5.Service {
1217
1218
  max_pocket_money: import_koishi5.Schema.number().default(400).description("随机p点最大值"),
1218
1219
  pocket_money_cost: import_koishi5.Schema.number().default(2).description("消耗心情换p点的心情值")
1219
1220
  }).description("好感度拓展:心情设置(需要开启好感度模块才能生效)"),
1221
+ import_koishi5.Schema.object({
1222
+ Broadcast_block_channel: import_koishi5.Schema.array(String).description("不提供广播的频道id"),
1223
+ waiting_time: import_koishi5.Schema.number().default(1440).description("广播在缓存中等待的最大时间(分钟)(超过时间后没有触发会不再推送)")
1224
+ }).description("广播设置(发出后在每个生效群收到首条消息时会推送)"),
1220
1225
  import_koishi5.Schema.object({
1221
1226
  enable_game: import_koishi5.Schema.boolean().default(false).description("是否开启游戏模块"),
1222
1227
  game_block_channel: import_koishi5.Schema.array(String).description("不提供游戏的频道id"),
@@ -2203,13 +2208,13 @@ var SKILL_MAP = {
2203
2208
  "4+6": { shield: 2, heal: 5, selfbleed: -3, name: "固守" },
2204
2209
  "8+8": { damage: 13, damageTimes: 2, selfStun: true, name: "双持" },
2205
2210
  "1+2": { pierceDamage: 3, vulnerablility: 3, stun: true, name: "弱点刺击" },
2206
- "2+8": { damage: 8, stun: true, selfStun: true, addLeft: 1, addRight: 9, name: "点射" },
2211
+ "2+8": { damage: 12, stun: true, selfStun: true, addLeft: 1, addRight: 9, name: "点射" },
2207
2212
  "3+4": { name: "防御反击", shield: 1, counterAttack: 15 },
2208
2213
  "7+7": { pierceDamage: 7, destroyShield: 5, name: "穿龙枪" },
2209
2214
  "7+8": { pierceDamage: 13, destroyShield: 3, selfStun: true, name: "穿甲弹" },
2210
2215
  "2+6": { damage: 5, heal: 6, selfbleed: -1, selfstrengthChange: 1, stun: true, name: "点辰" },
2211
2216
  "3+7": { name: "混沌", counterAttack: 7, destroyShield: 2, addLeft: 9, addRight: 1 },
2212
- "0+9": { name: "将大局逆转吧", revwersalOfStrength: true },
2217
+ "0+9": { name: "将大局逆转吧", revwersalOfStrength: true, selfstrengthChange: 2, strengthChange: -1 },
2213
2218
  "0+0": { name: "华丽收场", bleed: 5, selfstrengthChange: -99, magnificentEnd: true }
2214
2219
  };
2215
2220
  var OneTouchSingleGame = class extends abstractGameSingleGame {
@@ -2225,7 +2230,7 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
2225
2230
  // 当前回合数
2226
2231
  baseHP = 40;
2227
2232
  // 初始血量
2228
- playerLevelHP = 10;
2233
+ playerLevelHP = 8;
2229
2234
  // 每级增加的血量
2230
2235
  aiLevelHp = 10;
2231
2236
  // AI每级增加的血量
@@ -2272,11 +2277,11 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
2272
2277
  endGame = async () => {
2273
2278
  if (this.winningFlag === 4 /* pending */ || this.winningFlag === 2 /* lose */) {
2274
2279
  this.bonus = Math.abs(Math.floor(this.level * 0.2 * this.bonus));
2275
- this.bonus -= Math.floor(this.level * this.level * (Math.random() * 2 + 2) + 200);
2280
+ this.bonus -= Math.floor(this.level * this.level * (Math.random() * 2 + 2) + 50);
2276
2281
  this.bonus = Math.min(this.bonus, 0);
2277
2282
  }
2278
2283
  if (this.winningFlag === 1 /* win */) {
2279
- this.bonus = Math.floor(this.level * this.bonus * 0.2 * (Math.random() * 1 + 1));
2284
+ this.bonus = Math.floor(this.level * this.bonus * 0.1 * (Math.random() * 1 + 1));
2280
2285
  }
2281
2286
  const finalBonus = this.bonus;
2282
2287
  super.endGame();
@@ -2287,7 +2292,7 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
2287
2292
  left: this.player.left,
2288
2293
  right: this.player.right,
2289
2294
  hp: this.baseHP + level * this.playerLevelHP,
2290
- shield: Math.round(level / 2),
2295
+ shield: Math.round(5 - level / 2),
2291
2296
  strength: 0,
2292
2297
  bleed: 0,
2293
2298
  counterAttack: 0,
@@ -2382,7 +2387,7 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
2382
2387
  }
2383
2388
  if (this.player.status === 1 /* Stunned */) {
2384
2389
  this.player.status = 2 /* lastStunned */;
2385
- this.player = this.applyEffectToSelf(this.ai, this.player, SKILL_MAP["-1"]);
2390
+ this.applyEffect(this.player, this.ai, SKILL_MAP["-1"], false);
2386
2391
  return "你被眩晕,跳过回合";
2387
2392
  }
2388
2393
  const sum = (handA + handB) % 10;
@@ -2398,10 +2403,7 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
2398
2403
  this.comboCombos = 0;
2399
2404
  }
2400
2405
  const bonusMessage = this.buildMyTurnBonusMessage(effect, isCombo);
2401
- const playerState = this.player;
2402
- const aiState = this.ai;
2403
- this.ai = this.applyEffectToEnemy(playerState, aiState, effect, !!combo);
2404
- this.player = this.applyEffectToSelf(aiState, playerState, effect);
2406
+ this.applyEffect(this.player, this.ai, effect, !!combo);
2405
2407
  return this.buildResultMessage(effect, isCombo, this.player, this.ai) + (bonusMessage ? `
2406
2408
 
2407
2409
  ${bonusMessage}` : "");
@@ -2440,7 +2442,7 @@ ${bonusMessage}` : "");
2440
2442
  bonusMessage += `流血打击!获得${effectBonus}点分数!
2441
2443
  `;
2442
2444
  }
2443
- if ((effect.shield || 0) + this.player.shield >= 5) {
2445
+ if (effect.shield && (effect.shield || 0) + this.player.shield >= 5) {
2444
2446
  const effectBonus = Math.round(((effect.shield || 0) + this.player.shield) * 2);
2445
2447
  this.singleBonus += effectBonus;
2446
2448
  bonusMessage += `强效护盾!获得${effectBonus}点分数!
@@ -2477,7 +2479,7 @@ ${bonusMessage}` : "");
2477
2479
  `;
2478
2480
  }
2479
2481
  if (effect.revwersalOfStrength && this.player.strength <= this.ai.strength - 5) {
2480
- const effectBonus = Math.round((this.ai.strength - this.player.strength) * 3);
2482
+ const effectBonus = Math.min((this.ai.strength - this.player.strength) * 3, 100);
2481
2483
  this.singleBonus += effectBonus;
2482
2484
  bonusMessage += `逆转大局!获得${effectBonus}点分数!
2483
2485
  `;
@@ -2495,7 +2497,7 @@ ${bonusMessage}` : "");
2495
2497
  bonusMessage += `压倒性的优势!获得${effectBonus}点分数!本回合分数*2!
2496
2498
  `;
2497
2499
  }
2498
- if (effect.magnificentEnd && this.ai.bleed > 4) {
2500
+ if (effect.magnificentEnd && this.ai.bleed > 1) {
2499
2501
  const effectBonus = Math.round(this.ai.bleed * 1.5);
2500
2502
  this.singleBonusMultiplier *= effectBonus;
2501
2503
  this.bonus *= 2;
@@ -2518,7 +2520,7 @@ ${bonusMessage}` : "");
2518
2520
  }
2519
2521
  if (this.ai.status === 1 /* Stunned */) {
2520
2522
  this.ai.status = 2 /* lastStunned */;
2521
- this.ai = this.applyEffectToSelf(this.player, this.ai, SKILL_MAP["-1"]);
2523
+ this.applyEffect(this.ai, this.player, SKILL_MAP["-1"], false);
2522
2524
  return "被眩晕,跳过回合,本回合分数奖励继承到下一回合";
2523
2525
  }
2524
2526
  const sum = (handA + handB) % 10;
@@ -2530,11 +2532,8 @@ ${bonusMessage}` : "");
2530
2532
  isCombo = true;
2531
2533
  effect = { ...combo };
2532
2534
  }
2533
- const playerState = this.player;
2534
- const aiState = this.ai;
2535
2535
  const bonusMessage = this.buildAiTurnBonusMessage(effect);
2536
- this.player = this.applyEffectToEnemy(aiState, playerState, effect, !!combo);
2537
- this.ai = this.applyEffectToSelf(playerState, aiState, effect);
2536
+ this.applyEffect(this.ai, this.player, effect, !!combo);
2538
2537
  return handA + "碰" + handB + "," + this.buildResultMessage(effect, isCombo, this.ai, this.player) + (bonusMessage ? `
2539
2538
 
2540
2539
  ${bonusMessage}` : "");
@@ -2587,50 +2586,31 @@ ${bonusMessage}` : "");
2587
2586
  // destroyShield?: number // 破坏护盾
2588
2587
  // weakStun?: boolean // 弱眩晕
2589
2588
  // strengthChange?: number // 力量变化
2590
- applyEffectToEnemy(self, target, effect, isCombo) {
2589
+ // heal?: number // 治疗
2590
+ // shield?: number // 护盾
2591
+ // selfbleed?: number // 自身流血
2592
+ // selfStun?: boolean // 自身眩晕
2593
+ // selfstrengthChange?: number // 自身力量变化
2594
+ applyEffect(self, enemy, effect, isCombo) {
2595
+ if (effect.revwersalOfStrength) {
2596
+ const temp = self.strength;
2597
+ self.strength = enemy.strength;
2598
+ enemy.strength = temp;
2599
+ }
2591
2600
  if (effect.pierceDamage)
2592
- target.hp -= Math.max(effect.pierceDamage + (self.strength || 0), 0);
2601
+ enemy.hp -= Math.max(effect.pierceDamage + (self.strength || 0), 0);
2593
2602
  if (effect.destroyShield)
2594
- target.shield = Math.max(0, target.shield - effect.destroyShield);
2603
+ enemy.shield = Math.max(0, enemy.shield - effect.destroyShield);
2595
2604
  if (effect.bleed)
2596
- target.bleed += effect.bleed;
2605
+ enemy.bleed += effect.bleed;
2597
2606
  if (effect.strengthChange)
2598
- target.strength = target.strength + effect.strengthChange;
2607
+ enemy.strength = enemy.strength + effect.strengthChange;
2599
2608
  if (effect.addLeft)
2600
- target.left = (target.left + effect.addLeft) % 10;
2609
+ enemy.left = (enemy.left + effect.addLeft) % 10;
2601
2610
  if (effect.addRight)
2602
- target.right = (target.right + effect.addRight) % 10;
2611
+ enemy.right = (enemy.right + effect.addRight) % 10;
2603
2612
  if (effect.vulnerablility)
2604
- target.vulnerablility = (target.vulnerablility || 0) + effect.vulnerablility;
2605
- if (effect.damage) {
2606
- effect.damageTimes = effect.damageTimes || 1;
2607
- for (let i = 0; i < effect.damageTimes; i++) {
2608
- const blocked = target.shield > 0;
2609
- target.shield = Math.max(0, target.shield - (isCombo ? 2 : 1));
2610
- if (!blocked) {
2611
- target.hp -= Math.round(Math.max(0, effect.damage + (self.strength || 0)) * (target.vulnerablility ? 1.5 : 1));
2612
- if (effect.weakStun && target.status !== 2 /* lastStunned */) {
2613
- target.status = 1 /* Stunned */;
2614
- }
2615
- }
2616
- }
2617
- }
2618
- if (effect.revwersalOfStrength)
2619
- target.strength = self.strength;
2620
- if (effect.magnificentEnd) {
2621
- target.hp -= target.bleed * (target.bleed + 1) / 2;
2622
- target.bleed = 0;
2623
- }
2624
- if (effect.stun && target.status !== 2 /* lastStunned */)
2625
- target.status = 1 /* Stunned */;
2626
- return target;
2627
- }
2628
- // heal?: number // 治疗
2629
- // shield?: number // 护盾
2630
- // selfbleed?: number // 自身流血
2631
- // selfStun?: boolean // 自身眩晕
2632
- // selfstrengthChange?: number // 自身力量变化
2633
- applyEffectToSelf(enemy, self, effect) {
2613
+ enemy.vulnerablility = (enemy.vulnerablility || 0) + effect.vulnerablility;
2634
2614
  if (effect.heal)
2635
2615
  self.hp += effect.heal;
2636
2616
  if (effect.shield)
@@ -2641,24 +2621,41 @@ ${bonusMessage}` : "");
2641
2621
  self.left = (self.left + effect.addSelfLeft) % 10;
2642
2622
  if (effect.addSelfRight)
2643
2623
  self.right = (self.right + effect.addSelfRight) % 10;
2624
+ if (effect.damage) {
2625
+ effect.damageTimes = effect.damageTimes || 1;
2626
+ for (let i = 0; i < effect.damageTimes; i++) {
2627
+ const blocked = enemy.shield > 0;
2628
+ enemy.shield = Math.max(0, enemy.shield - (isCombo ? 2 : 1));
2629
+ if (!blocked) {
2630
+ enemy.hp -= Math.round(Math.max(0, effect.damage + (self.strength || 0)) * (enemy.vulnerablility ? 1.5 : 1));
2631
+ if (effect.weakStun && enemy.status !== 2 /* lastStunned */) {
2632
+ enemy.status = 1 /* Stunned */;
2633
+ }
2634
+ }
2635
+ }
2636
+ }
2644
2637
  if (self.counterAttack)
2645
2638
  self.counterAttack = 0;
2646
2639
  if (effect.counterAttack)
2647
2640
  self.counterAttack = effect.counterAttack;
2648
2641
  if (enemy.counterAttack > 0 && (effect.damage > 0 || effect.pierceDamage > 0))
2649
2642
  self.hp -= Math.max(enemy.counterAttack + (enemy.strength || 0), 0);
2650
- if (effect.revwersalOfStrength)
2651
- self.strength = enemy.strength;
2652
- if (effect.selfStun && self.status !== 2 /* lastStunned */)
2653
- self.status = 1 /* Stunned */;
2654
2643
  if (effect.selfbleed)
2655
- self.bleed = self.bleed + effect.selfbleed;
2644
+ self.bleed += effect.selfbleed;
2656
2645
  if (self.bleed > 0)
2657
2646
  self.hp -= self.bleed;
2658
2647
  self.bleed = Math.max(0, self.bleed - 1);
2648
+ if (effect.magnificentEnd) {
2649
+ enemy.hp -= enemy.bleed * (enemy.bleed + 1) / 2;
2650
+ enemy.bleed = 0;
2651
+ }
2659
2652
  if (self.vulnerablility)
2660
2653
  self.vulnerablility = Math.max(0, self.vulnerablility - 1);
2661
- return self;
2654
+ if (effect.stun && enemy.status !== 2 /* lastStunned */)
2655
+ enemy.status = 1 /* Stunned */;
2656
+ if (effect.selfStun && self.status !== 2 /* lastStunned */)
2657
+ self.status = 1 /* Stunned */;
2658
+ return;
2662
2659
  }
2663
2660
  checkCombo(a, b) {
2664
2661
  const key = `${Math.min(a, b)}+${Math.max(a, b)}`;
@@ -2668,6 +2665,8 @@ ${bonusMessage}` : "");
2668
2665
  let msg = [];
2669
2666
  if (effect.name)
2670
2667
  msg.push(`${effect.name}!`);
2668
+ if (effect.revwersalOfStrength)
2669
+ msg.push(`双方力量反转!`);
2671
2670
  if (effect.pierceDamage)
2672
2671
  msg.push(`对对方造成穿刺伤害${Math.max(0, effect.pierceDamage + (self.strength || 0))}`);
2673
2672
  if (effect.damage)
@@ -2729,7 +2728,7 @@ ${bonusMessage}` : "");
2729
2728
  ];
2730
2729
  const newState = this.simulateMove(move, simulatedState, 1);
2731
2730
  const score = this.aiSearch(
2732
- this.level,
2731
+ Math.round(this.level / 2),
2733
2732
  false,
2734
2733
  newState,
2735
2734
  -Infinity,
@@ -2788,7 +2787,7 @@ ${bonusMessage}` : "");
2788
2787
  }
2789
2788
  return moves;
2790
2789
  }
2791
- // 深度克隆玩家状态
2790
+ // 克隆玩家状态
2792
2791
  cloneState(state) {
2793
2792
  return {
2794
2793
  left: state.left,
@@ -2797,6 +2796,8 @@ ${bonusMessage}` : "");
2797
2796
  shield: state.shield,
2798
2797
  strength: state.strength,
2799
2798
  bleed: state.bleed,
2799
+ counterAttack: state.counterAttack,
2800
+ vulnerablility: state.vulnerablility,
2800
2801
  status: state.status
2801
2802
  };
2802
2803
  }
@@ -2809,16 +2810,13 @@ ${bonusMessage}` : "");
2809
2810
  attacker.status = 0 /* Normal */;
2810
2811
  if (attacker.status === 1 /* Stunned */) {
2811
2812
  attacker.status = 2 /* lastStunned */;
2812
- attacker = this.applyEffectToSelf(defender, attacker, SKILL_MAP["-1"]);
2813
+ this.applyEffect(attacker, defender, SKILL_MAP["-1"], false);
2813
2814
  } else {
2814
2815
  const sum = (handA + handB) % 10;
2815
2816
  attacker[handA === attacker.left ? "left" : "right"] = sum;
2816
2817
  const combo = this.checkCombo(attacker.left, attacker.right);
2817
2818
  const effect = combo ? combo : SKILL_MAP[sum.toString()] || {};
2818
- const defenderState = defender;
2819
- const attackerState = attacker;
2820
- defender = this.applyEffectToEnemy(attackerState, defenderState, effect, !!combo);
2821
- attacker = this.applyEffectToSelf(defenderState, attackerState, effect);
2819
+ this.applyEffect(attacker, defender, effect, !!combo);
2822
2820
  }
2823
2821
  if (attackerIndex === 1) {
2824
2822
  const temp = attacker;
@@ -2848,11 +2846,7 @@ ${bonusMessage}` : "");
2848
2846
  if (player.hp < playerBaseHP / 8)
2849
2847
  score += Math.round(playerBaseHP / 4);
2850
2848
  score += Math.min(ai.strength * 5, 100);
2851
- score -= Math.min(player.strength * 5);
2852
- if (ai.strength < 0)
2853
- score += Math.round(ai.strength * 5);
2854
- if (player.strength < 0)
2855
- score -= Math.round(player.strength * 5);
2849
+ score -= Math.max(player.strength * 5, -100);
2856
2850
  score += ai.shield * 8;
2857
2851
  score -= player.shield * 8;
2858
2852
  score -= Math.min(Math.round(ai.bleed * ai.bleed / 2.5));
@@ -2882,7 +2876,7 @@ ${bonusMessage}` : "");
2882
2876
  if (this.lastScore < 0 && Score > 0) {
2883
2877
  return "局势发生变化了呢~";
2884
2878
  }
2885
- if (Score - this.lastScore > 10)
2879
+ if (Score - this.lastScore > 10 && Math.random() > 0.5)
2886
2880
  return "看招!";
2887
2881
  }
2888
2882
  instuction = `游戏说明:
@@ -2895,7 +2889,7 @@ ${bonusMessage}` : "");
2895
2889
  当自身两手手势相同时,无论选择左手还是右手最终发生变化的都是左手。
2896
2890
  玩家初始有"${this.baseHP} + ${this.playerLevelHP} * 难度"血量。
2897
2891
  ai初始有"${this.baseHP} + ${this.aiLevelHp} * 难度"血量。
2898
- 玩家初始有"难度 / 2"护盾,四舍五入取整。
2892
+ 玩家初始有"5 - 难度 / 2"护盾,四舍五入取整。
2899
2893
  血量没有上限,率先将对方血量减到零的人获胜:
2900
2894
  具体的技能设计如下:{
2901
2895
  一:${SKILL_MAP["1"].name}:造成${SKILL_MAP["1"].pierceDamage}穿刺伤害,${SKILL_MAP["1"].bleed}流血;
@@ -2925,7 +2919,7 @@ ${bonusMessage}` : "");
2925
2919
  七+八:${SKILL_MAP["7+8"].name}:造成${SKILL_MAP["7+8"].pierceDamage}穿刺伤害,破坏对方${SKILL_MAP["7+8"].destroyShield}层护盾,眩晕自己
2926
2920
  六+二:${SKILL_MAP["2+6"].name}:造成${SKILL_MAP["2+6"].damage}伤害,恢复${SKILL_MAP["2+6"].heal}生命,自身${SKILL_MAP["2+6"].selfbleed}流血,自身增加${SKILL_MAP["2+6"].selfstrengthChange}力量,眩晕对方
2927
2921
  三+七:${SKILL_MAP["3+7"].name}:获得${SKILL_MAP["3+7"].counterAttack}层反击,破坏对方${SKILL_MAP["3+7"].destroyShield}层护盾,对方左手数值增加${SKILL_MAP["3+7"].addLeft},右手数值增加${SKILL_MAP["3+7"].addRight}
2928
- 九+十:${SKILL_MAP["0+9"].name}:逆转双方力量。
2922
+ 九+十:${SKILL_MAP["0+9"].name}:逆转双方力量,然后增加自身${SKILL_MAP["0+9"].selfstrengthChange}力量,对方${SKILL_MAP["0+9"].strengthChange}力量
2929
2923
  十+十:${SKILL_MAP["0+0"].name}:对对方造成${SKILL_MAP["0+0"].bleed}流血,自身${SKILL_MAP["0+0"].selfstrengthChange}力量,然后立即结算对方全部流血
2930
2924
  }
2931
2925
  注:
@@ -3134,14 +3128,152 @@ var Game = class {
3134
3128
  }
3135
3129
  };
3136
3130
 
3131
+ // src/broadcast.ts
3132
+ var import_koishi13 = require("koishi");
3133
+ var logger12 = new import_koishi13.Logger("satori-ai-broadcast");
3134
+ var BroadcastManager = class {
3135
+ static {
3136
+ __name(this, "BroadcastManager");
3137
+ }
3138
+ ctx;
3139
+ config;
3140
+ idCounter = 0;
3141
+ broadcastMessages = /* @__PURE__ */ new Map();
3142
+ constructor(ctx, cfg) {
3143
+ this.ctx = ctx;
3144
+ this.config = cfg;
3145
+ this.idCounter = 0;
3146
+ ctx.command("sat.broadcast <text:text>", "推送广播", { authority: 4 }).alias("广播").option("delete", "-d <id:string>", { authority: 4 }).option("list", "-l", { authority: 4 }).option("img", "-i", { authority: 4 }).action(async ({ options }, prompt) => {
3147
+ refreshPuppeteer(this.ctx);
3148
+ if (options.list) {
3149
+ const list = this.broadcastMessages.size > 0 ? await this.getBroadcastList() : null;
3150
+ return list ? `${list}` : "当前没有广播";
3151
+ }
3152
+ if (options.delete) {
3153
+ return await this.deleteBroadcast(options.delete);
3154
+ } else {
3155
+ return await this.createBroadcast(prompt, options.img);
3156
+ }
3157
+ });
3158
+ }
3159
+ async createBroadcast(message, img) {
3160
+ const id = `broadcast-${this.idCounter++}`;
3161
+ const broadcast = new broadcastMessage(this.ctx, this.config, message, img);
3162
+ this.broadcastMessages.set(id, broadcast);
3163
+ logger12.info(`广播已创建 ID: ${id}`);
3164
+ return `广播已创建 ID: ${id}`;
3165
+ }
3166
+ async deleteBroadcast(id) {
3167
+ if (this.broadcastMessages.has(id)) {
3168
+ this.broadcastMessages.delete(id);
3169
+ logger12.info(`广播已删除 ID: ${id}`);
3170
+ return "已删除广播:" + id;
3171
+ } else {
3172
+ logger12.warn(`未找到广播 ID: ${id}`);
3173
+ return "未找到该广播";
3174
+ }
3175
+ }
3176
+ async seedBroadcast(session) {
3177
+ for (const [id, broadcast] of this.broadcastMessages.entries()) {
3178
+ if (broadcast.setTime.getTime() + 1e3 * 60 * this.config.waiting_time < Date.now()) {
3179
+ this.broadcastMessages.delete(id);
3180
+ logger12.info(`广播已过期 ID: ${id}`);
3181
+ continue;
3182
+ }
3183
+ await broadcast.sendMessage(session);
3184
+ }
3185
+ return;
3186
+ }
3187
+ async getBroadcastList() {
3188
+ const idList = Array.from(this.broadcastMessages.keys());
3189
+ const list = [];
3190
+ list.push("当前广播列表:");
3191
+ for (const id of idList) {
3192
+ const broadcast = this.broadcastMessages.get(id);
3193
+ if (broadcast) {
3194
+ const time = broadcast.setTime.toLocaleString("zh-CN", { hour12: false });
3195
+ const ddl = new Date(broadcast.setTime.getTime() + 1e3 * 60 * this.config.waiting_time).toLocaleString("zh-CN", { hour12: false });
3196
+ const message = broadcast.message;
3197
+ const alreadySentChannels = broadcast.getAlreadySentChannels();
3198
+ list.push(`ID: ${id}
3199
+ 消息: ${message}
3200
+ 已发送频道:
3201
+ ${alreadySentChannels}
3202
+ 创建时间: ${time}
3203
+ 过期时间: ${ddl}
3204
+ `);
3205
+ }
3206
+ }
3207
+ const result = list.length > 0 ? list.join("\n") : null;
3208
+ return result ? wrapInHTML3(result) : null;
3209
+ }
3210
+ };
3211
+ var broadcastMessage = class {
3212
+ static {
3213
+ __name(this, "broadcastMessage");
3214
+ }
3215
+ ctx;
3216
+ config;
3217
+ message;
3218
+ alreadySentChannels = /* @__PURE__ */ new Set();
3219
+ setTime;
3220
+ img;
3221
+ constructor(ctx, cfg, message, img) {
3222
+ this.message = message;
3223
+ this.alreadySentChannels = /* @__PURE__ */ new Set();
3224
+ this.ctx = ctx;
3225
+ this.config = cfg;
3226
+ this.img = img;
3227
+ this.setTime = /* @__PURE__ */ new Date();
3228
+ for (const channelId of this.config.Broadcast_block_channel) {
3229
+ this.alreadySentChannels.add(channelId);
3230
+ }
3231
+ }
3232
+ async sendMessage(session) {
3233
+ const channelId = session.channelId;
3234
+ if (this.alreadySentChannels.has(channelId))
3235
+ return;
3236
+ try {
3237
+ if (this.img) {
3238
+ session.send(await wrapInHTML3(this.message));
3239
+ } else {
3240
+ session.send(this.message);
3241
+ }
3242
+ logger12.info(`向群 ${channelId} 广播: ${this.message}`);
3243
+ this.alreadySentChannels.add(channelId);
3244
+ } catch (error) {
3245
+ logger12.error(`广播失败 ${channelId}: ${error}`);
3246
+ }
3247
+ }
3248
+ getAlreadySentChannels() {
3249
+ const alreadySentChannels = Array.from(this.alreadySentChannels).filter((channelId) => !this.config.Broadcast_block_channel.includes(channelId));
3250
+ return alreadySentChannels.length > 0 ? alreadySentChannels.join("\n") : "无";
3251
+ }
3252
+ };
3253
+ async function wrapInHTML3(str) {
3254
+ if (!puppeteer) {
3255
+ logger12.warn("puppeteer未就绪");
3256
+ return str;
3257
+ }
3258
+ return puppeteer.render(`<html><body>${str.replaceAll(/\n/g, "<BR>")}</body>
3259
+ <style>
3260
+ body {
3261
+ padding: 10px;
3262
+ display: inline-block;
3263
+ }
3264
+ </style>
3265
+ </html>`);
3266
+ }
3267
+ __name(wrapInHTML3, "wrapInHTML");
3268
+
3137
3269
  // src/index.tsx
3138
- var logger12 = new import_koishi13.Logger("satori-ai");
3270
+ var logger13 = new import_koishi14.Logger("satori-ai");
3139
3271
  var puppeteer = null;
3140
3272
  function refreshPuppeteer(ctx) {
3141
3273
  if (ctx.puppeteer) {
3142
3274
  puppeteer = ctx.puppeteer;
3143
3275
  } else {
3144
- logger12.warn("puppeteer未就绪");
3276
+ logger13.warn("puppeteer未就绪");
3145
3277
  }
3146
3278
  }
3147
3279
  __name(refreshPuppeteer, "refreshPuppeteer");
@@ -3157,6 +3289,7 @@ var SAT = class extends Sat {
3157
3289
  this.memoryManager = new MemoryManager(ctx, this.getMemoryConfig());
3158
3290
  this.portraitManager = new UserPortraitManager(ctx, config);
3159
3291
  this.moodManager = new MoodManager(ctx, config);
3292
+ this.broadcastManager = new BroadcastManager(ctx, config);
3160
3293
  ensureCensorFileExists(this.config.dataDir);
3161
3294
  ctx.middleware(createMiddleware(ctx, this, this.getMiddlewareConfig()));
3162
3295
  this.registerCommands(ctx);
@@ -3172,6 +3305,7 @@ var SAT = class extends Sat {
3172
3305
  ChannelParallelCount = /* @__PURE__ */ new Map();
3173
3306
  onlineUsers = [];
3174
3307
  moodManager;
3308
+ broadcastManager;
3175
3309
  usersToWarn = /* @__PURE__ */ new Map();
3176
3310
  game;
3177
3311
  getAPIConfig() {
@@ -3327,9 +3461,9 @@ var SAT = class extends Sat {
3327
3461
  const messages = generateAuxiliaryPrompt(prompt, response.content, user, this.getFavorabilityConfig());
3328
3462
  const result = await this.apiClient.auxiliaryChat(messages);
3329
3463
  if (result.error) {
3330
- logger12.error(`辅助判断失败:${result.content}`);
3464
+ logger13.error(`辅助判断失败:${result.content}`);
3331
3465
  } else {
3332
- logger12.info(`辅助判断:${result.content}`);
3466
+ logger13.info(`辅助判断:${result.content}`);
3333
3467
  return handleAuxiliaryResult(this.ctx, session, this.getFavorabilityConfig(), result.content);
3334
3468
  }
3335
3469
  }
@@ -3416,13 +3550,13 @@ var SAT = class extends Sat {
3416
3550
  await inputContentCheck(this.ctx, censored, session.userId, this.getFavorabilityConfig(), session, this.moodManager);
3417
3551
  }
3418
3552
  if (this.config.log_ask_response)
3419
- logger12.info(`用户 ${session.username}:${processedPrompt}`);
3553
+ logger13.info(`用户 ${session.username}:${processedPrompt}`);
3420
3554
  return censored;
3421
3555
  }
3422
3556
  // 生成回复
3423
3557
  async generateResponse(session, prompt) {
3424
3558
  if (this.getChannelParallelCount(session) > this.config.max_parallel_count) {
3425
- logger12.info(`频道 ${session.channelId} 并发数过高(${this.getChannelParallelCount(session)}),${session.username}等待中...`);
3559
+ logger13.info(`频道 ${session.channelId} 并发数过高(${this.getChannelParallelCount(session)}),${session.username}等待中...`);
3426
3560
  }
3427
3561
  while (this.getChannelParallelCount(session) > this.config.max_parallel_count) {
3428
3562
  this.updateChannelParallelCount(session, -1);
@@ -3430,7 +3564,7 @@ var SAT = class extends Sat {
3430
3564
  this.updateChannelParallelCount(session, 1);
3431
3565
  }
3432
3566
  const messages = await this.buildMessages(session, prompt);
3433
- logger12.info(`频道 ${session.channelId} 处理:${session.userId},剩余${this.getChannelParallelCount(session)}并发`);
3567
+ logger13.info(`频道 ${session.channelId} 处理:${session.userId},剩余${this.getChannelParallelCount(session)}并发`);
3434
3568
  const user = await getUser(this.ctx, session.userId);
3435
3569
  let response = await this.getChatResponse(user, messages);
3436
3570
  if (response.error)
@@ -3444,9 +3578,9 @@ var SAT = class extends Sat {
3444
3578
  let response = await this.apiClient.chat(user, messages);
3445
3579
  if (this.config.log_ask_response) {
3446
3580
  if (this.config.enable_favorability && this.config.enable_mood)
3447
- logger12.info(`Satori AI:(心情值:${this.moodManager.getMoodValue(user.userid)})${response.content}`);
3581
+ logger13.info(`Satori AI:(心情值:${this.moodManager.getMoodValue(user.userid)})${response.content}`);
3448
3582
  else
3449
- logger12.info(`Satori AI:${response.content}`);
3583
+ logger13.info(`Satori AI:${response.content}`);
3450
3584
  }
3451
3585
  if (this.config.reasoner_filter && !response.error)
3452
3586
  response = filterResponse(response.content, this.config.reasoner_filter_word.split("-"));
@@ -3470,7 +3604,7 @@ var SAT = class extends Sat {
3470
3604
  messages.push({ role: "user", content: prompt });
3471
3605
  let payload = messages.map((msg) => msg.role + ":" + msg.content).join("\n");
3472
3606
  if (this.config.log_system_prompt)
3473
- logger12.info(`系统提示:
3607
+ logger13.info(`系统提示:
3474
3608
  ${payload}`);
3475
3609
  return messages;
3476
3610
  }
@@ -3575,7 +3709,7 @@ ${useNoReasoner ? promptForNoReasoner : promptForReasoner}
3575
3709
  response = `@${session.username} ` + response;
3576
3710
  }
3577
3711
  if (this.config.sentences_divide && response.length > 10) {
3578
- const sentences = splitSentences(response, this.config.min_sentences_length, this.config.max_sentences_length).map((text) => import_koishi13.h.text(text));
3712
+ const sentences = splitSentences(response, this.config.min_sentences_length, this.config.max_sentences_length).map((text) => import_koishi14.h.text(text));
3579
3713
  for (const sentence of sentences) {
3580
3714
  await session.send(sentence);
3581
3715
  await new Promise((resolve3) => setTimeout(resolve3, this.config.time_interval));
@@ -3588,7 +3722,7 @@ ${useNoReasoner ? promptForNoReasoner : promptForReasoner}
3588
3722
  if (!this.config.enable_warning)
3589
3723
  return;
3590
3724
  if (auxiliaryResult.includes("好感↓")) {
3591
- logger12.info(`在群${session.channelId}中,${session.username}骚扰我!`);
3725
+ logger13.info(`在群${session.channelId}中,${session.username}骚扰我!`);
3592
3726
  this.usersToWarn.set(session.channelId, session.username);
3593
3727
  }
3594
3728
  }
package/lib/types.d.ts CHANGED
@@ -240,6 +240,8 @@ export declare namespace Sat {
240
240
  warning_admin_id: string;
241
241
  maxRetryTimes: number;
242
242
  retry_delay_time: number;
243
+ Broadcast_block_channel: string[];
244
+ waiting_time: number;
243
245
  enable_game: boolean;
244
246
  game_block_channel: string[];
245
247
  enable_gobang: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-satori-ai",
3
3
  "description": "基于 Satori 适配器的智能对话插件,具备用户画像、长期记忆、常识管理和好感度系统",
4
- "version": "1.3.4",
4
+ "version": "1.3.5",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "types": "lib/index.d.ts",