koishi-plugin-game-mini 0.2.3 → 0.2.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.
package/lib/index.js CHANGED
@@ -14,193 +14,72 @@ exports.name = 'game-mini';
14
14
  exports.using = ['i18n'];
15
15
  exports.inject = ['console'];
16
16
  exports.Config = koishi_1.Schema.object({
17
- enableNumberGuess: koishi_1.Schema.boolean().default(true)
18
- .description('启用猜数字游戏')
19
- .i18n({ 'zh-CN': '启用猜数字游戏' }),
20
- enableWzHero: koishi_1.Schema.boolean().default(true)
21
- .description('启用王者英雄猜谜游戏')
22
- .i18n({ 'zh-CN': '启用王者英雄猜谜游戏' }),
23
- enableChengyuImage: koishi_1.Schema.boolean().default(true)
24
- .description('启用看图猜成语游戏')
25
- .i18n({ 'zh-CN': '启用看图猜成语游戏' }),
26
- enableChengyuJielong: koishi_1.Schema.boolean().default(true)
27
- .description('启用成语接龙游戏')
28
- .i18n({ 'zh-CN': '启用成语接龙游戏' }),
29
- enableDice: koishi_1.Schema.boolean().default(true)
30
- .description('启用掷骰子比大小游戏')
31
- .i18n({ 'zh-CN': '启用掷骰子比大小游戏' }),
32
- enableRps: koishi_1.Schema.boolean().default(true)
33
- .description('启用石头剪刀布游戏')
34
- .i18n({ 'zh-CN': '启用石头剪刀布游戏' }),
35
- enableCalc24: koishi_1.Schema.boolean().default(true)
36
- .description('启用算24点游戏')
37
- .i18n({ 'zh-CN': '启用算24点游戏' }),
38
- enablePasswordLock: koishi_1.Schema.boolean().default(true)
39
- .description('启用密码锁破解游戏')
40
- .i18n({ 'zh-CN': '启用密码锁破解游戏' }),
41
- enablePrivateGame: koishi_1.Schema.boolean().default(true)
42
- .description('允许私聊玩游戏')
43
- .i18n({ 'zh-CN': '允许私聊玩游戏' }),
44
- autoPlayDelay: koishi_1.Schema.number().min(0).default(10)
45
- .description('机器人自动操作延迟(秒)')
46
- .i18n({ 'zh-CN': '机器人自动操作延迟(秒)' }),
47
- autoPlayMaxCount: koishi_1.Schema.number().min(1).default(5)
48
- .description('机器人最大自动操作次数')
49
- .i18n({ 'zh-CN': '机器人最大自动操作次数' }),
50
- autoStopInactiveTime: koishi_1.Schema.number().min(0).default(30)
51
- .description('游戏无操作自动停止时间(秒)')
52
- .i18n({ 'zh-CN': '游戏无操作自动停止时间(秒)' }),
17
+ enableNumberGuess: koishi_1.Schema.boolean().default(true).description('启用猜数字游戏'),
18
+ enableWzHero: koishi_1.Schema.boolean().default(true).description('启用王者英雄猜谜游戏'),
19
+ enableChengyuImage: koishi_1.Schema.boolean().default(true).description('启用看图猜成语游戏'),
20
+ enableChengyuJielong: koishi_1.Schema.boolean().default(true).description('启用成语接龙游戏'),
21
+ enableCalc24: koishi_1.Schema.boolean().default(true).description('启用算24点游戏'),
22
+ enablePasswordLock: koishi_1.Schema.boolean().default(true).description('启用密码锁破解游戏'),
23
+ enablePrivateGame: koishi_1.Schema.boolean().default(true).description('允许私聊玩游戏'),
53
24
  guessNumber: koishi_1.Schema.object({
54
- min: koishi_1.Schema.number().min(0).default(0)
55
- .description('猜数字最小值')
56
- .i18n({ 'zh-CN': '猜数字最小值' }),
57
- max: koishi_1.Schema.number().min(1).default(100)
58
- .description('猜数字最大值')
59
- .i18n({ 'zh-CN': '猜数字最大值' }),
60
- botParticipateInGroup: koishi_1.Schema.boolean().default(true)
61
- .description('群聊中机器人参与猜数字')
62
- .i18n({ 'zh-CN': '群聊中机器人参与猜数字' }),
63
- totalRounds: koishi_1.Schema.number().min(1).default(10)
64
- .description('猜数字总回合数')
65
- .i18n({ 'zh-CN': '猜数字总回合数' }),
66
- showRank: koishi_1.Schema.boolean().default(true)
67
- .description('猜数字显示排行榜')
68
- .i18n({ 'zh-CN': '猜数字显示排行榜' }),
69
- }).description('猜数字游戏配置')
70
- .i18n({ 'zh-CN': '猜数字游戏配置' }),
25
+ min: koishi_1.Schema.number().min(0).default(0).description('猜数字最小值'),
26
+ max: koishi_1.Schema.number().min(1).default(100).description('猜数字最大值'),
27
+ botParticipateInGroup: koishi_1.Schema.boolean().default(true).description('群聊中机器人参与猜数字'),
28
+ totalRounds: koishi_1.Schema.number().min(1).default(10).description('猜数字总回合数'),
29
+ showRank: koishi_1.Schema.boolean().default(true).description('猜数字显示排行榜'),
30
+ autoPlayDelay: koishi_1.Schema.number().min(0).default(10).description('机器人自动操作延迟(秒)'),
31
+ autoPlayMaxCount: koishi_1.Schema.number().min(1).default(5).description('机器人最大自动操作次数'),
32
+ autoStopInactiveTime: koishi_1.Schema.number().min(0).default(30).description('游戏无操作自动停止时间(秒)'),
33
+ }).description('猜数字游戏配置'),
71
34
  wzHero: koishi_1.Schema.object({
72
- totalRounds: koishi_1.Schema.number().min(1).default(10)
73
- .description('王者英雄猜谜总回合数')
74
- .i18n({ 'zh-CN': '王者英雄猜谜总回合数' }),
75
- showRank: koishi_1.Schema.boolean().default(true)
76
- .description('王者英雄猜谜显示排行榜')
77
- .i18n({ 'zh-CN': '王者英雄猜谜显示排行榜' }),
78
- }).description('王者英雄猜谜游戏配置')
79
- .i18n({ 'zh-CN': '王者英雄猜谜游戏配置' }),
35
+ totalRounds: koishi_1.Schema.number().min(1).default(10).description('王者英雄猜谜总回合数'),
36
+ showRank: koishi_1.Schema.boolean().default(true).description('王者英雄猜谜显示排行榜'),
37
+ defaultDifficulty: koishi_1.Schema.union(['简单', '中等', '困难']).default('简单').description('默认难度'),
38
+ autoStopInactiveTime: koishi_1.Schema.number().min(0).default(30).description('游戏无操作自动停止时间(秒)'),
39
+ }).description('王者英雄猜谜游戏配置'),
80
40
  chengyuImage: koishi_1.Schema.object({
81
- totalRounds: koishi_1.Schema.number().min(1).default(10)
82
- .description('看图猜成语总回合数')
83
- .i18n({ 'zh-CN': '看图猜成语总回合数' }),
84
- showRank: koishi_1.Schema.boolean().default(true)
85
- .description('看图猜成语显示排行榜')
86
- .i18n({ 'zh-CN': '看图猜成语显示排行榜' }),
87
- }).description('看图猜成语游戏配置')
88
- .i18n({ 'zh-CN': '看图猜成语游戏配置' }),
41
+ totalRounds: koishi_1.Schema.number().min(1).default(10).description('看图猜成语总回合数'),
42
+ showRank: koishi_1.Schema.boolean().default(true).description('看图猜成语显示排行榜'),
43
+ defaultHintLevel: koishi_1.Schema.union([1, 2, 3, 4, 5]).default(1).description('默认提示级别(1-5)'),
44
+ autoStopInactiveTime: koishi_1.Schema.number().min(0).default(30).description('游戏无操作自动停止时间(秒)'),
45
+ }).description('看图猜成语游戏配置'),
89
46
  chengyuJielong: koishi_1.Schema.object({
90
- botParticipateInGroup: koishi_1.Schema.boolean().default(true)
91
- .description('群聊中机器人参与成语接龙')
92
- .i18n({ 'zh-CN': '群聊中机器人参与成语接龙' }),
93
- totalRounds: koishi_1.Schema.number().min(1).default(10)
94
- .description('成语接龙总回合数')
95
- .i18n({ 'zh-CN': '成语接龙总回合数' }),
96
- showRank: koishi_1.Schema.boolean().default(true)
97
- .description('成语接龙显示排行榜')
98
- .i18n({ 'zh-CN': '成语接龙显示排行榜' }),
99
- }).description('成语接龙游戏配置')
100
- .i18n({ 'zh-CN': '成语接龙游戏配置' }),
101
- dice: koishi_1.Schema.object({
102
- totalRounds: koishi_1.Schema.number().min(1).default(5)
103
- .description('掷骰子总回合数')
104
- .i18n({ 'zh-CN': '掷骰子总回合数' }),
105
- showRank: koishi_1.Schema.boolean().default(true)
106
- .description('掷骰子显示排行榜')
107
- .i18n({ 'zh-CN': '掷骰子显示排行榜' }),
108
- botParticipate: koishi_1.Schema.boolean().default(true)
109
- .description('机器人参与掷骰子')
110
- .i18n({ 'zh-CN': '机器人参与掷骰子' }),
111
- }).description('掷骰子比大小游戏配置')
112
- .i18n({ 'zh-CN': '掷骰子比大小游戏配置' }),
113
- rps: koishi_1.Schema.object({
114
- totalRounds: koishi_1.Schema.number().min(1).default(5)
115
- .description('石头剪刀布总回合数')
116
- .i18n({ 'zh-CN': '石头剪刀布总回合数' }),
117
- showRank: koishi_1.Schema.boolean().default(true)
118
- .description('石头剪刀布显示排行榜')
119
- .i18n({ 'zh-CN': '石头剪刀布显示排行榜' }),
120
- botParticipate: koishi_1.Schema.boolean().default(true)
121
- .description('机器人参与石头剪刀布')
122
- .i18n({ 'zh-CN': '机器人参与石头剪刀布' }),
123
- }).description('石头剪刀布游戏配置')
124
- .i18n({ 'zh-CN': '石头剪刀布游戏配置' }),
47
+ botParticipateInGroup: koishi_1.Schema.boolean().default(true).description('群聊中机器人参与成语接龙'),
48
+ totalRounds: koishi_1.Schema.number().min(1).default(10).description('成语接龙总回合数'),
49
+ showRank: koishi_1.Schema.boolean().default(true).description('成语接龙显示排行榜'),
50
+ autoPlayDelay: koishi_1.Schema.number().min(0).default(10).description('机器人自动操作延迟(秒)'),
51
+ autoPlayMaxCount: koishi_1.Schema.number().min(1).default(5).description('机器人最大自动操作次数'),
52
+ autoStopInactiveTime: koishi_1.Schema.number().min(0).default(30).description('游戏无操作自动停止时间(秒)'),
53
+ }).description('成语接龙游戏配置'),
125
54
  calc24: koishi_1.Schema.object({
126
- totalRounds: koishi_1.Schema.number().min(1).default(5)
127
- .description('算24点总回合数')
128
- .i18n({ 'zh-CN': '算24点总回合数' }),
129
- showRank: koishi_1.Schema.boolean().default(true)
130
- .description('算24点显示排行榜')
131
- .i18n({ 'zh-CN': '算24点显示排行榜' }),
132
- numberRange: koishi_1.Schema.array(koishi_1.Schema.number()).default([1, 13])
133
- .description('算24点数字范围 [最小值, 最大值]')
134
- .i18n({ 'zh-CN': '算24点数字范围 [最小值, 最大值]' }),
135
- }).description('算24点游戏配置')
136
- .i18n({ 'zh-CN': '算24点游戏配置' }),
55
+ totalRounds: koishi_1.Schema.number().min(1).default(5).description('算24点总回合数'),
56
+ showRank: koishi_1.Schema.boolean().default(true).description('算24点显示排行榜'),
57
+ defaultDifficulty: koishi_1.Schema.union(['简单', '中等', '困难']).default('中等').description('默认难度'),
58
+ difficultyLevels: koishi_1.Schema.object({
59
+ easy: koishi_1.Schema.object({
60
+ min: koishi_1.Schema.number().default(1).description('最小值'),
61
+ max: koishi_1.Schema.number().default(8).description('最大值'),
62
+ }).description('简单难度'),
63
+ medium: koishi_1.Schema.object({
64
+ min: koishi_1.Schema.number().default(1).description('最小值'),
65
+ max: koishi_1.Schema.number().default(10).description('最大值'),
66
+ }).description('中等难度'),
67
+ hard: koishi_1.Schema.object({
68
+ min: koishi_1.Schema.number().default(1).description('最小值'),
69
+ max: koishi_1.Schema.number().default(13).description('最大值'),
70
+ }).description('困难难度'),
71
+ }).description('难度等级配置'),
72
+ autoStopInactiveTime: koishi_1.Schema.number().min(0).default(30).description('游戏无操作自动停止时间(秒)'),
73
+ }).description('算24点游戏配置'),
137
74
  passwordLock: koishi_1.Schema.object({
138
- maxGuessTimes: koishi_1.Schema.number().min(1).default(10)
139
- .description('密码锁最大猜测次数')
140
- .i18n({ 'zh-CN': '密码锁最大猜测次数' }),
141
- showHint: koishi_1.Schema.boolean().default(true)
142
- .description('密码锁显示提示')
143
- .i18n({ 'zh-CN': '密码锁显示提示' }),
144
- showRank: koishi_1.Schema.boolean().default(true)
145
- .description('密码锁显示排行榜')
146
- .i18n({ 'zh-CN': '密码锁显示排行榜' }),
147
- }).description('密码锁破解游戏配置')
148
- .i18n({ 'zh-CN': '密码锁破解游戏配置' }),
75
+ maxGuessTimes: koishi_1.Schema.number().min(1).default(10).description('密码锁最大猜测次数'),
76
+ showHint: koishi_1.Schema.boolean().default(true).description('密码锁显示提示'),
77
+ showRank: koishi_1.Schema.boolean().default(true).description('密码锁显示排行榜'),
78
+ autoStopInactiveTime: koishi_1.Schema.number().min(0).default(30).description('游戏无操作自动停止时间(秒)'),
79
+ }).description('密码锁破解游戏配置'),
149
80
  apiConfig: koishi_1.Schema.object({
150
- timeout: koishi_1.Schema.number().default(5000)
151
- .description('API请求超时时间(毫秒)')
152
- .i18n({ 'zh-CN': 'API请求超时时间(毫秒)' }),
153
- }).description('API接口配置')
154
- .i18n({ 'zh-CN': 'API接口配置' }),
155
- }).i18n({
156
- 'zh-CN': {
157
- 'enableNumberGuess': '启用猜数字游戏',
158
- 'enableWzHero': '启用王者英雄猜谜游戏',
159
- 'enableChengyuImage': '启用看图猜成语游戏',
160
- 'enableChengyuJielong': '启用成语接龙游戏',
161
- 'enableDice': '启用掷骰子比大小游戏',
162
- 'enableRps': '启用石头剪刀布游戏',
163
- 'enableCalc24': '启用算24点游戏',
164
- 'enablePasswordLock': '启用密码锁破解游戏',
165
- 'enablePrivateGame': '允许私聊玩游戏',
166
- 'autoPlayDelay': '机器人自动操作延迟(秒)',
167
- 'autoPlayMaxCount': '机器人最大自动操作次数',
168
- 'autoStopInactiveTime': '游戏无操作自动停止时间(秒)',
169
- 'guessNumber': '猜数字游戏配置',
170
- 'guessNumber.min': '猜数字最小值',
171
- 'guessNumber.max': '猜数字最大值',
172
- 'guessNumber.botParticipateInGroup': '群聊中机器人参与猜数字',
173
- 'guessNumber.totalRounds': '猜数字总回合数',
174
- 'guessNumber.showRank': '猜数字显示排行榜',
175
- 'wzHero': '王者英雄猜谜配置',
176
- 'wzHero.totalRounds': '王者英雄猜谜总回合数',
177
- 'wzHero.showRank': '王者英雄猜谜显示排行榜',
178
- 'chengyuImage': '看图猜成语配置',
179
- 'chengyuImage.totalRounds': '看图猜成语总回合数',
180
- 'chengyuImage.showRank': '看图猜成语显示排行榜',
181
- 'chengyuJielong': '成语接龙配置',
182
- 'chengyuJielong.botParticipateInGroup': '群聊中机器人参与成语接龙',
183
- 'chengyuJielong.totalRounds': '成语接龙总回合数',
184
- 'chengyuJielong.showRank': '成语接龙显示排行榜',
185
- 'dice': '掷骰子比大小配置',
186
- 'dice.totalRounds': '掷骰子总回合数',
187
- 'dice.showRank': '掷骰子显示排行榜',
188
- 'dice.botParticipate': '机器人参与掷骰子',
189
- 'rps': '石头剪刀布配置',
190
- 'rps.totalRounds': '石头剪刀布总回合数',
191
- 'rps.showRank': '石头剪刀布显示排行榜',
192
- 'rps.botParticipate': '机器人参与石头剪刀布',
193
- 'calc24': '算24点配置',
194
- 'calc24.totalRounds': '算24点总回合数',
195
- 'calc24.showRank': '算24点显示排行榜',
196
- 'calc24.numberRange': '算24点数字范围',
197
- 'passwordLock': '密码锁破解配置',
198
- 'passwordLock.maxGuessTimes': '密码锁最大猜测次数',
199
- 'passwordLock.showHint': '密码锁显示提示',
200
- 'passwordLock.showRank': '密码锁显示排行榜',
201
- 'apiConfig': 'API接口配置',
202
- 'apiConfig.timeout': '请求超时时间(毫秒)'
203
- }
81
+ timeout: koishi_1.Schema.number().default(5000).description('API请求超时时间(毫秒)'),
82
+ }).description('API接口配置'),
204
83
  });
205
84
  const logger = new koishi_1.Logger('game-mini');
206
85
  const gameStates = new Map();
@@ -229,10 +108,6 @@ const checkGameRunning = (s, t) => {
229
108
  return true;
230
109
  if (t !== 'chengyuJielong' && s.chengyuJielong.started)
231
110
  return true;
232
- if (t !== 'dice' && s.dice.started)
233
- return true;
234
- if (t !== 'rps' && s.rps.started)
235
- return true;
236
111
  if (t !== 'calc24' && s.calc24.started)
237
112
  return true;
238
113
  if (t !== 'passwordLock' && s.passwordLock.started)
@@ -242,18 +117,16 @@ const checkGameRunning = (s, t) => {
242
117
  const clearGameTimer = (state) => {
243
118
  if (state.stopTimer)
244
119
  clearTimeout(state.stopTimer);
120
+ if (state.autoPlayTimer)
121
+ clearTimeout(state.autoPlayTimer);
245
122
  };
246
123
  const clearAllTimers = (st) => {
247
124
  clearGameTimer(st.guessNumber);
248
125
  clearGameTimer(st.wzHero);
249
126
  clearGameTimer(st.chengyuImage);
250
127
  clearGameTimer(st.chengyuJielong);
251
- clearGameTimer(st.dice);
252
- clearGameTimer(st.rps);
253
128
  clearGameTimer(st.calc24);
254
129
  clearGameTimer(st.passwordLock);
255
- if (st.chengyuJielong.autoPlayTimer)
256
- clearTimeout(st.chengyuJielong.autoPlayTimer);
257
130
  };
258
131
  const initState = (key, c) => {
259
132
  const s = {
@@ -274,7 +147,7 @@ const initState = (key, c) => {
274
147
  currentRound: 0,
275
148
  players: {},
276
149
  participants: [],
277
- difficulty: '',
150
+ difficulty: c.wzHero.defaultDifficulty,
278
151
  botAnswered: false,
279
152
  lastHint: '',
280
153
  currentHeroId: '',
@@ -301,27 +174,7 @@ const initState = (key, c) => {
301
174
  botTurn: true,
302
175
  autoPlayCount: 0,
303
176
  hasTriggeredAutoPlay: false,
304
- lastActiveTime: Date.now(),
305
- autoPlayTimer: undefined
306
- },
307
- dice: {
308
- started: false,
309
- totalRounds: c.dice.totalRounds,
310
- currentRound: 0,
311
- players: {},
312
- participants: [],
313
- playerDice: 0,
314
- botDice: 0
315
- },
316
- rps: {
317
- started: false,
318
- totalRounds: c.rps.totalRounds,
319
- currentRound: 0,
320
- players: {},
321
- participants: [],
322
- playerChoice: '',
323
- botChoice: '',
324
- choices: ['石头', '剪刀', '布']
177
+ lastActiveTime: Date.now()
325
178
  },
326
179
  calc24: {
327
180
  started: false,
@@ -329,8 +182,11 @@ const initState = (key, c) => {
329
182
  currentRound: 0,
330
183
  players: {},
331
184
  participants: [],
185
+ difficulty: c.calc24.defaultDifficulty,
332
186
  numbers: [],
333
- playerAnswer: ''
187
+ playerAnswer: '',
188
+ solved: false,
189
+ availableNumbers: []
334
190
  },
335
191
  passwordLock: {
336
192
  started: false,
@@ -342,7 +198,8 @@ const initState = (key, c) => {
342
198
  playerGuess: '',
343
199
  guessTimes: 0,
344
200
  maxGuessTimes: c.passwordLock.maxGuessTimes,
345
- hints: []
201
+ hints: [],
202
+ solved: false
346
203
  }
347
204
  };
348
205
  gameStates.set(key, s);
@@ -378,9 +235,22 @@ const addScoreToOthers = (players, excludePlayerKey) => {
378
235
  }
379
236
  });
380
237
  };
381
- const setupAutoStop = (session, state, cfg, endMsg, showRank) => {
238
+ const setupAutoStop = (session, state, cfg, gameType, endMsg, showRank) => {
382
239
  clearGameTimer(state);
383
- if (cfg.autoStopInactiveTime <= 0)
240
+ let inactiveTime = 30;
241
+ if (gameType === 'guessNumber')
242
+ inactiveTime = cfg.guessNumber.autoStopInactiveTime;
243
+ else if (gameType === 'wzHero')
244
+ inactiveTime = cfg.wzHero.autoStopInactiveTime;
245
+ else if (gameType === 'chengyuImage')
246
+ inactiveTime = cfg.chengyuImage.autoStopInactiveTime;
247
+ else if (gameType === 'chengyuJielong')
248
+ inactiveTime = cfg.chengyuJielong.autoStopInactiveTime;
249
+ else if (gameType === 'calc24')
250
+ inactiveTime = cfg.calc24.autoStopInactiveTime;
251
+ else if (gameType === 'passwordLock')
252
+ inactiveTime = cfg.passwordLock.autoStopInactiveTime;
253
+ if (inactiveTime <= 0)
384
254
  return;
385
255
  state.stopTimer = setTimeout(() => {
386
256
  clearGameData(state);
@@ -388,7 +258,7 @@ const setupAutoStop = (session, state, cfg, endMsg, showRank) => {
388
258
  if (showRank && session.channelId) {
389
259
  session.send(generateRankText(state.players));
390
260
  }
391
- }, cfg.autoStopInactiveTime * 1000);
261
+ }, inactiveTime * 1000);
392
262
  };
393
263
  const calculate24 = (numbers) => {
394
264
  if (numbers.length === 1)
@@ -420,6 +290,21 @@ const calculate24 = (numbers) => {
420
290
  }
421
291
  return false;
422
292
  };
293
+ const generateSolvable24Numbers = (min, max) => {
294
+ const maxAttempts = 1000;
295
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
296
+ const numbers = [
297
+ koishi_1.Random.int(min, max + 1),
298
+ koishi_1.Random.int(min, max + 1),
299
+ koishi_1.Random.int(min, max + 1),
300
+ koishi_1.Random.int(min, max + 1)
301
+ ];
302
+ if (calculate24([...numbers])) {
303
+ return numbers;
304
+ }
305
+ }
306
+ return [6, 4, 3, 1];
307
+ };
423
308
  const generatePasswordHint = (password, guess) => {
424
309
  let correctPos = 0;
425
310
  let correctNum = 0;
@@ -447,6 +332,21 @@ const generatePasswordHint = (password, guess) => {
447
332
  }
448
333
  return `提示:${correctPos}个数字位置正确,${correctNum}个数字正确但位置错误`;
449
334
  };
335
+ const evaluateExpression = (expr) => {
336
+ try {
337
+ const cleanExpr = expr.replace(/[^\d\+\-\*\/\(\)\[\]\{\}\s]/g, '');
338
+ const normalizedExpr = cleanExpr.replace(/[\[\{]/g, '(').replace(/[\]\}]/g, ')');
339
+ const func = new Function('return ' + normalizedExpr);
340
+ const result = func();
341
+ if (typeof result === 'number' && isFinite(result)) {
342
+ return result;
343
+ }
344
+ return null;
345
+ }
346
+ catch {
347
+ return null;
348
+ }
349
+ };
450
350
  function apply(ctx, cfg) {
451
351
  const d = {
452
352
  guessNumber: {
@@ -465,23 +365,23 @@ function apply(ctx, cfg) {
465
365
  autoStop: "游戏因长时间无人操作,已自动结束"
466
366
  },
467
367
  wzHero: {
468
- start: "王者英雄猜谜开始!本次共 {0} 回合~",
469
- startUsage: "用法错误!正确用法:王者英雄 开始 [难度] | 王者英雄 [答案] | 王者英雄 提示 | 王者英雄 结束",
470
- stop: "王者英雄猜谜比赛已停止",
471
- notStarted: "王者英雄猜谜比赛尚未开始,请输入 王者英雄 开始 [难度] 开始游戏",
368
+ start: "猜王者英雄开始!本次共 {0} 回合~当前难度:{1}",
369
+ startUsage: "用法错误!正确用法:猜王者英雄 开始 | 猜王者英雄 [答案] | 猜王者英雄 提示 | 猜王者英雄 结束",
370
+ stop: "猜王者英雄比赛已停止",
371
+ notStarted: "猜王者英雄比赛尚未开始,请输入 猜王者英雄 开始 开始游戏",
472
372
  hint: "提示",
473
373
  apiError: "API请求失败,请稍后再试",
474
374
  correct: "答对啦!你获得1分~",
475
375
  wrong: "答错啦~正确答案是:{0},你不得分",
476
376
  roundEnd: "第 {0} 回合结束!剩余回合:{1}",
477
- gameEnd: "🎉 王者英雄猜谜比赛结束!🎉",
377
+ gameEnd: "🎉 猜王者英雄比赛结束!🎉",
478
378
  rankTitle: "🏆 排行榜 🏆",
479
379
  rankEmpty: "暂无参与记录~",
480
- disabled: "王者英雄猜谜功能已关闭,请联系管理员开启",
380
+ disabled: "猜王者英雄功能已关闭,请联系管理员开启",
481
381
  autoStop: "游戏因长时间无人操作,已自动结束"
482
382
  },
483
383
  chengyuImage: {
484
- start: "看图猜成语比赛开始!本次共 {0} 回合~",
384
+ start: "看图猜成语比赛开始!本次共 {0} 回合~当前提示级别:{1}",
485
385
  stop: "看图猜成语比赛已停止",
486
386
  submitUsage: "请直接输入 看图猜成语 [答案],或输入 看图猜成语 提示 获取线索",
487
387
  notStarted: "看图猜成语比赛尚未开始,请输入 看图猜成语 开始 开始游戏",
@@ -518,45 +418,15 @@ function apply(ctx, cfg) {
518
418
  disabled: "成语接龙功能已关闭,请联系管理员开启",
519
419
  autoStop: "游戏因长时间无人操作,已自动结束"
520
420
  },
521
- dice: {
522
- start: "掷骰子比大小游戏开始!本次共 {0} 回合~",
523
- stop: "掷骰子比大小游戏已停止",
524
- notStarted: "掷骰子比大小游戏尚未开始,请输入 掷骰子 开始 开始游戏",
525
- roll: "🎲 你掷出了 {0} 点!机器人掷出了 {1} 点!",
526
- win: "你赢了这一回合!获得1分~",
527
- lose: "机器人赢了这一回合!",
528
- draw: "平局!双方都不得分~",
529
- roundEnd: "第 {0} 回合结束!剩余回合:{1}",
530
- gameEnd: "🎉 掷骰子比大小游戏结束!🎉",
531
- rankTitle: "🏆 排行榜 🏆",
532
- rankEmpty: "暂无参与记录~",
533
- disabled: "掷骰子比大小功能已关闭,请联系管理员开启",
534
- autoStop: "游戏因长时间无人操作,已自动结束"
535
- },
536
- rps: {
537
- start: "石头剪刀布游戏开始!本次共 {0} 回合~",
538
- stop: "石头剪刀布游戏已停止",
539
- notStarted: "石头剪刀布游戏尚未开始,请输入 石头剪刀布 开始 开始游戏",
540
- choice: "你选择了 {0},机器人选择了 {1}!",
541
- win: "你赢了这一回合!获得1分~",
542
- lose: "机器人赢了这一回合!",
543
- draw: "平局!双方都不得分~",
544
- invalidChoice: "无效的选择!请输入 石头、剪刀 或 布",
545
- roundEnd: "第 {0} 回合结束!剩余回合:{1}",
546
- gameEnd: "🎉 石头剪刀布游戏结束!🎉",
547
- rankTitle: "🏆 排行榜 🏆",
548
- rankEmpty: "暂无参与记录~",
549
- disabled: "石头剪刀布功能已关闭,请联系管理员开启",
550
- autoStop: "游戏因长时间无人操作,已自动结束"
551
- },
552
421
  calc24: {
553
- start: "算24点游戏开始!本次共 {0} 回合~",
422
+ start: "算24点游戏开始!本次共 {0} 回合~当前难度:{1}",
554
423
  stop: "算24点游戏已停止",
555
424
  notStarted: "算24点游戏尚未开始,请输入 算24点 开始 开始游戏",
556
- generate: "📝 第 {0} 题:用 {1} 通过加减乘除算出24!",
425
+ generate: "📝 第 {0} 题({1}):用 {2} 通过加减乘除和括号算出24!",
557
426
  correct: "答对啦!你获得1分~",
558
- wrong: "答错啦~这组数可以算出24哦!",
559
- impossible: "这组数无法算出24!本轮作废~",
427
+ wrong: "答错啦~",
428
+ impossible: "这组数无法算出24!本题作废,换一组数字~",
429
+ solved: "这组数已经被答对啦,换一组数字~",
560
430
  roundEnd: "第 {0} 回合结束!剩余回合:{1}",
561
431
  gameEnd: "🎉 算24点游戏结束!🎉",
562
432
  rankTitle: "🏆 排行榜 🏆",
@@ -565,18 +435,19 @@ function apply(ctx, cfg) {
565
435
  autoStop: "游戏因长时间无人操作,已自动结束"
566
436
  },
567
437
  passwordLock: {
568
- start: "密码锁破解游戏开始!密码为4位数字,你有 {0} 次猜测机会~",
569
- stop: "密码锁破解游戏已停止",
570
- notStarted: "密码锁破解游戏尚未开始,请输入 密码锁 开始 开始游戏",
438
+ start: "猜密码游戏开始!密码为4位数字,你有 {0} 次猜测机会~",
439
+ stop: "猜密码游戏已停止",
440
+ notStarted: "猜密码游戏尚未开始,请输入 猜密码 开始 开始游戏",
571
441
  guess: "你猜测的密码是:{0},这是第 {1} 次猜测",
572
442
  correct: "🎉 恭喜!你猜对了密码 {0}!总共猜测了 {1} 次,获得10分~",
573
443
  wrong: "密码错误!{0}",
444
+ solved: "密码已经被猜出来啦,游戏结束~",
574
445
  noChance: "❌ 没有猜测机会了!正确密码是:{0}~",
575
446
  invalidPassword: "无效的密码!请输入4位数字",
576
- gameEnd: "🎉 密码锁破解游戏结束!🎉",
447
+ gameEnd: "🎉 猜密码游戏结束!🎉",
577
448
  rankTitle: "🏆 排行榜 🏆",
578
449
  rankEmpty: "暂无参与记录~",
579
- disabled: "密码锁破解功能已关闭,请联系管理员开启",
450
+ disabled: "猜密码功能已关闭,请联系管理员开启",
580
451
  autoStop: "游戏因长时间无人操作,已自动结束"
581
452
  },
582
453
  common: {
@@ -609,7 +480,7 @@ function apply(ctx, cfg) {
609
480
  return;
610
481
  if (st.chengyuJielong.hasTriggeredAutoPlay)
611
482
  return;
612
- const delay = cfg.autoPlayDelay * 1000;
483
+ const delay = cfg.chengyuJielong.autoPlayDelay * 1000;
613
484
  st.chengyuJielong.autoPlayTimer = setTimeout(() => {
614
485
  doAutoPlay(session, key, st);
615
486
  }, delay);
@@ -619,11 +490,11 @@ function apply(ctx, cfg) {
619
490
  return;
620
491
  if (st.chengyuJielong.hasTriggeredAutoPlay)
621
492
  return;
622
- if (st.chengyuJielong.autoPlayCount >= cfg.autoPlayMaxCount) {
623
- session.send(d.chengyuJielong.autoPlayTooMany.replace('{0}', String(cfg.autoPlayMaxCount)));
493
+ if (st.chengyuJielong.autoPlayCount >= cfg.chengyuJielong.autoPlayMaxCount) {
494
+ session.send(d.chengyuJielong.autoPlayTooMany.replace('{0}', String(cfg.chengyuJielong.autoPlayMaxCount)));
624
495
  st.chengyuJielong.hasTriggeredAutoPlay = true;
625
496
  gameStates.set(key, st);
626
- setupAutoStop(session, st.chengyuJielong, cfg, d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
497
+ setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
627
498
  return;
628
499
  }
629
500
  st.chengyuJielong.hasTriggeredAutoPlay = true;
@@ -674,7 +545,7 @@ function apply(ctx, cfg) {
674
545
  await session.send(d.chengyuJielong.apiError);
675
546
  }
676
547
  gameStates.set(key, st);
677
- setupAutoStop(session, st.chengyuJielong, cfg, d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
548
+ setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
678
549
  };
679
550
  ctx.middleware(async (session, next) => {
680
551
  if (!session.content)
@@ -693,7 +564,7 @@ function apply(ctx, cfg) {
693
564
  st.chengyuJielong.participants.push(playerKey);
694
565
  }
695
566
  if (!isFourCharIdiom(content)) {
696
- setupAutoStop(session, st.chengyuJielong, cfg, d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
567
+ setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
697
568
  scheduleAutoPlay(session, key, st);
698
569
  return next();
699
570
  }
@@ -743,7 +614,7 @@ function apply(ctx, cfg) {
743
614
  m += '\n' + d.chengyuJielong.roundEnd.replace('{0}', st.chengyuJielong.currentRound.toString()).replace('{1}', (st.chengyuJielong.totalRounds - st.chengyuJielong.currentRound).toString());
744
615
  await session.send(m);
745
616
  st.chengyuJielong.hasTriggeredAutoPlay = false;
746
- setupAutoStop(session, st.chengyuJielong, cfg, d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
617
+ setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
747
618
  scheduleAutoPlay(session, key, st);
748
619
  }
749
620
  }
@@ -756,7 +627,7 @@ function apply(ctx, cfg) {
756
627
  }
757
628
  catch (error) {
758
629
  await session.send(d.chengyuJielong.apiError);
759
- setupAutoStop(session, st.chengyuJielong, cfg, d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
630
+ setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
760
631
  scheduleAutoPlay(session, key, st);
761
632
  }
762
633
  gameStates.set(key, st);
@@ -774,7 +645,7 @@ function apply(ctx, cfg) {
774
645
  params: {
775
646
  action: 'get_hint',
776
647
  id: st.chengyuImage.currentId,
777
- level: 1
648
+ level: cfg.chengyuImage.defaultHintLevel
778
649
  },
779
650
  timeout: cfg.apiConfig.timeout
780
651
  });
@@ -789,11 +660,11 @@ function apply(ctx, cfg) {
789
660
  catch (error) {
790
661
  await session.send(d.chengyuImage.hintError);
791
662
  }
792
- setupAutoStop(session, st.chengyuImage, cfg, d.chengyuImage.autoStop, cfg.chengyuImage.showRank);
663
+ setupAutoStop(session, st.chengyuImage, cfg, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank);
793
664
  return;
794
665
  }
795
666
  if (!isFourCharIdiom(content)) {
796
- setupAutoStop(session, st.chengyuImage, cfg, d.chengyuImage.autoStop, cfg.chengyuImage.showRank);
667
+ setupAutoStop(session, st.chengyuImage, cfg, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank);
797
668
  return next();
798
669
  }
799
670
  try {
@@ -869,7 +740,7 @@ function apply(ctx, cfg) {
869
740
  catch (error) {
870
741
  await session.send(d.chengyuImage.apiError);
871
742
  }
872
- setupAutoStop(session, st.chengyuImage, cfg, d.chengyuImage.autoStop, cfg.chengyuImage.showRank);
743
+ setupAutoStop(session, st.chengyuImage, cfg, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank);
873
744
  gameStates.set(key, st);
874
745
  return;
875
746
  }
@@ -879,6 +750,12 @@ function apply(ctx, cfg) {
879
750
  st.wzHero.players[playerKey] = getPlayerData(session);
880
751
  st.wzHero.participants.push(playerKey);
881
752
  }
753
+ if (content === '结束') {
754
+ clearGameData(st.wzHero);
755
+ await session.send(d.wzHero.stop);
756
+ gameStates.set(key, st);
757
+ return;
758
+ }
882
759
  try {
883
760
  const r = await axios_1.default.get('https://api.suol.cc/v1/game_wz.php', {
884
761
  params: { id: getIntUserId(session), msg: content }, timeout: cfg.apiConfig.timeout
@@ -931,7 +808,7 @@ function apply(ctx, cfg) {
931
808
  catch (error) {
932
809
  await session.send(d.wzHero.apiError);
933
810
  }
934
- setupAutoStop(session, st.wzHero, cfg, d.wzHero.autoStop, cfg.wzHero.showRank);
811
+ setupAutoStop(session, st.wzHero, cfg, 'wzHero', d.wzHero.autoStop, cfg.wzHero.showRank);
935
812
  gameStates.set(key, st);
936
813
  return;
937
814
  }
@@ -941,9 +818,15 @@ function apply(ctx, cfg) {
941
818
  st.guessNumber.players[playerKey] = getPlayerData(session);
942
819
  st.guessNumber.participants.push(playerKey);
943
820
  }
821
+ if (content === '结束') {
822
+ clearGameData(st.guessNumber);
823
+ await session.send(d.guessNumber.stop);
824
+ gameStates.set(key, st);
825
+ return;
826
+ }
944
827
  const num = parseInt(content);
945
828
  if (isNaN(num)) {
946
- setupAutoStop(session, st.guessNumber, cfg, d.guessNumber.autoStop, cfg.guessNumber.showRank);
829
+ setupAutoStop(session, st.guessNumber, cfg, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank);
947
830
  return next();
948
831
  }
949
832
  if (num === st.guessNumber.target) {
@@ -974,108 +857,7 @@ function apply(ctx, cfg) {
974
857
  st.guessNumber.currentMax = num - 1;
975
858
  await session.send(d.guessNumber.tooBig.replace('{0}', st.guessNumber.currentMin.toString()).replace('{1}', st.guessNumber.currentMax.toString()));
976
859
  }
977
- setupAutoStop(session, st.guessNumber, cfg, d.guessNumber.autoStop, cfg.guessNumber.showRank);
978
- gameStates.set(key, st);
979
- return;
980
- }
981
- if (cfg.enableDice && st.dice.started) {
982
- clearGameTimer(st.dice);
983
- if (!st.dice.players[playerKey]) {
984
- st.dice.players[playerKey] = getPlayerData(session);
985
- st.dice.participants.push(playerKey);
986
- }
987
- if (content !== '掷骰子') {
988
- setupAutoStop(session, st.dice, cfg, d.dice.autoStop, cfg.dice.showRank);
989
- return next();
990
- }
991
- st.dice.playerDice = koishi_1.Random.int(1, 6);
992
- st.dice.botDice = cfg.dice.botParticipate ? koishi_1.Random.int(1, 6) : 0;
993
- let resultMsg = d.dice.roll.replace('{0}', st.dice.playerDice.toString()).replace('{1}', st.dice.botDice.toString());
994
- if (cfg.dice.botParticipate) {
995
- if (st.dice.playerDice > st.dice.botDice) {
996
- resultMsg += '\n' + d.dice.win;
997
- st.dice.players[playerKey].score += 1;
998
- st.dice.players[playerKey].correctCount += 1;
999
- }
1000
- else if (st.dice.playerDice < st.dice.botDice) {
1001
- resultMsg += '\n' + d.dice.lose;
1002
- }
1003
- else {
1004
- resultMsg += '\n' + d.dice.draw;
1005
- }
1006
- }
1007
- else {
1008
- resultMsg += '\n你掷出了 ' + st.dice.playerDice + ' 点!';
1009
- st.dice.players[playerKey].score += 1;
1010
- }
1011
- await session.send(resultMsg);
1012
- st.dice.currentRound += 1;
1013
- if (st.dice.currentRound > st.dice.totalRounds) {
1014
- st.dice.started = false;
1015
- clearGameTimer(st.dice);
1016
- await session.send(d.dice.gameEnd);
1017
- if (cfg.dice.showRank && !isPrivate(session)) {
1018
- const rankText = generateRankText(st.dice.players);
1019
- await session.send(rankText);
1020
- }
1021
- clearGameData(st.dice);
1022
- }
1023
- else {
1024
- await session.send(d.dice.roundEnd.replace('{0}', st.dice.currentRound.toString()).replace('{1}', (st.dice.totalRounds - st.dice.currentRound).toString()));
1025
- }
1026
- setupAutoStop(session, st.dice, cfg, d.dice.autoStop, cfg.dice.showRank);
1027
- gameStates.set(key, st);
1028
- return;
1029
- }
1030
- if (cfg.enableRps && st.rps.started) {
1031
- clearGameTimer(st.rps);
1032
- if (!st.rps.players[playerKey]) {
1033
- st.rps.players[playerKey] = getPlayerData(session);
1034
- st.rps.participants.push(playerKey);
1035
- }
1036
- if (!st.rps.choices.includes(content)) {
1037
- await session.send(d.rps.invalidChoice);
1038
- setupAutoStop(session, st.rps, cfg, d.rps.autoStop, cfg.rps.showRank);
1039
- return next();
1040
- }
1041
- st.rps.playerChoice = content;
1042
- st.rps.botChoice = cfg.rps.botParticipate ? st.rps.choices[koishi_1.Random.int(0, 2)] : '';
1043
- let resultMsg = d.rps.choice.replace('{0}', st.rps.playerChoice).replace('{1}', st.rps.botChoice);
1044
- if (cfg.rps.botParticipate) {
1045
- if ((st.rps.playerChoice === '石头' && st.rps.botChoice === '剪刀') ||
1046
- (st.rps.playerChoice === '剪刀' && st.rps.botChoice === '布') ||
1047
- (st.rps.playerChoice === '布' && st.rps.botChoice === '石头')) {
1048
- resultMsg += '\n' + d.rps.win;
1049
- st.rps.players[playerKey].score += 1;
1050
- st.rps.players[playerKey].correctCount += 1;
1051
- }
1052
- else if (st.rps.playerChoice === st.rps.botChoice) {
1053
- resultMsg += '\n' + d.rps.draw;
1054
- }
1055
- else {
1056
- resultMsg += '\n' + d.rps.lose;
1057
- }
1058
- }
1059
- else {
1060
- resultMsg += '\n你选择了 ' + st.rps.playerChoice + '!';
1061
- st.rps.players[playerKey].score += 1;
1062
- }
1063
- await session.send(resultMsg);
1064
- st.rps.currentRound += 1;
1065
- if (st.rps.currentRound > st.rps.totalRounds) {
1066
- st.rps.started = false;
1067
- clearGameTimer(st.rps);
1068
- await session.send(d.rps.gameEnd);
1069
- if (cfg.rps.showRank && !isPrivate(session)) {
1070
- const rankText = generateRankText(st.rps.players);
1071
- await session.send(rankText);
1072
- }
1073
- clearGameData(st.rps);
1074
- }
1075
- else {
1076
- await session.send(d.rps.roundEnd.replace('{0}', st.rps.currentRound.toString()).replace('{1}', (st.rps.totalRounds - st.rps.currentRound).toString()));
1077
- }
1078
- setupAutoStop(session, st.rps, cfg, d.rps.autoStop, cfg.rps.showRank);
860
+ setupAutoStop(session, st.guessNumber, cfg, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank);
1079
861
  gameStates.set(key, st);
1080
862
  return;
1081
863
  }
@@ -1085,56 +867,62 @@ function apply(ctx, cfg) {
1085
867
  st.calc24.players[playerKey] = getPlayerData(session);
1086
868
  st.calc24.participants.push(playerKey);
1087
869
  }
870
+ if (content === '结束') {
871
+ clearGameData(st.calc24);
872
+ await session.send(d.calc24.stop);
873
+ gameStates.set(key, st);
874
+ return;
875
+ }
1088
876
  if (content === '换题') {
1089
- st.calc24.numbers = [];
1090
- for (let i = 0; i < 4; i++) {
1091
- st.calc24.numbers.push(koishi_1.Random.int(cfg.calc24.numberRange[0], cfg.calc24.numberRange[1]));
877
+ if (!st.calc24.solved) {
878
+ const range = cfg.calc24.difficultyLevels[st.calc24.difficulty === '简单' ? 'easy' :
879
+ st.calc24.difficulty === '中等' ? 'medium' : 'hard'];
880
+ st.calc24.numbers = generateSolvable24Numbers(range.min, range.max);
881
+ st.calc24.solved = false;
882
+ await session.send(d.calc24.generate.replace('{0}', st.calc24.currentRound.toString())
883
+ .replace('{1}', st.calc24.difficulty)
884
+ .replace('{2}', st.calc24.numbers.join('、')));
1092
885
  }
1093
- await session.send(d.calc24.generate.replace('{0}', st.calc24.currentRound.toString()).replace('{1}', st.calc24.numbers.join('、')));
1094
- setupAutoStop(session, st.calc24, cfg, d.calc24.autoStop, cfg.calc24.showRank);
1095
- return next();
886
+ setupAutoStop(session, st.calc24, cfg, 'calc24', d.calc24.autoStop, cfg.calc24.showRank);
887
+ return;
1096
888
  }
1097
- st.calc24.playerAnswer = content;
1098
- const canCalculate = calculate24([...st.calc24.numbers]);
1099
- if (!canCalculate) {
1100
- await session.send(d.calc24.impossible);
889
+ if (st.calc24.solved) {
890
+ await session.send(d.calc24.solved);
891
+ setupAutoStop(session, st.calc24, cfg, 'calc24', d.calc24.autoStop, cfg.calc24.showRank);
892
+ return;
1101
893
  }
1102
- else {
1103
- try {
1104
- const result = eval(content.replace(/[^\d\+\-\*\/\(\)\.]/g, ''));
1105
- if (Math.abs(result - 24) < 0.001) {
1106
- await session.send(d.calc24.correct);
1107
- st.calc24.players[playerKey].score += 1;
1108
- st.calc24.players[playerKey].correctCount += 1;
1109
- }
1110
- else {
1111
- await session.send(d.calc24.wrong);
894
+ const result = evaluateExpression(content);
895
+ if (result !== null && Math.abs(result - 24) < 0.001) {
896
+ await session.send(d.calc24.correct);
897
+ st.calc24.players[playerKey].score += 1;
898
+ st.calc24.players[playerKey].correctCount += 1;
899
+ st.calc24.solved = true;
900
+ st.calc24.currentRound += 1;
901
+ if (st.calc24.currentRound > st.calc24.totalRounds) {
902
+ st.calc24.started = false;
903
+ clearGameTimer(st.calc24);
904
+ await session.send(d.calc24.gameEnd);
905
+ if (cfg.calc24.showRank && !isPrivate(session)) {
906
+ const rankText = generateRankText(st.calc24.players);
907
+ await session.send(rankText);
1112
908
  }
909
+ clearGameData(st.calc24);
1113
910
  }
1114
- catch {
1115
- await session.send(d.calc24.wrong);
1116
- }
1117
- }
1118
- st.calc24.currentRound += 1;
1119
- if (st.calc24.currentRound > st.calc24.totalRounds) {
1120
- st.calc24.started = false;
1121
- clearGameTimer(st.calc24);
1122
- await session.send(d.calc24.gameEnd);
1123
- if (cfg.calc24.showRank && !isPrivate(session)) {
1124
- const rankText = generateRankText(st.calc24.players);
1125
- await session.send(rankText);
911
+ else {
912
+ await session.send(d.calc24.roundEnd.replace('{0}', st.calc24.currentRound.toString()).replace('{1}', (st.calc24.totalRounds - st.calc24.currentRound).toString()));
913
+ const range = cfg.calc24.difficultyLevels[st.calc24.difficulty === '简单' ? 'easy' :
914
+ st.calc24.difficulty === '中等' ? 'medium' : 'hard'];
915
+ st.calc24.numbers = generateSolvable24Numbers(range.min, range.max);
916
+ st.calc24.solved = false;
917
+ await session.send(d.calc24.generate.replace('{0}', st.calc24.currentRound.toString())
918
+ .replace('{1}', st.calc24.difficulty)
919
+ .replace('{2}', st.calc24.numbers.join('、')));
1126
920
  }
1127
- clearGameData(st.calc24);
1128
921
  }
1129
922
  else {
1130
- st.calc24.numbers = [];
1131
- for (let i = 0; i < 4; i++) {
1132
- st.calc24.numbers.push(koishi_1.Random.int(cfg.calc24.numberRange[0], cfg.calc24.numberRange[1]));
1133
- }
1134
- await session.send(d.calc24.roundEnd.replace('{0}', st.calc24.currentRound.toString()).replace('{1}', (st.calc24.totalRounds - st.calc24.currentRound).toString()));
1135
- await session.send(d.calc24.generate.replace('{0}', st.calc24.currentRound.toString()).replace('{1}', st.calc24.numbers.join('、')));
923
+ await session.send(d.calc24.wrong);
1136
924
  }
1137
- setupAutoStop(session, st.calc24, cfg, d.calc24.autoStop, cfg.calc24.showRank);
925
+ setupAutoStop(session, st.calc24, cfg, 'calc24', d.calc24.autoStop, cfg.calc24.showRank);
1138
926
  gameStates.set(key, st);
1139
927
  return;
1140
928
  }
@@ -1144,18 +932,31 @@ function apply(ctx, cfg) {
1144
932
  st.passwordLock.players[playerKey] = getPlayerData(session);
1145
933
  st.passwordLock.participants.push(playerKey);
1146
934
  }
935
+ if (content === '结束') {
936
+ clearGameData(st.passwordLock);
937
+ await session.send(d.passwordLock.stop);
938
+ gameStates.set(key, st);
939
+ return;
940
+ }
941
+ if (st.passwordLock.solved) {
942
+ await session.send(d.passwordLock.solved);
943
+ setupAutoStop(session, st.passwordLock, cfg, 'passwordLock', d.passwordLock.autoStop, cfg.passwordLock.showRank);
944
+ return;
945
+ }
1147
946
  if (!/^\d{4}$/.test(content)) {
1148
947
  await session.send(d.passwordLock.invalidPassword);
1149
- setupAutoStop(session, st.passwordLock, cfg, d.passwordLock.autoStop, cfg.passwordLock.showRank);
1150
- return next();
948
+ setupAutoStop(session, st.passwordLock, cfg, 'passwordLock', d.passwordLock.autoStop, cfg.passwordLock.showRank);
949
+ return;
1151
950
  }
1152
951
  st.passwordLock.playerGuess = content;
1153
952
  st.passwordLock.guessTimes += 1;
1154
953
  await session.send(d.passwordLock.guess.replace('{0}', content).replace('{1}', st.passwordLock.guessTimes.toString()));
1155
954
  if (content === st.passwordLock.password) {
955
+ const score = 10 - (st.passwordLock.guessTimes - 1);
1156
956
  await session.send(d.passwordLock.correct.replace('{0}', content).replace('{1}', st.passwordLock.guessTimes.toString()));
1157
- st.passwordLock.players[playerKey].score += 10 - (st.passwordLock.guessTimes - 1);
957
+ st.passwordLock.players[playerKey].score += score > 0 ? score : 1;
1158
958
  st.passwordLock.players[playerKey].correctCount += 1;
959
+ st.passwordLock.solved = true;
1159
960
  st.passwordLock.started = false;
1160
961
  clearGameTimer(st.passwordLock);
1161
962
  await session.send(d.passwordLock.gameEnd);
@@ -1169,6 +970,10 @@ function apply(ctx, cfg) {
1169
970
  let hint = '';
1170
971
  if (cfg.passwordLock.showHint) {
1171
972
  hint = generatePasswordHint(st.passwordLock.password, content);
973
+ await session.send(d.passwordLock.wrong.replace('{0}', hint));
974
+ }
975
+ else {
976
+ await session.send(d.passwordLock.wrong.replace('{0}', ''));
1172
977
  }
1173
978
  if (st.passwordLock.guessTimes >= st.passwordLock.maxGuessTimes) {
1174
979
  await session.send(d.passwordLock.noChance.replace('{0}', st.passwordLock.password));
@@ -1182,11 +987,10 @@ function apply(ctx, cfg) {
1182
987
  clearGameData(st.passwordLock);
1183
988
  }
1184
989
  else {
1185
- await session.send(d.passwordLock.wrong.replace('{0}', hint));
1186
990
  await session.send(`剩余猜测次数:${st.passwordLock.maxGuessTimes - st.passwordLock.guessTimes}`);
1187
991
  }
1188
992
  }
1189
- setupAutoStop(session, st.passwordLock, cfg, d.passwordLock.autoStop, cfg.passwordLock.showRank);
993
+ setupAutoStop(session, st.passwordLock, cfg, 'passwordLock', d.passwordLock.autoStop, cfg.passwordLock.showRank);
1190
994
  gameStates.set(key, st);
1191
995
  return;
1192
996
  }
@@ -1199,7 +1003,7 @@ function apply(ctx, cfg) {
1199
1003
  return;
1200
1004
  const key = getSessionKey(session);
1201
1005
  const st = gameStates.get(key) || initState(key, cfg);
1202
- if (checkGameRunning(st)) {
1006
+ if (checkGameRunning(st, 'guessNumber')) {
1203
1007
  await session.send(d.common.gameRunning);
1204
1008
  return;
1205
1009
  }
@@ -1212,7 +1016,7 @@ function apply(ctx, cfg) {
1212
1016
  await session.send(d.guessNumber.start.replace('{0}', st.guessNumber.totalRounds.toString()));
1213
1017
  await session.send(`猜数字范围:${st.guessNumber.currentMin} - ${st.guessNumber.currentMax}`);
1214
1018
  gameStates.set(key, st);
1215
- setupAutoStop(session, st.guessNumber, cfg, d.guessNumber.autoStop, cfg.guessNumber.showRank);
1019
+ setupAutoStop(session, st.guessNumber, cfg, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank);
1216
1020
  }
1217
1021
  else if (action === '结束') {
1218
1022
  clearGameData(st.guessNumber);
@@ -1223,20 +1027,20 @@ function apply(ctx, cfg) {
1223
1027
  await session.send(d.guessNumber.usage);
1224
1028
  }
1225
1029
  });
1226
- ctx.command('王者英雄 <action> [param]', '王者英雄猜谜')
1030
+ ctx.command('猜王者英雄 <action> [param]', '猜王者英雄猜谜')
1227
1031
  .action(async (argv, action, param) => {
1228
1032
  const session = argv.session;
1229
1033
  if (!session)
1230
1034
  return;
1231
1035
  const key = getSessionKey(session);
1232
1036
  const st = gameStates.get(key) || initState(key, cfg);
1233
- if (checkGameRunning(st)) {
1037
+ if (checkGameRunning(st, 'wzHero')) {
1234
1038
  await session.send(d.common.gameRunning);
1235
1039
  return;
1236
1040
  }
1237
1041
  if (action === '开始') {
1238
1042
  st.wzHero.started = true;
1239
- st.wzHero.difficulty = param || '简单';
1043
+ st.wzHero.difficulty = cfg.wzHero.defaultDifficulty;
1240
1044
  st.wzHero.currentRound = 1;
1241
1045
  try {
1242
1046
  const r = await axios_1.default.get('https://api.suol.cc/v1/game_wz.php', {
@@ -1246,7 +1050,7 @@ function apply(ctx, cfg) {
1246
1050
  const dt = r.data;
1247
1051
  let text = `${dt.message || ''}\n${dt.hint || ''}\n剩余提示次数:${dt.remaining_hints}\n${dt.guide || ''}`;
1248
1052
  text = text.replace(/\\n/g, '\n');
1249
- await session.send(d.wzHero.start.replace('{0}', st.wzHero.totalRounds.toString()));
1053
+ await session.send(d.wzHero.start.replace('{0}', st.wzHero.totalRounds.toString()).replace('{1}', st.wzHero.difficulty));
1250
1054
  await session.send(text);
1251
1055
  st.wzHero.currentAnswer = dt.hint || '';
1252
1056
  }
@@ -1254,7 +1058,7 @@ function apply(ctx, cfg) {
1254
1058
  await session.send(d.wzHero.apiError);
1255
1059
  }
1256
1060
  gameStates.set(key, st);
1257
- setupAutoStop(session, st.wzHero, cfg, d.wzHero.autoStop, cfg.wzHero.showRank);
1061
+ setupAutoStop(session, st.wzHero, cfg, 'wzHero', d.wzHero.autoStop, cfg.wzHero.showRank);
1258
1062
  }
1259
1063
  else if (action === '结束') {
1260
1064
  clearGameData(st.wzHero);
@@ -1272,7 +1076,7 @@ function apply(ctx, cfg) {
1272
1076
  return;
1273
1077
  const key = getSessionKey(session);
1274
1078
  const st = gameStates.get(key) || initState(key, cfg);
1275
- if (checkGameRunning(st)) {
1079
+ if (checkGameRunning(st, 'chengyuImage')) {
1276
1080
  await session.send(d.common.gameRunning);
1277
1081
  return;
1278
1082
  }
@@ -1290,7 +1094,7 @@ function apply(ctx, cfg) {
1290
1094
  st.chengyuImage.currentPage = dt.data.question.page;
1291
1095
  st.chengyuImage.options = dt.data.question.options;
1292
1096
  st.chengyuImage.answer = dt.data.question.answer || '';
1293
- await session.send(d.chengyuImage.start.replace('{0}', st.chengyuImage.totalRounds.toString()));
1097
+ await session.send(d.chengyuImage.start.replace('{0}', st.chengyuImage.totalRounds.toString()).replace('{1}', cfg.chengyuImage.defaultHintLevel.toString()));
1294
1098
  await session.send(`请从选项中选择4个字组成成语\n选项:${dt.data.question.options.join('、')}`);
1295
1099
  await session.send(koishi_1.segment.image(dt.data.question.image_url));
1296
1100
  }
@@ -1302,7 +1106,7 @@ function apply(ctx, cfg) {
1302
1106
  await session.send(d.chengyuImage.apiError);
1303
1107
  }
1304
1108
  gameStates.set(key, st);
1305
- setupAutoStop(session, st.chengyuImage, cfg, d.chengyuImage.autoStop, cfg.chengyuImage.showRank);
1109
+ setupAutoStop(session, st.chengyuImage, cfg, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank);
1306
1110
  }
1307
1111
  else if (action === '结束') {
1308
1112
  clearGameData(st.chengyuImage);
@@ -1320,7 +1124,7 @@ function apply(ctx, cfg) {
1320
1124
  return;
1321
1125
  const key = getSessionKey(session);
1322
1126
  const st = gameStates.get(key) || initState(key, cfg);
1323
- if (checkGameRunning(st)) {
1127
+ if (checkGameRunning(st, 'chengyuJielong')) {
1324
1128
  await session.send(d.common.gameRunning);
1325
1129
  return;
1326
1130
  }
@@ -1332,7 +1136,7 @@ function apply(ctx, cfg) {
1332
1136
  await session.send(d.chengyuJielong.start.replace('{0}', st.chengyuJielong.totalRounds.toString()));
1333
1137
  gameStates.set(key, st);
1334
1138
  scheduleAutoPlay(session, key, st);
1335
- setupAutoStop(session, st.chengyuJielong, cfg, d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
1139
+ setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank);
1336
1140
  }
1337
1141
  else if (action === '结束') {
1338
1142
  clearGameData(st.chengyuJielong);
@@ -1343,54 +1147,6 @@ function apply(ctx, cfg) {
1343
1147
  await session.send(d.chengyuJielong.joinUsage);
1344
1148
  }
1345
1149
  });
1346
- ctx.command('掷骰子 <action>', '掷骰子比大小')
1347
- .action(async (argv, action) => {
1348
- const session = argv.session;
1349
- if (!session)
1350
- return;
1351
- const key = getSessionKey(session);
1352
- const st = gameStates.get(key) || initState(key, cfg);
1353
- if (checkGameRunning(st)) {
1354
- await session.send(d.common.gameRunning);
1355
- return;
1356
- }
1357
- if (action === '开始') {
1358
- st.dice.started = true;
1359
- st.dice.currentRound = 1;
1360
- await session.send(d.dice.start.replace('{0}', st.dice.totalRounds.toString()));
1361
- gameStates.set(key, st);
1362
- setupAutoStop(session, st.dice, cfg, d.dice.autoStop, cfg.dice.showRank);
1363
- }
1364
- else if (action === '结束') {
1365
- clearGameData(st.dice);
1366
- await session.send(d.dice.stop);
1367
- gameStates.set(key, st);
1368
- }
1369
- });
1370
- ctx.command('石头剪刀布 <action>', '石头剪刀布')
1371
- .action(async (argv, action) => {
1372
- const session = argv.session;
1373
- if (!session)
1374
- return;
1375
- const key = getSessionKey(session);
1376
- const st = gameStates.get(key) || initState(key, cfg);
1377
- if (checkGameRunning(st)) {
1378
- await session.send(d.common.gameRunning);
1379
- return;
1380
- }
1381
- if (action === '开始') {
1382
- st.rps.started = true;
1383
- st.rps.currentRound = 1;
1384
- await session.send(d.rps.start.replace('{0}', st.rps.totalRounds.toString()));
1385
- gameStates.set(key, st);
1386
- setupAutoStop(session, st.rps, cfg, d.rps.autoStop, cfg.rps.showRank);
1387
- }
1388
- else if (action === '结束') {
1389
- clearGameData(st.rps);
1390
- await session.send(d.rps.stop);
1391
- gameStates.set(key, st);
1392
- }
1393
- });
1394
1150
  ctx.command('算24点 <action>', '算24点游戏')
1395
1151
  .action(async (argv, action) => {
1396
1152
  const session = argv.session;
@@ -1398,36 +1154,42 @@ function apply(ctx, cfg) {
1398
1154
  return;
1399
1155
  const key = getSessionKey(session);
1400
1156
  const st = gameStates.get(key) || initState(key, cfg);
1401
- if (checkGameRunning(st)) {
1157
+ if (checkGameRunning(st, 'calc24')) {
1402
1158
  await session.send(d.common.gameRunning);
1403
1159
  return;
1404
1160
  }
1405
1161
  if (action === '开始') {
1162
+ st.calc24.difficulty = cfg.calc24.defaultDifficulty;
1406
1163
  st.calc24.started = true;
1407
1164
  st.calc24.currentRound = 1;
1408
- st.calc24.numbers = [];
1409
- for (let i = 0; i < 4; i++) {
1410
- st.calc24.numbers.push(koishi_1.Random.int(cfg.calc24.numberRange[0], cfg.calc24.numberRange[1]));
1411
- }
1412
- await session.send(d.calc24.start.replace('{0}', st.calc24.totalRounds.toString()));
1413
- await session.send(d.calc24.generate.replace('{0}', st.calc24.currentRound.toString()).replace('{1}', st.calc24.numbers.join('、')));
1165
+ st.calc24.solved = false;
1166
+ const range = cfg.calc24.difficultyLevels[st.calc24.difficulty === '简单' ? 'easy' :
1167
+ st.calc24.difficulty === '中等' ? 'medium' : 'hard'];
1168
+ st.calc24.numbers = generateSolvable24Numbers(range.min, range.max);
1169
+ await session.send(d.calc24.start.replace('{0}', st.calc24.totalRounds.toString()).replace('{1}', st.calc24.difficulty));
1170
+ await session.send(d.calc24.generate.replace('{0}', st.calc24.currentRound.toString())
1171
+ .replace('{1}', st.calc24.difficulty)
1172
+ .replace('{2}', st.calc24.numbers.join('、')));
1414
1173
  gameStates.set(key, st);
1415
- setupAutoStop(session, st.calc24, cfg, d.calc24.autoStop, cfg.calc24.showRank);
1174
+ setupAutoStop(session, st.calc24, cfg, 'calc24', d.calc24.autoStop, cfg.calc24.showRank);
1416
1175
  }
1417
1176
  else if (action === '结束') {
1418
1177
  clearGameData(st.calc24);
1419
1178
  await session.send(d.calc24.stop);
1420
1179
  gameStates.set(key, st);
1421
1180
  }
1181
+ else {
1182
+ await session.send('请输入:算24点 开始 或 算24点 结束');
1183
+ }
1422
1184
  });
1423
- ctx.command('密码锁 <action>', '密码锁破解')
1185
+ ctx.command('猜密码 <action>', '猜密码游戏')
1424
1186
  .action(async (argv, action) => {
1425
1187
  const session = argv.session;
1426
1188
  if (!session)
1427
1189
  return;
1428
1190
  const key = getSessionKey(session);
1429
1191
  const st = gameStates.get(key) || initState(key, cfg);
1430
- if (checkGameRunning(st)) {
1192
+ if (checkGameRunning(st, 'passwordLock')) {
1431
1193
  await session.send(d.common.gameRunning);
1432
1194
  return;
1433
1195
  }
@@ -1435,15 +1197,19 @@ function apply(ctx, cfg) {
1435
1197
  st.passwordLock.started = true;
1436
1198
  st.passwordLock.currentRound = 1;
1437
1199
  st.passwordLock.guessTimes = 0;
1200
+ st.passwordLock.solved = false;
1438
1201
  st.passwordLock.password = koishi_1.Random.int(1000, 9999).toString();
1439
1202
  await session.send(d.passwordLock.start.replace('{0}', st.passwordLock.maxGuessTimes.toString()));
1440
1203
  gameStates.set(key, st);
1441
- setupAutoStop(session, st.passwordLock, cfg, d.passwordLock.autoStop, cfg.passwordLock.showRank);
1204
+ setupAutoStop(session, st.passwordLock, cfg, 'passwordLock', d.passwordLock.autoStop, cfg.passwordLock.showRank);
1442
1205
  }
1443
1206
  else if (action === '结束') {
1444
1207
  clearGameData(st.passwordLock);
1445
1208
  await session.send(d.passwordLock.stop);
1446
1209
  gameStates.set(key, st);
1447
1210
  }
1211
+ else {
1212
+ await session.send('请输入:猜密码 开始 或 猜密码 结束');
1213
+ }
1448
1214
  });
1449
1215
  }