koishi-plugin-game-mini 0.2.6 → 0.2.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.js CHANGED
@@ -11,27 +11,28 @@ const path_1 = __importDefault(require("path"));
11
11
  const yaml_1 = __importDefault(require("yaml"));
12
12
  const axios_1 = __importDefault(require("axios"));
13
13
  exports.name = 'game-mini';
14
- exports.using = ['i18n'];
14
+ exports.using = ['i18n', 'database'];
15
15
  exports.inject = ['console'];
16
16
  const defaultMessages = {
17
17
  guessNumber: {
18
- usage: "用法错误!正确用法:猜数字 开始 | 猜数字 [数字] | 猜数字 结束",
18
+ usage: "用法错误!正确用法:猜数字 开始 | [数字] | 猜数字 结束",
19
19
  start: "猜数字比赛开始!本次共 {0} 回合~",
20
20
  stop: "猜数字比赛已停止",
21
21
  outOfRange: "数字超出当前范围 [{0}-{1}],请重新输入!",
22
22
  tooSmall: "猜小啦!当前范围更新为 [{0}-{1}]",
23
23
  tooBig: "猜大啦!当前范围更新为 [{0}-{1}]",
24
- correct: "恭喜你猜中数字!本轮你不得分,其他参与者各得1分~",
24
+ correct: "恭喜你猜中数字!",
25
25
  roundEnd: "第 {0} 回合结束!剩余回合:{1}",
26
26
  gameEnd: "🎉 猜数字比赛结束!🎉",
27
- rankTitle: "🏆 排行榜 🏆",
27
+ rankTitle: "🏆 本局排行榜 🏆",
28
28
  rankEmpty: "暂无参与记录~",
29
29
  disabled: "猜数字功能已关闭,请联系管理员开启",
30
- autoStop: "游戏因长时间无人操作,已自动结束"
30
+ autoStop: "太久没人玩啦,比赛自动结束~"
31
31
  },
32
32
  wzHero: {
33
+ usage: "用法错误!正确用法:猜王者英雄 开始 | [答案] | 提示 | 结束",
33
34
  start: "猜王者英雄开始!本次共 {0} 回合~当前难度:{1}",
34
- startUsage: "用法错误!正确用法:猜王者英雄 开始 | 猜王者英雄 [答案] | 猜王者英雄 提示 | 猜王者英雄 结束",
35
+ startUsage: "用法错误!正确用法:猜王者英雄 开始 | [答案] | 提示 | 结束",
35
36
  stop: "猜王者英雄比赛已停止",
36
37
  notStarted: "猜王者英雄比赛尚未开始,请输入 猜王者英雄 开始 开始游戏",
37
38
  hint: "提示",
@@ -40,15 +41,16 @@ const defaultMessages = {
40
41
  wrong: "答错啦~正确答案是:{0},你不得分",
41
42
  roundEnd: "第 {0} 回合结束!剩余回合:{1}",
42
43
  gameEnd: "🎉 猜王者英雄比赛结束!🎉",
43
- rankTitle: "🏆 排行榜 🏆",
44
+ rankTitle: "🏆 本局排行榜 🏆",
44
45
  rankEmpty: "暂无参与记录~",
45
46
  disabled: "猜王者英雄功能已关闭,请联系管理员开启",
46
- autoStop: "游戏因长时间无人操作,已自动结束"
47
+ autoStop: "太久没人玩啦,比赛自动结束~"
47
48
  },
48
49
  chengyuImage: {
50
+ usage: "用法错误!正确用法:看图猜成语 开始 | [答案] | 提示 | 结束",
49
51
  start: "看图猜成语比赛开始!本次共 {0} 回合~当前提示级别:{1}",
50
52
  stop: "看图猜成语比赛已停止",
51
- submitUsage: "请直接输入 看图猜成语 [答案],或输入 看图猜成语 提示 获取线索",
53
+ submitUsage: "用法错误!正确用法:看图猜成语 开始 | [答案] | 提示 | 结束",
52
54
  notStarted: "看图猜成语比赛尚未开始,请输入 看图猜成语 开始 开始游戏",
53
55
  next: "第 {0} 题来啦!",
54
56
  hintGet: "【提示】{0}",
@@ -58,216 +60,260 @@ const defaultMessages = {
58
60
  wrong: "答错啦~正确答案是:{0},你不得分",
59
61
  roundEnd: "第 {0} 回合结束!剩余回合:{1}",
60
62
  gameEnd: "🎉 看图猜成语比赛结束!🎉",
61
- rankTitle: "🏆 排行榜 🏆",
63
+ rankTitle: "🏆 本局排行榜 🏆",
62
64
  rankEmpty: "暂无参与记录~",
63
65
  disabled: "看图猜成语功能已关闭,请联系管理员开启",
64
- autoStop: "游戏因长时间无人操作,已自动结束"
66
+ autoStop: "太久没人玩啦,比赛自动结束~"
65
67
  },
66
68
  chengyuJielong: {
69
+ usage: "用法错误!正确用法:成语接龙 开始 | [成语] | 结束",
67
70
  start: "成语接龙比赛开始!本次共 {0} 回合~我先来~",
68
71
  stop: "成语接龙比赛已停止",
69
72
  notStarted: "成语接龙比赛尚未开始,请输入 成语接龙 开始 开始游戏",
70
- joinUsage: "请直接发送 成语接龙 [成语] 参与接龙",
73
+ joinUsage: "用法错误!正确用法:成语接龙 开始 | [成语] | 结束",
71
74
  apiError: "API请求失败,请稍后再试",
72
- botTurn: "该我了!我接:{0}({1})\n释义:{2}",
75
+ botTurn: "该我了!我接:{0}",
73
76
  botWin: "哈哈我接不上了!本轮结束~",
74
- autoPlayTooMany: "我已经主动参与 {0} 次啦,不再主动接啦~",
75
- gameInactiveStop: "太久没人玩啦,比赛自动结束~",
76
- notIdiom: "请发送四字成语参与游戏~",
77
- correct: "接龙成功!你获得1分~",
78
- wrong: "接龙失败!你不得分,其他参与者各得1分~",
77
+ autoPlayTooMany: "自动参与次数已达上限 {0}",
78
+ notIdiom: "请输入4字成语",
79
+ correct: "接龙成功!",
80
+ wrong: "接龙失败!",
79
81
  roundEnd: "第 {0} 回合结束!剩余回合:{1}",
80
82
  gameEnd: "🎉 成语接龙比赛结束!🎉",
81
- rankTitle: "🏆 排行榜 🏆",
83
+ rankTitle: "🏆 本局排行榜 🏆",
82
84
  rankEmpty: "暂无参与记录~",
83
85
  disabled: "成语接龙功能已关闭,请联系管理员开启",
84
- autoStop: "游戏因长时间无人操作,已自动结束"
86
+ autoStop: "太久没人玩啦,比赛自动结束~"
85
87
  },
86
88
  calc24: {
89
+ usage: "用法错误!正确用法:算24点 开始 | [算式] | 换题 | 结束",
87
90
  start: "算24点游戏开始!本次共 {0} 回合~当前难度:{1}",
88
91
  stop: "算24点游戏已停止",
89
92
  notStarted: "算24点游戏尚未开始,请输入 算24点 开始 开始游戏",
90
93
  generate: "📝 第 {0} 题({1}):用 {2} 通过加减乘除和括号算出24!",
91
94
  correct: "答对啦!你获得1分~",
92
95
  wrong: "答错啦~",
93
- impossible: "这组数无法算出24!本题作废,换一组数字~",
94
96
  solved: "这组数已经被答对啦,换一组数字~",
95
97
  roundEnd: "第 {0} 回合结束!剩余回合:{1}",
96
98
  gameEnd: "🎉 算24点游戏结束!🎉",
97
- rankTitle: "🏆 排行榜 🏆",
99
+ rankTitle: "🏆 本局排行榜 🏆",
98
100
  rankEmpty: "暂无参与记录~",
99
101
  disabled: "算24点功能已关闭,请联系管理员开启",
100
- autoStop: "游戏因长时间无人操作,已自动结束"
102
+ autoStop: "太久没人玩啦,比赛自动结束~"
103
+ },
104
+ rank: {
105
+ title: "📊 群游戏总排行榜",
106
+ empty: "暂无玩家数据",
107
+ playerInfo: "{0}. {1} - 得分:{2}分 | 答对:{3}题 | 游玩:{4}次",
108
+ totalStats: "\n📈 总统计:共 {0} 位玩家 | 总得分:{1} | 总答对:{2} | 总游玩:{3}",
109
+ noPermission: "❌ 你没有权限执行此操作",
110
+ clearSuccess: "✅ 本群所有玩家数据已清零"
101
111
  },
102
112
  common: {
103
113
  gameRunning: "当前已有游戏在运行中,请先结束当前游戏后再开始新游戏!",
104
- gameStoppedByInactive: "游戏因长时间无人操作,已自动结束",
105
- paramError: "参数错误!请检查输入格式"
114
+ gameStoppedByInactive: "太久没人玩啦,比赛自动结束~",
115
+ paramError: "参数错误!请检查输入格式"
106
116
  }
107
117
  };
108
118
  exports.Config = koishi_1.Schema.intersect([
109
119
  koishi_1.Schema.object({
110
- enableNumberGuess: koishi_1.Schema.boolean().default(true).description('启用猜数字游戏'),
111
- enableWzHero: koishi_1.Schema.boolean().default(true).description('启用王者英雄猜谜游戏'),
112
- enableChengyuImage: koishi_1.Schema.boolean().default(true).description('启用看图猜成语游戏'),
113
- enableChengyuJielong: koishi_1.Schema.boolean().default(true).description('启用成语接龙游戏'),
114
- enableCalc24: koishi_1.Schema.boolean().default(true).description('启用算24点游戏'),
115
- enablePrivateGame: koishi_1.Schema.boolean().default(true).description('允许私聊玩游戏'),
116
- }).description('基础功能开关'),
120
+ enableNumberGuess: koishi_1.Schema.boolean().default(true).description('🎲 启用猜数字游戏'),
121
+ enableWzHero: koishi_1.Schema.boolean().default(true).description('⚔️ 启用王者英雄猜谜'),
122
+ enableChengyuImage: koishi_1.Schema.boolean().default(true).description('🖼️ 启用看图猜成语'),
123
+ enableChengyuJielong: koishi_1.Schema.boolean().default(true).description('🐉 启用成语接龙'),
124
+ enableCalc24: koishi_1.Schema.boolean().default(true).description('🧮 启用算24'),
125
+ }).description('⚙️ 游戏开关'),
126
+ koishi_1.Schema.object({
127
+ privateGame: koishi_1.Schema.object({
128
+ enableNumberGuess: koishi_1.Schema.boolean().default(true).description('🎲 允许私聊玩猜数字'),
129
+ enableWzHero: koishi_1.Schema.boolean().default(true).description('⚔️ 允许私聊玩王者英雄'),
130
+ enableChengyuImage: koishi_1.Schema.boolean().default(true).description('🖼️ 允许私聊玩看图猜成语'),
131
+ enableChengyuJielong: koishi_1.Schema.boolean().default(true).description('🐉 允许私聊玩成语接龙'),
132
+ enableCalc24: koishi_1.Schema.boolean().default(true).description('🧮 允许私聊玩算24点'),
133
+ }).description('💬 私聊游戏开关'),
134
+ }),
135
+ koishi_1.Schema.object({
136
+ rank: koishi_1.Schema.object({
137
+ enableCommand: koishi_1.Schema.boolean().default(true).description('📊 启用排行榜指令'),
138
+ maxDisplay: koishi_1.Schema.number().min(1).max(100).default(10).description('📋 排行榜最多显示人数'),
139
+ clearDataPermission: koishi_1.Schema.number().default(5).description('🔑 清零数据所需权限等级'),
140
+ messages: koishi_1.Schema.object({
141
+ title: koishi_1.Schema.string().default(defaultMessages.rank.title).description('排行榜标题'),
142
+ empty: koishi_1.Schema.string().default(defaultMessages.rank.empty).description('排行榜为空提示'),
143
+ playerInfo: koishi_1.Schema.string().default(defaultMessages.rank.playerInfo).description('玩家信息格式\n{0}-排名, {1}-玩家名, {2}-得分, {3}-答对题数, {4}-游玩次数'),
144
+ totalStats: koishi_1.Schema.string().default(defaultMessages.rank.totalStats).description('总统计信息\n{0}-总玩家数, {1}-总得分, {2}-总答对, {3}-总游玩'),
145
+ noPermission: koishi_1.Schema.string().default(defaultMessages.rank.noPermission).description('无权限提示'),
146
+ clearSuccess: koishi_1.Schema.string().default(defaultMessages.rank.clearSuccess).description('清零成功提示'),
147
+ showTotalStats: koishi_1.Schema.boolean().default(true).description('是否显示总统计数据'),
148
+ }).description('📊 排行榜消息配置'),
149
+ }).description('📊 排行榜配置'),
150
+ }),
117
151
  koishi_1.Schema.object({
118
152
  guessNumber: koishi_1.Schema.object({
119
- min: koishi_1.Schema.number().min(0).default(0).description('猜数字最小值'),
120
- max: koishi_1.Schema.number().min(1).default(100).description('猜数字最大值'),
121
- botParticipateInGroup: koishi_1.Schema.boolean().default(true).description('群聊中机器人参与猜数字'),
122
- totalRounds: koishi_1.Schema.number().min(1).default(10).description('猜数字总回合数'),
123
- showRank: koishi_1.Schema.boolean().default(true).description('显示排行榜'),
153
+ min: koishi_1.Schema.number().min(0).default(0).description('最小值'),
154
+ max: koishi_1.Schema.number().min(1).default(100).description('最大值'),
155
+ botParticipateInGroup: koishi_1.Schema.boolean().default(true).description('群聊中机器人是否参与'),
156
+ totalRounds: koishi_1.Schema.number().min(1).default(10).description('总回合数'),
157
+ showRank: koishi_1.Schema.boolean().default(true).description('游戏结束后显示本局排行榜'),
124
158
  autoPlayDelay: koishi_1.Schema.number().min(0).default(10).description('机器人自动操作延迟(秒)'),
125
159
  autoPlayMaxCount: koishi_1.Schema.number().min(1).default(5).description('机器人最大自动操作次数'),
126
160
  autoStopInactiveTime: koishi_1.Schema.number().min(0).default(60).description('游戏无操作自动停止时间(秒)'),
161
+ enablePenalty: koishi_1.Schema.boolean().default(true).description('启用惩罚机制(猜中者扣分,其他人加分)'),
162
+ penaltyScore: koishi_1.Schema.number().max(0).default(-1).description('猜中者扣除分数(负数)'),
163
+ rewardScore: koishi_1.Schema.number().min(0).default(1).description('其他人奖励分数'),
127
164
  messages: koishi_1.Schema.object({
128
- usage: koishi_1.Schema.string().default(defaultMessages.guessNumber.usage).description('用法错误提示'),
129
- start: koishi_1.Schema.string().default(defaultMessages.guessNumber.start).description('游戏开始提示'),
165
+ usage: koishi_1.Schema.string().default(defaultMessages.guessNumber.usage).description('用法错误提示\n{0}-最小值, {1}-最大值'),
166
+ start: koishi_1.Schema.string().default(defaultMessages.guessNumber.start).description('游戏开始提示\n{0}-总回合数'),
130
167
  stop: koishi_1.Schema.string().default(defaultMessages.guessNumber.stop).description('游戏停止提示'),
131
- outOfRange: koishi_1.Schema.string().default(defaultMessages.guessNumber.outOfRange).description('数字超出范围提示'),
132
- tooSmall: koishi_1.Schema.string().default(defaultMessages.guessNumber.tooSmall).description('猜小了提示'),
133
- tooBig: koishi_1.Schema.string().default(defaultMessages.guessNumber.tooBig).description('猜大了提示'),
168
+ outOfRange: koishi_1.Schema.string().default(defaultMessages.guessNumber.outOfRange).description('数字超出范围提示\n{0}-最小值, {1}-最大值'),
169
+ tooSmall: koishi_1.Schema.string().default(defaultMessages.guessNumber.tooSmall).description('猜小了提示\n{0}-新最小值, {1}-新最大值'),
170
+ tooBig: koishi_1.Schema.string().default(defaultMessages.guessNumber.tooBig).description('猜大了提示\n{0}-新最小值, {1}-新最大值'),
134
171
  correct: koishi_1.Schema.string().default(defaultMessages.guessNumber.correct).description('猜中提示'),
135
- roundEnd: koishi_1.Schema.string().default(defaultMessages.guessNumber.roundEnd).description('回合结束提示'),
172
+ roundEnd: koishi_1.Schema.string().default(defaultMessages.guessNumber.roundEnd).description('回合结束提示\n{0}-当前回合, {1}-剩余回合'),
136
173
  gameEnd: koishi_1.Schema.string().default(defaultMessages.guessNumber.gameEnd).description('游戏结束提示'),
137
- rankTitle: koishi_1.Schema.string().default(defaultMessages.guessNumber.rankTitle).description('排行榜标题'),
138
- rankEmpty: koishi_1.Schema.string().default(defaultMessages.guessNumber.rankEmpty).description('排行榜为空提示'),
174
+ rankTitle: koishi_1.Schema.string().default(defaultMessages.guessNumber.rankTitle).description('本局排行榜标题'),
175
+ rankEmpty: koishi_1.Schema.string().default(defaultMessages.guessNumber.rankEmpty).description('本局排行榜为空提示'),
139
176
  disabled: koishi_1.Schema.string().default(defaultMessages.guessNumber.disabled).description('功能禁用提示'),
140
177
  autoStop: koishi_1.Schema.string().default(defaultMessages.guessNumber.autoStop).description('自动停止提示'),
141
- }).description('猜数字消息配置'),
142
- }).description('猜数字游戏配置'),
178
+ }).description('💬 猜数字消息配置'),
179
+ }).description('🎲 猜数字游戏配置'),
143
180
  }),
144
181
  koishi_1.Schema.object({
145
182
  wzHero: koishi_1.Schema.object({
146
- totalRounds: koishi_1.Schema.number().min(1).default(10).description('王者英雄猜谜总回合数'),
147
- showRank: koishi_1.Schema.boolean().default(true).description('显示排行榜'),
183
+ totalRounds: koishi_1.Schema.number().min(1).default(10).description('总回合数'),
184
+ showRank: koishi_1.Schema.boolean().default(true).description('游戏结束后显示本局排行榜'),
148
185
  defaultDifficulty: koishi_1.Schema.union(['简单', '中等', '困难']).default('简单').description('默认难度'),
149
186
  autoStopInactiveTime: koishi_1.Schema.number().min(0).default(60).description('游戏无操作自动停止时间(秒)'),
187
+ rewardScore: koishi_1.Schema.number().min(0).default(1).description('答对奖励分数'),
150
188
  messages: koishi_1.Schema.object({
151
- start: koishi_1.Schema.string().default(defaultMessages.wzHero.start).description('游戏开始提示'),
189
+ usage: koishi_1.Schema.string().default(defaultMessages.wzHero.usage).description('用法错误提示'),
190
+ start: koishi_1.Schema.string().default(defaultMessages.wzHero.start).description('游戏开始提示\n{0}-总回合数, {1}-难度'),
152
191
  startUsage: koishi_1.Schema.string().default(defaultMessages.wzHero.startUsage).description('开始用法提示'),
153
192
  stop: koishi_1.Schema.string().default(defaultMessages.wzHero.stop).description('游戏停止提示'),
154
193
  notStarted: koishi_1.Schema.string().default(defaultMessages.wzHero.notStarted).description('游戏未开始提示'),
155
194
  hint: koishi_1.Schema.string().default(defaultMessages.wzHero.hint).description('提示命令'),
156
195
  apiError: koishi_1.Schema.string().default(defaultMessages.wzHero.apiError).description('API错误提示'),
157
- correct: koishi_1.Schema.string().default(defaultMessages.wzHero.correct).description('答对提示'),
158
- wrong: koishi_1.Schema.string().default(defaultMessages.wzHero.wrong).description('答错提示'),
159
- roundEnd: koishi_1.Schema.string().default(defaultMessages.wzHero.roundEnd).description('回合结束提示'),
196
+ correct: koishi_1.Schema.string().default(defaultMessages.wzHero.correct).description('答对提示\n{0}-当前得分'),
197
+ wrong: koishi_1.Schema.string().default(defaultMessages.wzHero.wrong).description('答错提示\n{0}-正确答案'),
198
+ roundEnd: koishi_1.Schema.string().default(defaultMessages.wzHero.roundEnd).description('回合结束提示\n{0}-当前回合, {1}-剩余回合'),
160
199
  gameEnd: koishi_1.Schema.string().default(defaultMessages.wzHero.gameEnd).description('游戏结束提示'),
161
- rankTitle: koishi_1.Schema.string().default(defaultMessages.wzHero.rankTitle).description('排行榜标题'),
162
- rankEmpty: koishi_1.Schema.string().default(defaultMessages.wzHero.rankEmpty).description('排行榜为空提示'),
200
+ rankTitle: koishi_1.Schema.string().default(defaultMessages.wzHero.rankTitle).description('本局排行榜标题'),
201
+ rankEmpty: koishi_1.Schema.string().default(defaultMessages.wzHero.rankEmpty).description('本局排行榜为空提示'),
163
202
  disabled: koishi_1.Schema.string().default(defaultMessages.wzHero.disabled).description('功能禁用提示'),
164
203
  autoStop: koishi_1.Schema.string().default(defaultMessages.wzHero.autoStop).description('自动停止提示'),
165
- }).description('王者英雄猜谜消息配置'),
166
- }).description('王者英雄猜谜游戏配置'),
204
+ }).description('💬 王者英雄猜谜消息配置'),
205
+ }).description('⚔️ 王者英雄猜谜配置'),
167
206
  }),
168
207
  koishi_1.Schema.object({
169
208
  chengyuImage: koishi_1.Schema.object({
170
- totalRounds: koishi_1.Schema.number().min(1).default(10).description('看图猜成语总回合数'),
171
- showRank: koishi_1.Schema.boolean().default(true).description('显示排行榜'),
172
- defaultHintLevel: koishi_1.Schema.union([1, 2, 3, 4, 5]).default(1).description('默认提示级别(1-5)'),
209
+ totalRounds: koishi_1.Schema.number().min(1).default(10).description('总回合数'),
210
+ showRank: koishi_1.Schema.boolean().default(true).description('游戏结束后显示本局排行榜'),
211
+ defaultHintLevel: koishi_1.Schema.union([1, 2, 3, 4, 5]).default(1).description('默认提示级别'),
173
212
  autoStopInactiveTime: koishi_1.Schema.number().min(0).default(60).description('游戏无操作自动停止时间(秒)'),
213
+ rewardScore: koishi_1.Schema.number().min(0).default(1).description('答对奖励分数'),
174
214
  messages: koishi_1.Schema.object({
175
- start: koishi_1.Schema.string().default(defaultMessages.chengyuImage.start).description('游戏开始提示'),
215
+ usage: koishi_1.Schema.string().default(defaultMessages.chengyuImage.usage).description('用法错误提示'),
216
+ start: koishi_1.Schema.string().default(defaultMessages.chengyuImage.start).description('游戏开始提示\n{0}-总回合数, {1}-提示级别'),
176
217
  stop: koishi_1.Schema.string().default(defaultMessages.chengyuImage.stop).description('游戏停止提示'),
177
218
  submitUsage: koishi_1.Schema.string().default(defaultMessages.chengyuImage.submitUsage).description('提交答案用法提示'),
178
219
  notStarted: koishi_1.Schema.string().default(defaultMessages.chengyuImage.notStarted).description('游戏未开始提示'),
179
- next: koishi_1.Schema.string().default(defaultMessages.chengyuImage.next).description('下一题提示'),
180
- hintGet: koishi_1.Schema.string().default(defaultMessages.chengyuImage.hintGet).description('获取提示成功'),
220
+ next: koishi_1.Schema.string().default(defaultMessages.chengyuImage.next).description('下一题提示\n{0}-当前回合'),
221
+ hintGet: koishi_1.Schema.string().default(defaultMessages.chengyuImage.hintGet).description('获取提示成功\n{0}-提示内容'),
181
222
  hintError: koishi_1.Schema.string().default(defaultMessages.chengyuImage.hintError).description('获取提示失败'),
182
223
  apiError: koishi_1.Schema.string().default(defaultMessages.chengyuImage.apiError).description('API错误提示'),
183
- correct: koishi_1.Schema.string().default(defaultMessages.chengyuImage.correct).description('答对提示'),
184
- wrong: koishi_1.Schema.string().default(defaultMessages.chengyuImage.wrong).description('答错提示'),
185
- roundEnd: koishi_1.Schema.string().default(defaultMessages.chengyuImage.roundEnd).description('回合结束提示'),
224
+ correct: koishi_1.Schema.string().default(defaultMessages.chengyuImage.correct).description('答对提示\n{0}-当前得分'),
225
+ wrong: koishi_1.Schema.string().default(defaultMessages.chengyuImage.wrong).description('答错提示\n{0}-正确答案, {1}-当前得分'),
226
+ roundEnd: koishi_1.Schema.string().default(defaultMessages.chengyuImage.roundEnd).description('回合结束提示\n{0}-当前回合, {1}-剩余回合'),
186
227
  gameEnd: koishi_1.Schema.string().default(defaultMessages.chengyuImage.gameEnd).description('游戏结束提示'),
187
- rankTitle: koishi_1.Schema.string().default(defaultMessages.chengyuImage.rankTitle).description('排行榜标题'),
188
- rankEmpty: koishi_1.Schema.string().default(defaultMessages.chengyuImage.rankEmpty).description('排行榜为空提示'),
228
+ rankTitle: koishi_1.Schema.string().default(defaultMessages.chengyuImage.rankTitle).description('本局排行榜标题'),
229
+ rankEmpty: koishi_1.Schema.string().default(defaultMessages.chengyuImage.rankEmpty).description('本局排行榜为空提示'),
189
230
  disabled: koishi_1.Schema.string().default(defaultMessages.chengyuImage.disabled).description('功能禁用提示'),
190
231
  autoStop: koishi_1.Schema.string().default(defaultMessages.chengyuImage.autoStop).description('自动停止提示'),
191
- }).description('看图猜成语消息配置'),
192
- }).description('看图猜成语游戏配置'),
232
+ }).description('💬 看图猜成语消息配置'),
233
+ }).description('🖼️ 看图猜成语配置'),
193
234
  }),
194
235
  koishi_1.Schema.object({
195
236
  chengyuJielong: koishi_1.Schema.object({
196
- botParticipateInGroup: koishi_1.Schema.boolean().default(true).description('群聊中机器人参与成语接龙'),
197
- totalRounds: koishi_1.Schema.number().min(1).default(10).description('成语接龙总回合数'),
198
- showRank: koishi_1.Schema.boolean().default(true).description('显示排行榜'),
237
+ totalRounds: koishi_1.Schema.number().min(1).default(10).description('总回合数'),
238
+ showRank: koishi_1.Schema.boolean().default(true).description('游戏结束后显示本局排行榜'),
199
239
  autoPlayDelay: koishi_1.Schema.number().min(0).default(10).description('机器人自动操作延迟(秒)'),
200
240
  autoPlayMaxCount: koishi_1.Schema.number().min(1).default(5).description('机器人最大自动操作次数'),
201
241
  autoStopInactiveTime: koishi_1.Schema.number().min(0).default(60).description('游戏无操作自动停止时间(秒)'),
242
+ maxRounds: koishi_1.Schema.number().min(0).default(10).description('最大接龙回合数(0为无限)'),
243
+ botParticipate: koishi_1.Schema.boolean().default(false).description('机器人是否参与接龙'),
244
+ rewardScore: koishi_1.Schema.number().min(0).default(1).description('接龙成功奖励分数'),
202
245
  messages: koishi_1.Schema.object({
203
- start: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.start).description('游戏开始提示'),
246
+ usage: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.usage).description('用法错误提示'),
247
+ start: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.start).description('游戏开始提示\n{0}-总回合数'),
204
248
  stop: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.stop).description('游戏停止提示'),
205
249
  notStarted: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.notStarted).description('游戏未开始提示'),
206
250
  joinUsage: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.joinUsage).description('参与用法提示'),
207
251
  apiError: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.apiError).description('API错误提示'),
208
- botTurn: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.botTurn).description('机器人回合提示'),
252
+ botTurn: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.botTurn).description('机器人回合提示\n{0}-成语'),
209
253
  botWin: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.botWin).description('机器人赢提示'),
210
- autoPlayTooMany: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.autoPlayTooMany).description('自动参与次数过多提示'),
211
- gameInactiveStop: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.gameInactiveStop).description('游戏无操作停止提示'),
254
+ autoPlayTooMany: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.autoPlayTooMany).description('自动参与次数过多提示\n{0}-最大次数'),
212
255
  notIdiom: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.notIdiom).description('非成语提示'),
213
256
  correct: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.correct).description('接龙成功提示'),
214
257
  wrong: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.wrong).description('接龙失败提示'),
215
- roundEnd: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.roundEnd).description('回合结束提示'),
258
+ roundEnd: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.roundEnd).description('回合结束提示\n{0}-当前回合, {1}-剩余回合'),
216
259
  gameEnd: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.gameEnd).description('游戏结束提示'),
217
- rankTitle: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.rankTitle).description('排行榜标题'),
218
- rankEmpty: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.rankEmpty).description('排行榜为空提示'),
260
+ rankTitle: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.rankTitle).description('本局排行榜标题'),
261
+ rankEmpty: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.rankEmpty).description('本局排行榜为空提示'),
219
262
  disabled: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.disabled).description('功能禁用提示'),
220
263
  autoStop: koishi_1.Schema.string().default(defaultMessages.chengyuJielong.autoStop).description('自动停止提示'),
221
- }).description('成语接龙消息配置'),
222
- }).description('成语接龙游戏配置'),
264
+ }).description('💬 成语接龙消息配置'),
265
+ }).description('🐉 成语接龙配置'),
223
266
  }),
224
267
  koishi_1.Schema.object({
225
268
  calc24: koishi_1.Schema.object({
226
- totalRounds: koishi_1.Schema.number().min(1).default(5).description('算24点总回合数'),
227
- showRank: koishi_1.Schema.boolean().default(true).description('显示排行榜'),
269
+ totalRounds: koishi_1.Schema.number().min(1).default(5).description('总回合数'),
270
+ showRank: koishi_1.Schema.boolean().default(true).description('游戏结束后显示本局排行榜'),
228
271
  defaultDifficulty: koishi_1.Schema.union(['简单', '中等', '困难']).default('中等').description('默认难度'),
229
272
  difficultyLevels: koishi_1.Schema.object({
230
273
  easy: koishi_1.Schema.object({
231
274
  min: koishi_1.Schema.number().default(1).description('最小值'),
232
275
  max: koishi_1.Schema.number().default(8).description('最大值'),
233
- }).description('简单难度'),
276
+ }).description('简单难度数字范围'),
234
277
  medium: koishi_1.Schema.object({
235
278
  min: koishi_1.Schema.number().default(1).description('最小值'),
236
279
  max: koishi_1.Schema.number().default(10).description('最大值'),
237
- }).description('中等难度'),
280
+ }).description('中等难度数字范围'),
238
281
  hard: koishi_1.Schema.object({
239
282
  min: koishi_1.Schema.number().default(1).description('最小值'),
240
283
  max: koishi_1.Schema.number().default(13).description('最大值'),
241
- }).description('困难难度'),
242
- }).description('难度等级配置'),
284
+ }).description('困难难度数字范围'),
285
+ }).description('各难度数字范围配置'),
243
286
  autoStopInactiveTime: koishi_1.Schema.number().min(0).default(60).description('游戏无操作自动停止时间(秒)'),
287
+ rewardScore: koishi_1.Schema.number().min(0).default(1).description('答对奖励分数'),
244
288
  messages: koishi_1.Schema.object({
245
- start: koishi_1.Schema.string().default(defaultMessages.calc24.start).description('游戏开始提示'),
289
+ usage: koishi_1.Schema.string().default(defaultMessages.calc24.usage).description('用法错误提示'),
290
+ start: koishi_1.Schema.string().default(defaultMessages.calc24.start).description('游戏开始提示\n{0}-总回合数, {1}-难度'),
246
291
  stop: koishi_1.Schema.string().default(defaultMessages.calc24.stop).description('游戏停止提示'),
247
292
  notStarted: koishi_1.Schema.string().default(defaultMessages.calc24.notStarted).description('游戏未开始提示'),
248
- generate: koishi_1.Schema.string().default(defaultMessages.calc24.generate).description('生成题目提示'),
293
+ generate: koishi_1.Schema.string().default(defaultMessages.calc24.generate).description('生成题目提示\n{0}-当前回合, {1}-难度, {2}-数字列表'),
249
294
  correct: koishi_1.Schema.string().default(defaultMessages.calc24.correct).description('答对提示'),
250
295
  wrong: koishi_1.Schema.string().default(defaultMessages.calc24.wrong).description('答错提示'),
251
- impossible: koishi_1.Schema.string().default(defaultMessages.calc24.impossible).description('无解提示'),
252
296
  solved: koishi_1.Schema.string().default(defaultMessages.calc24.solved).description('已解决提示'),
253
- roundEnd: koishi_1.Schema.string().default(defaultMessages.calc24.roundEnd).description('回合结束提示'),
297
+ roundEnd: koishi_1.Schema.string().default(defaultMessages.calc24.roundEnd).description('回合结束提示\n{0}-当前回合, {1}-剩余回合'),
254
298
  gameEnd: koishi_1.Schema.string().default(defaultMessages.calc24.gameEnd).description('游戏结束提示'),
255
- rankTitle: koishi_1.Schema.string().default(defaultMessages.calc24.rankTitle).description('排行榜标题'),
256
- rankEmpty: koishi_1.Schema.string().default(defaultMessages.calc24.rankEmpty).description('排行榜为空提示'),
299
+ rankTitle: koishi_1.Schema.string().default(defaultMessages.calc24.rankTitle).description('本局排行榜标题'),
300
+ rankEmpty: koishi_1.Schema.string().default(defaultMessages.calc24.rankEmpty).description('本局排行榜为空提示'),
257
301
  disabled: koishi_1.Schema.string().default(defaultMessages.calc24.disabled).description('功能禁用提示'),
258
302
  autoStop: koishi_1.Schema.string().default(defaultMessages.calc24.autoStop).description('自动停止提示'),
259
- }).description('算24点消息配置'),
260
- }).description('算24点游戏配置'),
303
+ }).description('💬 算24点消息配置'),
304
+ }).description('🧮 算24点配置'),
261
305
  }),
262
306
  koishi_1.Schema.object({
263
307
  apiConfig: koishi_1.Schema.object({
264
308
  timeout: koishi_1.Schema.number().default(5000).description('API请求超时时间(毫秒)'),
265
- }).description('API接口配置'),
309
+ }).description('🌐 API接口配置'),
310
+ }),
311
+ koishi_1.Schema.object({
266
312
  commonMessages: koishi_1.Schema.object({
267
313
  gameRunning: koishi_1.Schema.string().default(defaultMessages.common.gameRunning).description('游戏运行中提示'),
268
314
  gameStoppedByInactive: koishi_1.Schema.string().default(defaultMessages.common.gameStoppedByInactive).description('无操作停止提示'),
269
315
  paramError: koishi_1.Schema.string().default(defaultMessages.common.paramError).description('参数错误提示'),
270
- }).description('通用消息配置'),
316
+ }).description('💬 通用消息配置'),
271
317
  }),
272
318
  ]);
273
319
  const logger = new koishi_1.Logger('game-mini');
@@ -278,232 +324,29 @@ const getIntUserId = (session) => {
278
324
  const hash = userIdStr.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
279
325
  return hash || 1000000;
280
326
  };
281
- const getPlayerData = (session) => {
282
- const safeUserId = session.userId || 'unknown_user';
283
- return {
284
- platform: session.platform,
285
- userId: safeUserId,
286
- name: session.username || safeUserId || '未知用户',
287
- score: 0,
288
- correctCount: 0
289
- };
290
- };
291
- const checkGameRunning = (s, t) => {
292
- if (t !== 'guessNumber' && s.guessNumber.started)
293
- return true;
294
- if (t !== 'wzHero' && s.wzHero.started)
295
- return true;
296
- if (t !== 'chengyuImage' && s.chengyuImage.started)
297
- return true;
298
- if (t !== 'chengyuJielong' && s.chengyuJielong.started)
299
- return true;
300
- if (t !== 'calc24' && s.calc24.started)
301
- return true;
302
- return false;
303
- };
304
- const clearGameTimer = (state) => {
305
- if (state.stopTimer)
306
- clearTimeout(state.stopTimer);
307
- if (state.autoPlayTimer)
308
- clearTimeout(state.autoPlayTimer);
309
- };
310
- const clearAllTimers = (st) => {
311
- clearGameTimer(st.guessNumber);
312
- clearGameTimer(st.wzHero);
313
- clearGameTimer(st.chengyuImage);
314
- clearGameTimer(st.chengyuJielong);
315
- clearGameTimer(st.calc24);
316
- };
317
- const initState = (key, c) => {
318
- const s = {
319
- guessNumber: {
320
- started: false,
321
- totalRounds: c.guessNumber.totalRounds,
322
- currentRound: 0,
323
- players: {},
324
- participants: [],
325
- target: 0,
326
- currentMin: c.guessNumber.min,
327
- currentMax: c.guessNumber.max,
328
- botGuess: []
329
- },
330
- wzHero: {
331
- started: false,
332
- totalRounds: c.wzHero.totalRounds,
333
- currentRound: 0,
334
- players: {},
335
- participants: [],
336
- difficulty: c.wzHero.defaultDifficulty,
337
- botAnswered: false,
338
- lastHint: '',
339
- currentHeroId: '',
340
- currentAnswer: ''
341
- },
342
- chengyuImage: {
343
- started: false,
344
- totalRounds: c.chengyuImage.totalRounds,
345
- currentRound: 0,
346
- players: {},
347
- participants: [],
348
- currentId: '',
349
- currentPage: 1,
350
- options: [],
351
- answer: ''
352
- },
353
- chengyuJielong: {
354
- started: false,
355
- totalRounds: c.chengyuJielong.totalRounds,
356
- currentRound: 0,
357
- players: {},
358
- participants: [],
359
- lastChar: '',
360
- botTurn: true,
361
- autoPlayCount: 0,
362
- hasTriggeredAutoPlay: false,
363
- lastActiveTime: Date.now()
364
- },
365
- calc24: {
366
- started: false,
367
- totalRounds: c.calc24.totalRounds,
368
- currentRound: 0,
369
- players: {},
370
- participants: [],
371
- difficulty: c.calc24.defaultDifficulty,
372
- numbers: [],
373
- playerAnswer: '',
374
- solved: false,
375
- availableNumbers: []
376
- }
377
- };
378
- gameStates.set(key, s);
379
- return s;
380
- };
381
- const isFourCharIdiom = (text) => {
382
- const t = text.trim();
383
- return /^[\u4e00-\u9fa5]{4}$/.test(t);
384
- };
385
- const generateRankText = (players, rankTitle, rankEmpty) => {
386
- const playerList = Object.values(players);
387
- if (playerList.length === 0) {
388
- return `${rankTitle}\n${rankEmpty}`;
389
- }
390
- const sortedPlayers = playerList.sort((a, b) => b.score - a.score);
391
- let rankText = `${rankTitle}\n`;
392
- sortedPlayers.forEach((player, index) => {
393
- rankText += `${index + 1}. ${player.name} - 得分:${player.score}分(答对${player.correctCount}题)\n`;
394
- });
395
- return rankText.trim();
396
- };
397
- const clearGameData = (gameState, showRank = false, session, rankTitle, rankEmpty) => {
398
- if (showRank && session && session.channelId && rankTitle && rankEmpty) {
399
- session.send(generateRankText(gameState.players, rankTitle, rankEmpty));
400
- }
401
- gameState.players = {};
402
- gameState.participants = [];
403
- gameState.currentRound = 0;
404
- gameState.started = false;
405
- clearGameTimer(gameState);
406
- };
407
- const addScoreToOthers = (players, excludePlayerKey) => {
408
- Object.keys(players).forEach(playerKey => {
409
- if (playerKey !== excludePlayerKey) {
410
- players[playerKey].score += 1;
411
- }
327
+ async function apply(ctx, cfg) {
328
+ ctx.model.extend('game_mini_player', {
329
+ id: 'unsigned',
330
+ guildId: 'string',
331
+ platform: 'string',
332
+ userId: 'string',
333
+ name: 'string',
334
+ score: 'integer',
335
+ correctCount: 'integer',
336
+ playCount: 'integer',
337
+ lastGameTime: 'unsigned'
338
+ }, {
339
+ primary: 'id',
340
+ autoInc: true,
341
+ unique: [['guildId', 'platform', 'userId']]
412
342
  });
413
- };
414
- const setupAutoStop = (session, state, cfg, gameType, endMsg, showRank, rankTitle, rankEmpty) => {
415
- clearGameTimer(state);
416
- let inactiveTime = 60;
417
- if (gameType === 'guessNumber')
418
- inactiveTime = cfg.guessNumber.autoStopInactiveTime;
419
- else if (gameType === 'wzHero')
420
- inactiveTime = cfg.wzHero.autoStopInactiveTime;
421
- else if (gameType === 'chengyuImage')
422
- inactiveTime = cfg.chengyuImage.autoStopInactiveTime;
423
- else if (gameType === 'chengyuJielong')
424
- inactiveTime = cfg.chengyuJielong.autoStopInactiveTime;
425
- else if (gameType === 'calc24')
426
- inactiveTime = cfg.calc24.autoStopInactiveTime;
427
- if (inactiveTime <= 0)
428
- return;
429
- state.stopTimer = setTimeout(() => {
430
- clearGameData(state, showRank, session, rankTitle, rankEmpty);
431
- session.send(endMsg);
432
- }, inactiveTime * 1000);
433
- };
434
- const calculate24 = (numbers) => {
435
- if (numbers.length === 1)
436
- return Math.abs(numbers[0] - 24) < 0.001;
437
- for (let i = 0; i < numbers.length; i++) {
438
- for (let j = 0; j < numbers.length; j++) {
439
- if (i === j)
440
- continue;
441
- const rest = [];
442
- for (let k = 0; k < numbers.length; k++) {
443
- if (k !== i && k !== j)
444
- rest.push(numbers[k]);
445
- }
446
- const a = numbers[i];
447
- const b = numbers[j];
448
- if (calculate24([...rest, a + b]))
449
- return true;
450
- if (calculate24([...rest, a - b]))
451
- return true;
452
- if (calculate24([...rest, b - a]))
453
- return true;
454
- if (calculate24([...rest, a * b]))
455
- return true;
456
- if (b !== 0 && calculate24([...rest, a / b]))
457
- return true;
458
- if (a !== 0 && calculate24([...rest, b / a]))
459
- return true;
460
- }
461
- }
462
- return false;
463
- };
464
- const generateSolvable24Numbers = (min, max) => {
465
- const maxAttempts = 1000;
466
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
467
- const numbers = [
468
- koishi_1.Random.int(min, max + 1),
469
- koishi_1.Random.int(min, max + 1),
470
- koishi_1.Random.int(min, max + 1),
471
- koishi_1.Random.int(min, max + 1)
472
- ];
473
- if (calculate24([...numbers])) {
474
- return numbers;
475
- }
476
- }
477
- return [6, 4, 3, 1];
478
- };
479
- const evaluateExpression = (expr) => {
480
- try {
481
- let cleanExpr = expr.replace(/\s+/g, '');
482
- cleanExpr = cleanExpr.replace(/[×xX]/g, '*');
483
- cleanExpr = cleanExpr.replace(/[÷/]/g, '/');
484
- cleanExpr = cleanExpr.replace(/\/\//g, '/');
485
- if (!/^[\d\+\-\*\/\(\)\[\]\{\}]+$/.test(cleanExpr)) {
486
- return null;
487
- }
488
- const normalizedExpr = cleanExpr.replace(/[\[\{]/g, '(').replace(/[\]\}]/g, ')');
489
- const func = new Function('return ' + normalizedExpr);
490
- const result = func();
491
- if (typeof result === 'number' && isFinite(result)) {
492
- return result;
493
- }
494
- return null;
495
- }
496
- catch {
497
- return null;
498
- }
499
- };
500
- function apply(ctx, cfg) {
501
343
  const d = {
502
344
  guessNumber: cfg.guessNumber.messages,
503
345
  wzHero: cfg.wzHero.messages,
504
346
  chengyuImage: cfg.chengyuImage.messages,
505
347
  chengyuJielong: cfg.chengyuJielong.messages,
506
348
  calc24: cfg.calc24.messages,
349
+ rank: cfg.rank.messages,
507
350
  common: cfg.commonMessages
508
351
  };
509
352
  try {
@@ -517,6 +360,318 @@ function apply(ctx, cfg) {
517
360
  ctx.i18n.define('zh-CN', d);
518
361
  }
519
362
  const isPrivate = (s) => !s.channelId;
363
+ const canPlayPrivate = (game) => {
364
+ if (game === 'guessNumber')
365
+ return cfg.privateGame.enableNumberGuess;
366
+ if (game === 'wzHero')
367
+ return cfg.privateGame.enableWzHero;
368
+ if (game === 'chengyuImage')
369
+ return cfg.privateGame.enableChengyuImage;
370
+ if (game === 'chengyuJielong')
371
+ return cfg.privateGame.enableChengyuJielong;
372
+ if (game === 'calc24')
373
+ return cfg.privateGame.enableCalc24;
374
+ return false;
375
+ };
376
+ const getPlayerData = async (session) => {
377
+ if (!session.channelId) {
378
+ return {
379
+ platform: session.platform,
380
+ userId: session.userId || 'unknown_user',
381
+ name: session.username || session.userId || '未知用户',
382
+ score: 0,
383
+ correctCount: 0,
384
+ playCount: 0,
385
+ lastGameTime: 0
386
+ };
387
+ }
388
+ const guildId = session.channelId;
389
+ const platform = session.platform;
390
+ const userId = session.userId || 'unknown_user';
391
+ const name = session.username || userId;
392
+ let player = await ctx.database.get('game_mini_player', {
393
+ guildId,
394
+ platform,
395
+ userId
396
+ });
397
+ if (!player.length) {
398
+ const newPlayer = {
399
+ guildId,
400
+ platform,
401
+ userId,
402
+ name,
403
+ score: 0,
404
+ correctCount: 0,
405
+ playCount: 0,
406
+ lastGameTime: 0
407
+ };
408
+ await ctx.database.create('game_mini_player', newPlayer);
409
+ return {
410
+ guildId,
411
+ platform,
412
+ userId,
413
+ name,
414
+ score: 0,
415
+ correctCount: 0,
416
+ playCount: 0,
417
+ lastGameTime: 0
418
+ };
419
+ }
420
+ return player[0];
421
+ };
422
+ const savePlayerData = async (session, playerData) => {
423
+ if (!session.channelId)
424
+ return;
425
+ await ctx.database.set('game_mini_player', { guildId: session.channelId, platform: session.platform, userId: session.userId }, {
426
+ name: playerData.name,
427
+ score: playerData.score,
428
+ correctCount: playerData.correctCount,
429
+ playCount: playerData.playCount,
430
+ lastGameTime: playerData.lastGameTime
431
+ });
432
+ };
433
+ const updatePlayerPlayCount = async (session) => {
434
+ if (!session.channelId)
435
+ return;
436
+ const player = await getPlayerData(session);
437
+ player.playCount += 1;
438
+ player.lastGameTime = Date.now();
439
+ await savePlayerData(session, player);
440
+ };
441
+ const generateTotalRankText = async (session) => {
442
+ if (!session.channelId)
443
+ return cfg.rank.messages.empty;
444
+ const players = await ctx.database.get('game_mini_player', { guildId: session.channelId });
445
+ if (players.length === 0) {
446
+ return cfg.rank.messages.empty;
447
+ }
448
+ const sortedPlayers = players.sort((a, b) => b.score - a.score);
449
+ let rankText = cfg.rank.messages.title + '\n';
450
+ const displayCount = Math.min(cfg.rank.maxDisplay, sortedPlayers.length);
451
+ for (let i = 0; i < displayCount; i++) {
452
+ const player = sortedPlayers[i];
453
+ rankText += cfg.rank.messages.playerInfo
454
+ .replace('{0}', String(i + 1))
455
+ .replace('{1}', player.name)
456
+ .replace('{2}', String(player.score))
457
+ .replace('{3}', String(player.correctCount))
458
+ .replace('{4}', String(player.playCount)) + '\n';
459
+ }
460
+ if (cfg.rank.messages.showTotalStats) {
461
+ const totalScore = players.reduce((sum, p) => sum + p.score, 0);
462
+ const totalCorrect = players.reduce((sum, p) => sum + p.correctCount, 0);
463
+ const totalPlay = players.reduce((sum, p) => sum + p.playCount, 0);
464
+ rankText += cfg.rank.messages.totalStats
465
+ .replace('{0}', String(players.length))
466
+ .replace('{1}', String(totalScore))
467
+ .replace('{2}', String(totalCorrect))
468
+ .replace('{3}', String(totalPlay));
469
+ }
470
+ return rankText;
471
+ };
472
+ const checkGameRunning = (s, t) => {
473
+ if (t !== 'guessNumber' && s.guessNumber.started)
474
+ return true;
475
+ if (t !== 'wzHero' && s.wzHero.started)
476
+ return true;
477
+ if (t !== 'chengyuImage' && s.chengyuImage.started)
478
+ return true;
479
+ if (t !== 'chengyuJielong' && s.chengyuJielong.started)
480
+ return true;
481
+ if (t !== 'calc24' && s.calc24.started)
482
+ return true;
483
+ return false;
484
+ };
485
+ const clearGameTimer = (state) => {
486
+ if (state.stopTimer)
487
+ clearTimeout(state.stopTimer);
488
+ if (state.autoPlayTimer)
489
+ clearTimeout(state.autoPlayTimer);
490
+ };
491
+ const clearAllTimers = (st) => {
492
+ clearGameTimer(st.guessNumber);
493
+ clearGameTimer(st.wzHero);
494
+ clearGameTimer(st.chengyuImage);
495
+ clearGameTimer(st.chengyuJielong);
496
+ clearGameTimer(st.calc24);
497
+ };
498
+ const initState = (key) => {
499
+ const s = {
500
+ guessNumber: {
501
+ started: false,
502
+ totalRounds: cfg.guessNumber.totalRounds,
503
+ currentRound: 0,
504
+ players: {},
505
+ participants: [],
506
+ target: 0,
507
+ currentMin: cfg.guessNumber.min,
508
+ currentMax: cfg.guessNumber.max,
509
+ botGuess: []
510
+ },
511
+ wzHero: {
512
+ started: false,
513
+ totalRounds: cfg.wzHero.totalRounds,
514
+ currentRound: 0,
515
+ players: {},
516
+ participants: [],
517
+ difficulty: cfg.wzHero.defaultDifficulty,
518
+ botAnswered: false,
519
+ lastHint: '',
520
+ currentHeroId: '',
521
+ currentAnswer: ''
522
+ },
523
+ chengyuImage: {
524
+ started: false,
525
+ totalRounds: cfg.chengyuImage.totalRounds,
526
+ currentRound: 0,
527
+ players: {},
528
+ participants: [],
529
+ currentId: '',
530
+ currentPage: 1,
531
+ options: [],
532
+ answer: ''
533
+ },
534
+ chengyuJielong: {
535
+ started: false,
536
+ totalRounds: cfg.chengyuJielong.totalRounds,
537
+ currentRound: 0,
538
+ players: {},
539
+ participants: [],
540
+ lastChar: '',
541
+ botTurn: true,
542
+ autoPlayCount: 0,
543
+ hasTriggeredAutoPlay: false,
544
+ lastActiveTime: Date.now(),
545
+ jielongCount: 0
546
+ },
547
+ calc24: {
548
+ started: false,
549
+ totalRounds: cfg.calc24.totalRounds,
550
+ currentRound: 0,
551
+ players: {},
552
+ participants: [],
553
+ difficulty: cfg.calc24.defaultDifficulty,
554
+ numbers: [],
555
+ playerAnswer: '',
556
+ solved: false,
557
+ availableNumbers: []
558
+ }
559
+ };
560
+ gameStates.set(key, s);
561
+ return s;
562
+ };
563
+ const isFourCharIdiom = (text) => {
564
+ const t = text.trim();
565
+ return /^[\u4e00-\u9fa5]{4}$/.test(t);
566
+ };
567
+ const generateGameRankText = (players, rankTitle, rankEmpty) => {
568
+ const playerList = Object.values(players);
569
+ if (playerList.length === 0) {
570
+ return `${rankTitle}\n${rankEmpty}`;
571
+ }
572
+ const sortedPlayers = playerList.sort((a, b) => b.score - a.score);
573
+ let rankText = `${rankTitle}\n`;
574
+ sortedPlayers.forEach((player, index) => {
575
+ rankText += `${index + 1}. ${player.name} - 得分:${player.score}分\n`;
576
+ });
577
+ return rankText.trim();
578
+ };
579
+ const clearGameData = (gameState, showRank = false, session, rankTitle, rankEmpty) => {
580
+ if (showRank && session && session.channelId && rankTitle && rankEmpty) {
581
+ session.send(generateGameRankText(gameState.players, rankTitle, rankEmpty));
582
+ }
583
+ gameState.players = {};
584
+ gameState.participants = [];
585
+ gameState.currentRound = 0;
586
+ gameState.started = false;
587
+ clearGameTimer(gameState);
588
+ };
589
+ const setupAutoStop = (session, state, gameType, endMsg, showRank, rankTitle, rankEmpty) => {
590
+ clearGameTimer(state);
591
+ let inactiveTime = 60;
592
+ if (gameType === 'guessNumber')
593
+ inactiveTime = cfg.guessNumber.autoStopInactiveTime;
594
+ else if (gameType === 'wzHero')
595
+ inactiveTime = cfg.wzHero.autoStopInactiveTime;
596
+ else if (gameType === 'chengyuImage')
597
+ inactiveTime = cfg.chengyuImage.autoStopInactiveTime;
598
+ else if (gameType === 'chengyuJielong')
599
+ inactiveTime = cfg.chengyuJielong.autoStopInactiveTime;
600
+ else if (gameType === 'calc24')
601
+ inactiveTime = cfg.calc24.autoStopInactiveTime;
602
+ if (inactiveTime <= 0)
603
+ return;
604
+ state.stopTimer = setTimeout(() => {
605
+ clearGameData(state, showRank, session, rankTitle, rankEmpty);
606
+ session.send(endMsg);
607
+ }, inactiveTime * 1000);
608
+ };
609
+ const calculate24 = (numbers) => {
610
+ if (numbers.length === 1)
611
+ return Math.abs(numbers[0] - 24) < 0.001;
612
+ for (let i = 0; i < numbers.length; i++) {
613
+ for (let j = 0; j < numbers.length; j++) {
614
+ if (i === j)
615
+ continue;
616
+ const rest = [];
617
+ for (let k = 0; k < numbers.length; k++) {
618
+ if (k !== i && k !== j)
619
+ rest.push(numbers[k]);
620
+ }
621
+ const a = numbers[i];
622
+ const b = numbers[j];
623
+ if (calculate24([...rest, a + b]))
624
+ return true;
625
+ if (calculate24([...rest, a - b]))
626
+ return true;
627
+ if (calculate24([...rest, b - a]))
628
+ return true;
629
+ if (calculate24([...rest, a * b]))
630
+ return true;
631
+ if (b !== 0 && calculate24([...rest, a / b]))
632
+ return true;
633
+ if (a !== 0 && calculate24([...rest, b / a]))
634
+ return true;
635
+ }
636
+ }
637
+ return false;
638
+ };
639
+ const generateSolvable24Numbers = (min, max) => {
640
+ const maxAttempts = 1000;
641
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
642
+ const numbers = [
643
+ koishi_1.Random.int(min, max + 1),
644
+ koishi_1.Random.int(min, max + 1),
645
+ koishi_1.Random.int(min, max + 1),
646
+ koishi_1.Random.int(min, max + 1)
647
+ ];
648
+ if (calculate24([...numbers])) {
649
+ return numbers;
650
+ }
651
+ }
652
+ return [6, 4, 3, 1];
653
+ };
654
+ const evaluateExpression = (expr) => {
655
+ try {
656
+ let cleanExpr = expr.replace(/\s+/g, '');
657
+ cleanExpr = cleanExpr.replace(/[×xX]/g, '*');
658
+ cleanExpr = cleanExpr.replace(/[÷/]/g, '/');
659
+ cleanExpr = cleanExpr.replace(/\/\//g, '/');
660
+ if (!/^[\d\+\-\*\/\(\)\[\]\{\}]+$/.test(cleanExpr)) {
661
+ return null;
662
+ }
663
+ const normalizedExpr = cleanExpr.replace(/[\[\{]/g, '(').replace(/[\]\}]/g, ')');
664
+ const func = new Function('return ' + normalizedExpr);
665
+ const result = func();
666
+ if (typeof result === 'number' && isFinite(result)) {
667
+ return result;
668
+ }
669
+ return null;
670
+ }
671
+ catch {
672
+ return null;
673
+ }
674
+ };
520
675
  const refreshActive = (st) => {
521
676
  st.chengyuJielong.lastActiveTime = Date.now();
522
677
  };
@@ -526,7 +681,7 @@ function apply(ctx, cfg) {
526
681
  doAutoPlay(session, key, st);
527
682
  return;
528
683
  }
529
- if (!cfg.chengyuJielong.botParticipateInGroup)
684
+ if (!cfg.chengyuJielong.botParticipate)
530
685
  return;
531
686
  if (st.chengyuJielong.hasTriggeredAutoPlay)
532
687
  return;
@@ -541,10 +696,9 @@ function apply(ctx, cfg) {
541
696
  if (st.chengyuJielong.hasTriggeredAutoPlay)
542
697
  return;
543
698
  if (st.chengyuJielong.autoPlayCount >= cfg.chengyuJielong.autoPlayMaxCount) {
544
- session.send(d.chengyuJielong.autoPlayTooMany.replace('{0}', String(cfg.chengyuJielong.autoPlayMaxCount)));
545
699
  st.chengyuJielong.hasTriggeredAutoPlay = true;
546
700
  gameStates.set(key, st);
547
- setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
701
+ setupAutoStop(session, st.chengyuJielong, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
548
702
  return;
549
703
  }
550
704
  st.chengyuJielong.hasTriggeredAutoPlay = true;
@@ -566,8 +720,9 @@ function apply(ctx, cfg) {
566
720
  let m = '';
567
721
  if (dt.code === 200 && dt.data?.system) {
568
722
  const sys = dt.data.system;
569
- m = d.chengyuJielong.botTurn.replace('{0}', sys.idiom).replace('{1}', sys.pinyin).replace('{2}', sys.meaning);
723
+ m = d.chengyuJielong.botTurn.replace('{0}', sys.idiom);
570
724
  st.chengyuJielong.lastChar = dt.data.current_char || '';
725
+ st.chengyuJielong.jielongCount += 1;
571
726
  }
572
727
  else {
573
728
  m = dt.msg || d.chengyuJielong.botWin;
@@ -578,7 +733,7 @@ function apply(ctx, cfg) {
578
733
  await session.send(m);
579
734
  await session.send(d.chengyuJielong.gameEnd);
580
735
  if (cfg.chengyuJielong.showRank && !isPrivate(session)) {
581
- const rankText = generateRankText(st.chengyuJielong.players, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
736
+ const rankText = generateGameRankText(st.chengyuJielong.players, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
582
737
  await session.send(rankText);
583
738
  }
584
739
  clearGameData(st.chengyuJielong);
@@ -589,34 +744,63 @@ function apply(ctx, cfg) {
589
744
  m += '\n' + d.chengyuJielong.roundEnd.replace('{0}', st.chengyuJielong.currentRound.toString()).replace('{1}', (st.chengyuJielong.totalRounds - st.chengyuJielong.currentRound).toString());
590
745
  }
591
746
  }
747
+ if (cfg.chengyuJielong.maxRounds > 0 && st.chengyuJielong.jielongCount >= cfg.chengyuJielong.maxRounds) {
748
+ st.chengyuJielong.started = false;
749
+ clearAllTimers(st);
750
+ await session.send(m);
751
+ await session.send(d.chengyuJielong.gameEnd);
752
+ if (cfg.chengyuJielong.showRank && !isPrivate(session)) {
753
+ const rankText = generateGameRankText(st.chengyuJielong.players, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
754
+ await session.send(rankText);
755
+ }
756
+ clearGameData(st.chengyuJielong);
757
+ gameStates.set(key, st);
758
+ return;
759
+ }
592
760
  await session.send(m);
593
761
  }
594
762
  catch (error) {
595
763
  await session.send(d.chengyuJielong.apiError);
596
764
  }
597
765
  gameStates.set(key, st);
598
- setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
766
+ setupAutoStop(session, st.chengyuJielong, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
599
767
  };
600
768
  ctx.middleware(async (session, next) => {
601
769
  if (!session.content)
602
770
  return next();
603
771
  const key = getSessionKey(session);
604
- const st = gameStates.get(key) || initState(key, cfg);
605
- if (isPrivate(session) && !cfg.enablePrivateGame)
606
- return next();
772
+ const st = gameStates.get(key) || initState(key);
773
+ if (isPrivate(session)) {
774
+ const gameActive = st.guessNumber.started || st.wzHero.started || st.chengyuImage.started || st.chengyuJielong.started || st.calc24.started;
775
+ if (gameActive) {
776
+ if (st.guessNumber.started && !canPlayPrivate('guessNumber'))
777
+ return next();
778
+ if (st.wzHero.started && !canPlayPrivate('wzHero'))
779
+ return next();
780
+ if (st.chengyuImage.started && !canPlayPrivate('chengyuImage'))
781
+ return next();
782
+ if (st.chengyuJielong.started && !canPlayPrivate('chengyuJielong'))
783
+ return next();
784
+ if (st.calc24.started && !canPlayPrivate('calc24'))
785
+ return next();
786
+ }
787
+ }
607
788
  const content = session.content.trim();
608
789
  const playerKey = `${session.platform}_${session.userId || 'unknown'}`;
609
790
  if (cfg.enableChengyuJielong && st.chengyuJielong.started) {
610
791
  refreshActive(st);
611
792
  clearGameTimer(st.chengyuJielong);
612
793
  if (!st.chengyuJielong.players[playerKey]) {
613
- st.chengyuJielong.players[playerKey] = getPlayerData(session);
794
+ const playerData = await getPlayerData(session);
795
+ st.chengyuJielong.players[playerKey] = playerData;
614
796
  st.chengyuJielong.participants.push(playerKey);
797
+ await updatePlayerPlayCount(session);
615
798
  }
616
799
  if (!isFourCharIdiom(content)) {
617
- setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
800
+ await session.send(d.chengyuJielong.notIdiom);
801
+ setupAutoStop(session, st.chengyuJielong, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
618
802
  scheduleAutoPlay(session, key, st);
619
- return next();
803
+ return;
620
804
  }
621
805
  try {
622
806
  const intUserId = getIntUserId(session);
@@ -635,27 +819,41 @@ function apply(ctx, cfg) {
635
819
  if (dt.code === 200) {
636
820
  m = dt.msg + '\n';
637
821
  if (dt.data?.user) {
638
- st.chengyuJielong.players[playerKey].score += 1;
822
+ m += d.chengyuJielong.correct + '\n';
823
+ m += `你的成语:${dt.data.user.idiom}\n`;
824
+ st.chengyuJielong.players[playerKey].score += cfg.chengyuJielong.rewardScore;
639
825
  st.chengyuJielong.players[playerKey].correctCount += 1;
640
- m += d.chengyuJielong.correct.replace('{0}', st.chengyuJielong.players[playerKey].score.toString()) + '\n';
641
- m += `你的成语:${dt.data.user.idiom}(${dt.data.user.pinyin})\n释义:${dt.data.user.meaning}\n`;
826
+ await savePlayerData(session, st.chengyuJielong.players[playerKey]);
642
827
  }
643
828
  else {
644
- addScoreToOthers(st.chengyuJielong.players, playerKey);
645
- m += d.chengyuJielong.wrong.replace('{1}', st.chengyuJielong.players[playerKey].score.toString()) + '\n';
829
+ m += d.chengyuJielong.wrong + '\n';
646
830
  }
647
831
  if (dt.data?.system) {
648
- m += `我的接龙:${dt.data.system.idiom}(${dt.data.system.pinyin})\n释义:${dt.data.system.meaning}`;
832
+ m += `我的接龙:${dt.data.system.idiom}`;
649
833
  st.chengyuJielong.lastChar = dt.data.current_char || '';
834
+ st.chengyuJielong.jielongCount += 1;
650
835
  }
651
836
  st.chengyuJielong.currentRound += 1;
837
+ if (cfg.chengyuJielong.maxRounds > 0 && st.chengyuJielong.jielongCount >= cfg.chengyuJielong.maxRounds) {
838
+ st.chengyuJielong.started = false;
839
+ clearAllTimers(st);
840
+ await session.send(m);
841
+ await session.send(d.chengyuJielong.gameEnd);
842
+ if (cfg.chengyuJielong.showRank && !isPrivate(session)) {
843
+ const rankText = generateGameRankText(st.chengyuJielong.players, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
844
+ await session.send(rankText);
845
+ }
846
+ clearGameData(st.chengyuJielong);
847
+ gameStates.set(key, st);
848
+ return;
849
+ }
652
850
  if (st.chengyuJielong.currentRound > st.chengyuJielong.totalRounds) {
653
851
  st.chengyuJielong.started = false;
654
852
  clearAllTimers(st);
655
853
  await session.send(m);
656
854
  await session.send(d.chengyuJielong.gameEnd);
657
855
  if (cfg.chengyuJielong.showRank && !isPrivate(session)) {
658
- const rankText = generateRankText(st.chengyuJielong.players, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
856
+ const rankText = generateGameRankText(st.chengyuJielong.players, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
659
857
  await session.send(rankText);
660
858
  }
661
859
  clearGameData(st.chengyuJielong);
@@ -664,20 +862,19 @@ function apply(ctx, cfg) {
664
862
  m += '\n' + d.chengyuJielong.roundEnd.replace('{0}', st.chengyuJielong.currentRound.toString()).replace('{1}', (st.chengyuJielong.totalRounds - st.chengyuJielong.currentRound).toString());
665
863
  await session.send(m);
666
864
  st.chengyuJielong.hasTriggeredAutoPlay = false;
667
- setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
865
+ setupAutoStop(session, st.chengyuJielong, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
668
866
  scheduleAutoPlay(session, key, st);
669
867
  }
670
868
  }
671
869
  else {
672
870
  m = dt.msg || '接龙失败';
673
- addScoreToOthers(st.chengyuJielong.players, playerKey);
674
- m += '\n' + d.chengyuJielong.wrong.replace('{1}', st.chengyuJielong.players[playerKey].score.toString());
871
+ m += '\n' + d.chengyuJielong.wrong;
675
872
  await session.send(m);
676
873
  }
677
874
  }
678
875
  catch (error) {
679
876
  await session.send(d.chengyuJielong.apiError);
680
- setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
877
+ setupAutoStop(session, st.chengyuJielong, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
681
878
  scheduleAutoPlay(session, key, st);
682
879
  }
683
880
  gameStates.set(key, st);
@@ -686,8 +883,10 @@ function apply(ctx, cfg) {
686
883
  if (cfg.enableChengyuImage && st.chengyuImage.started) {
687
884
  clearGameTimer(st.chengyuImage);
688
885
  if (!st.chengyuImage.players[playerKey]) {
689
- st.chengyuImage.players[playerKey] = getPlayerData(session);
886
+ const playerData = await getPlayerData(session);
887
+ st.chengyuImage.players[playerKey] = playerData;
690
888
  st.chengyuImage.participants.push(playerKey);
889
+ await updatePlayerPlayCount(session);
691
890
  }
692
891
  if (content === '提示') {
693
892
  try {
@@ -710,12 +909,13 @@ function apply(ctx, cfg) {
710
909
  catch (error) {
711
910
  await session.send(d.chengyuImage.hintError);
712
911
  }
713
- setupAutoStop(session, st.chengyuImage, cfg, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
912
+ setupAutoStop(session, st.chengyuImage, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
714
913
  return;
715
914
  }
716
915
  if (!isFourCharIdiom(content)) {
717
- setupAutoStop(session, st.chengyuImage, cfg, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
718
- return next();
916
+ await session.send('请输入4字成语');
917
+ setupAutoStop(session, st.chengyuImage, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
918
+ return;
719
919
  }
720
920
  try {
721
921
  const r = await axios_1.default.get('https://jcy.lvlong.xyz/api/api/chengyu.php', {
@@ -730,8 +930,9 @@ function apply(ctx, cfg) {
730
930
  if (dt.success) {
731
931
  let reply = '';
732
932
  if (dt.message.includes('正确') || dt.message.includes('答对')) {
733
- st.chengyuImage.players[playerKey].score += 1;
933
+ st.chengyuImage.players[playerKey].score += cfg.chengyuImage.rewardScore;
734
934
  st.chengyuImage.players[playerKey].correctCount += 1;
935
+ await savePlayerData(session, st.chengyuImage.players[playerKey]);
735
936
  reply = d.chengyuImage.correct.replace('{0}', st.chengyuImage.players[playerKey].score.toString());
736
937
  st.chengyuImage.currentRound += 1;
737
938
  if (st.chengyuImage.currentRound > st.chengyuImage.totalRounds) {
@@ -740,7 +941,7 @@ function apply(ctx, cfg) {
740
941
  await session.send(reply);
741
942
  await session.send(d.chengyuImage.gameEnd);
742
943
  if (cfg.chengyuImage.showRank && !isPrivate(session)) {
743
- const rankText = generateRankText(st.chengyuImage.players, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
944
+ const rankText = generateGameRankText(st.chengyuImage.players, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
744
945
  await session.send(rankText);
745
946
  }
746
947
  clearGameData(st.chengyuImage);
@@ -770,7 +971,7 @@ function apply(ctx, cfg) {
770
971
  st.chengyuImage.started = false;
771
972
  clearGameTimer(st.chengyuImage);
772
973
  if (cfg.chengyuImage.showRank && !isPrivate(session)) {
773
- const rankText = generateRankText(st.chengyuImage.players, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
974
+ const rankText = generateGameRankText(st.chengyuImage.players, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
774
975
  await session.send(rankText);
775
976
  }
776
977
  clearGameData(st.chengyuImage);
@@ -790,15 +991,17 @@ function apply(ctx, cfg) {
790
991
  catch (error) {
791
992
  await session.send(d.chengyuImage.apiError);
792
993
  }
793
- setupAutoStop(session, st.chengyuImage, cfg, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
994
+ setupAutoStop(session, st.chengyuImage, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
794
995
  gameStates.set(key, st);
795
996
  return;
796
997
  }
797
998
  if (cfg.enableWzHero && st.wzHero.started) {
798
999
  clearGameTimer(st.wzHero);
799
1000
  if (!st.wzHero.players[playerKey]) {
800
- st.wzHero.players[playerKey] = getPlayerData(session);
1001
+ const playerData = await getPlayerData(session);
1002
+ st.wzHero.players[playerKey] = playerData;
801
1003
  st.wzHero.participants.push(playerKey);
1004
+ await updatePlayerPlayCount(session);
802
1005
  }
803
1006
  if (content === '结束') {
804
1007
  clearGameData(st.wzHero, cfg.wzHero.showRank && !isPrivate(session), session, d.wzHero.rankTitle, d.wzHero.rankEmpty);
@@ -815,8 +1018,9 @@ function apply(ctx, cfg) {
815
1018
  let text = `${dt.message || ''}\n${dt.hint || ''}\n剩余提示次数:${dt.remaining_hints}\n${dt.guide || ''}`;
816
1019
  text = text.replace(/\\n/g, '\n');
817
1020
  if (content !== '提示' && dt.message.includes('正确')) {
818
- st.wzHero.players[playerKey].score += 1;
1021
+ st.wzHero.players[playerKey].score += cfg.wzHero.rewardScore;
819
1022
  st.wzHero.players[playerKey].correctCount += 1;
1023
+ await savePlayerData(session, st.wzHero.players[playerKey]);
820
1024
  text += '\n' + d.wzHero.correct.replace('{0}', st.wzHero.players[playerKey].score.toString());
821
1025
  st.wzHero.currentRound += 1;
822
1026
  if (st.wzHero.currentRound > st.wzHero.totalRounds) {
@@ -825,7 +1029,7 @@ function apply(ctx, cfg) {
825
1029
  await session.send(text);
826
1030
  await session.send(d.wzHero.gameEnd);
827
1031
  if (cfg.wzHero.showRank && !isPrivate(session)) {
828
- const rankText = generateRankText(st.wzHero.players, d.wzHero.rankTitle, d.wzHero.rankEmpty);
1032
+ const rankText = generateGameRankText(st.wzHero.players, d.wzHero.rankTitle, d.wzHero.rankEmpty);
829
1033
  await session.send(rankText);
830
1034
  }
831
1035
  clearGameData(st.wzHero);
@@ -858,15 +1062,17 @@ function apply(ctx, cfg) {
858
1062
  catch (error) {
859
1063
  await session.send(d.wzHero.apiError);
860
1064
  }
861
- setupAutoStop(session, st.wzHero, cfg, 'wzHero', d.wzHero.autoStop, cfg.wzHero.showRank, d.wzHero.rankTitle, d.wzHero.rankEmpty);
1065
+ setupAutoStop(session, st.wzHero, 'wzHero', d.wzHero.autoStop, cfg.wzHero.showRank, d.wzHero.rankTitle, d.wzHero.rankEmpty);
862
1066
  gameStates.set(key, st);
863
1067
  return;
864
1068
  }
865
1069
  if (cfg.enableNumberGuess && st.guessNumber.started) {
866
1070
  clearGameTimer(st.guessNumber);
867
1071
  if (!st.guessNumber.players[playerKey]) {
868
- st.guessNumber.players[playerKey] = getPlayerData(session);
1072
+ const playerData = await getPlayerData(session);
1073
+ st.guessNumber.players[playerKey] = playerData;
869
1074
  st.guessNumber.participants.push(playerKey);
1075
+ await updatePlayerPlayCount(session);
870
1076
  }
871
1077
  if (content === '结束') {
872
1078
  clearGameData(st.guessNumber, cfg.guessNumber.showRank && !isPrivate(session), session, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
@@ -876,19 +1082,35 @@ function apply(ctx, cfg) {
876
1082
  }
877
1083
  const num = parseInt(content);
878
1084
  if (isNaN(num)) {
879
- setupAutoStop(session, st.guessNumber, cfg, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
1085
+ setupAutoStop(session, st.guessNumber, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
880
1086
  return next();
881
1087
  }
1088
+ if (num < st.guessNumber.currentMin || num > st.guessNumber.currentMax) {
1089
+ await session.send(d.guessNumber.outOfRange.replace('{0}', st.guessNumber.currentMin.toString()).replace('{1}', st.guessNumber.currentMax.toString()));
1090
+ setupAutoStop(session, st.guessNumber, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
1091
+ return;
1092
+ }
882
1093
  if (num === st.guessNumber.target) {
883
- await session.send(d.guessNumber.correct);
884
- addScoreToOthers(st.guessNumber.players, playerKey);
1094
+ st.guessNumber.players[playerKey].score += cfg.guessNumber.penaltyScore;
1095
+ await savePlayerData(session, st.guessNumber.players[playerKey]);
1096
+ let message = d.guessNumber.correct;
1097
+ if (cfg.guessNumber.enablePenalty) {
1098
+ Object.keys(st.guessNumber.players).forEach(key => {
1099
+ if (key !== playerKey) {
1100
+ st.guessNumber.players[key].score += cfg.guessNumber.rewardScore;
1101
+ savePlayerData(session, st.guessNumber.players[key]);
1102
+ }
1103
+ });
1104
+ message += `\n猜中者被扣 ${-cfg.guessNumber.penaltyScore} 分,其他玩家各加 ${cfg.guessNumber.rewardScore} 分`;
1105
+ }
1106
+ await session.send(message);
885
1107
  st.guessNumber.currentRound += 1;
886
1108
  if (st.guessNumber.currentRound > st.guessNumber.totalRounds) {
887
1109
  st.guessNumber.started = false;
888
1110
  clearGameTimer(st.guessNumber);
889
1111
  await session.send(d.guessNumber.gameEnd);
890
1112
  if (cfg.guessNumber.showRank && !isPrivate(session)) {
891
- const rankText = generateRankText(st.guessNumber.players, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
1113
+ const rankText = generateGameRankText(st.guessNumber.players, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
892
1114
  await session.send(rankText);
893
1115
  }
894
1116
  clearGameData(st.guessNumber);
@@ -907,15 +1129,17 @@ function apply(ctx, cfg) {
907
1129
  st.guessNumber.currentMax = num - 1;
908
1130
  await session.send(d.guessNumber.tooBig.replace('{0}', st.guessNumber.currentMin.toString()).replace('{1}', st.guessNumber.currentMax.toString()));
909
1131
  }
910
- setupAutoStop(session, st.guessNumber, cfg, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
1132
+ setupAutoStop(session, st.guessNumber, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
911
1133
  gameStates.set(key, st);
912
1134
  return;
913
1135
  }
914
1136
  if (cfg.enableCalc24 && st.calc24.started) {
915
1137
  clearGameTimer(st.calc24);
916
1138
  if (!st.calc24.players[playerKey]) {
917
- st.calc24.players[playerKey] = getPlayerData(session);
1139
+ const playerData = await getPlayerData(session);
1140
+ st.calc24.players[playerKey] = playerData;
918
1141
  st.calc24.participants.push(playerKey);
1142
+ await updatePlayerPlayCount(session);
919
1143
  }
920
1144
  if (content === '结束') {
921
1145
  clearGameData(st.calc24, cfg.calc24.showRank && !isPrivate(session), session, d.calc24.rankTitle, d.calc24.rankEmpty);
@@ -933,19 +1157,20 @@ function apply(ctx, cfg) {
933
1157
  .replace('{1}', st.calc24.difficulty)
934
1158
  .replace('{2}', st.calc24.numbers.join('、')));
935
1159
  }
936
- setupAutoStop(session, st.calc24, cfg, 'calc24', d.calc24.autoStop, cfg.calc24.showRank, d.calc24.rankTitle, d.calc24.rankEmpty);
1160
+ setupAutoStop(session, st.calc24, 'calc24', d.calc24.autoStop, cfg.calc24.showRank, d.calc24.rankTitle, d.calc24.rankEmpty);
937
1161
  return;
938
1162
  }
939
1163
  if (st.calc24.solved) {
940
1164
  await session.send(d.calc24.solved);
941
- setupAutoStop(session, st.calc24, cfg, 'calc24', d.calc24.autoStop, cfg.calc24.showRank, d.calc24.rankTitle, d.calc24.rankEmpty);
1165
+ setupAutoStop(session, st.calc24, 'calc24', d.calc24.autoStop, cfg.calc24.showRank, d.calc24.rankTitle, d.calc24.rankEmpty);
942
1166
  return;
943
1167
  }
944
1168
  const result = evaluateExpression(content);
945
1169
  if (result !== null && Math.abs(result - 24) < 0.001) {
946
1170
  await session.send(d.calc24.correct);
947
- st.calc24.players[playerKey].score += 1;
1171
+ st.calc24.players[playerKey].score += cfg.calc24.rewardScore;
948
1172
  st.calc24.players[playerKey].correctCount += 1;
1173
+ await savePlayerData(session, st.calc24.players[playerKey]);
949
1174
  st.calc24.solved = true;
950
1175
  st.calc24.currentRound += 1;
951
1176
  if (st.calc24.currentRound > st.calc24.totalRounds) {
@@ -953,7 +1178,7 @@ function apply(ctx, cfg) {
953
1178
  clearGameTimer(st.calc24);
954
1179
  await session.send(d.calc24.gameEnd);
955
1180
  if (cfg.calc24.showRank && !isPrivate(session)) {
956
- const rankText = generateRankText(st.calc24.players, d.calc24.rankTitle, d.calc24.rankEmpty);
1181
+ const rankText = generateGameRankText(st.calc24.players, d.calc24.rankTitle, d.calc24.rankEmpty);
957
1182
  await session.send(rankText);
958
1183
  }
959
1184
  clearGameData(st.calc24);
@@ -972,7 +1197,7 @@ function apply(ctx, cfg) {
972
1197
  else {
973
1198
  await session.send(d.calc24.wrong);
974
1199
  }
975
- setupAutoStop(session, st.calc24, cfg, 'calc24', d.calc24.autoStop, cfg.calc24.showRank, d.calc24.rankTitle, d.calc24.rankEmpty);
1200
+ setupAutoStop(session, st.calc24, 'calc24', d.calc24.autoStop, cfg.calc24.showRank, d.calc24.rankTitle, d.calc24.rankEmpty);
976
1201
  gameStates.set(key, st);
977
1202
  return;
978
1203
  }
@@ -983,8 +1208,12 @@ function apply(ctx, cfg) {
983
1208
  const session = argv.session;
984
1209
  if (!session)
985
1210
  return;
1211
+ if (isPrivate(session) && !canPlayPrivate('guessNumber')) {
1212
+ await session.send('私聊已禁用猜数字游戏');
1213
+ return;
1214
+ }
986
1215
  const key = getSessionKey(session);
987
- const st = gameStates.get(key) || initState(key, cfg);
1216
+ const st = gameStates.get(key) || initState(key);
988
1217
  if (checkGameRunning(st, 'guessNumber')) {
989
1218
  await session.send(d.common.gameRunning);
990
1219
  return;
@@ -998,7 +1227,7 @@ function apply(ctx, cfg) {
998
1227
  await session.send(d.guessNumber.start.replace('{0}', st.guessNumber.totalRounds.toString()));
999
1228
  await session.send(`猜数字范围:${st.guessNumber.currentMin} - ${st.guessNumber.currentMax}`);
1000
1229
  gameStates.set(key, st);
1001
- setupAutoStop(session, st.guessNumber, cfg, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
1230
+ setupAutoStop(session, st.guessNumber, 'guessNumber', d.guessNumber.autoStop, cfg.guessNumber.showRank, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
1002
1231
  }
1003
1232
  else if (action === '结束') {
1004
1233
  clearGameData(st.guessNumber, cfg.guessNumber.showRank && !isPrivate(session), session, d.guessNumber.rankTitle, d.guessNumber.rankEmpty);
@@ -1014,8 +1243,12 @@ function apply(ctx, cfg) {
1014
1243
  const session = argv.session;
1015
1244
  if (!session)
1016
1245
  return;
1246
+ if (isPrivate(session) && !canPlayPrivate('wzHero')) {
1247
+ await session.send('私聊已禁用王者英雄猜谜');
1248
+ return;
1249
+ }
1017
1250
  const key = getSessionKey(session);
1018
- const st = gameStates.get(key) || initState(key, cfg);
1251
+ const st = gameStates.get(key) || initState(key);
1019
1252
  if (checkGameRunning(st, 'wzHero')) {
1020
1253
  await session.send(d.common.gameRunning);
1021
1254
  return;
@@ -1040,7 +1273,7 @@ function apply(ctx, cfg) {
1040
1273
  await session.send(d.wzHero.apiError);
1041
1274
  }
1042
1275
  gameStates.set(key, st);
1043
- setupAutoStop(session, st.wzHero, cfg, 'wzHero', d.wzHero.autoStop, cfg.wzHero.showRank, d.wzHero.rankTitle, d.wzHero.rankEmpty);
1276
+ setupAutoStop(session, st.wzHero, 'wzHero', d.wzHero.autoStop, cfg.wzHero.showRank, d.wzHero.rankTitle, d.wzHero.rankEmpty);
1044
1277
  }
1045
1278
  else if (action === '结束') {
1046
1279
  clearGameData(st.wzHero, cfg.wzHero.showRank && !isPrivate(session), session, d.wzHero.rankTitle, d.wzHero.rankEmpty);
@@ -1048,7 +1281,7 @@ function apply(ctx, cfg) {
1048
1281
  gameStates.set(key, st);
1049
1282
  }
1050
1283
  else {
1051
- await session.send(d.wzHero.startUsage);
1284
+ await session.send(d.wzHero.usage);
1052
1285
  }
1053
1286
  });
1054
1287
  ctx.command('看图猜成语 <action>', '看图猜成语')
@@ -1056,8 +1289,12 @@ function apply(ctx, cfg) {
1056
1289
  const session = argv.session;
1057
1290
  if (!session)
1058
1291
  return;
1292
+ if (isPrivate(session) && !canPlayPrivate('chengyuImage')) {
1293
+ await session.send('私聊已禁用看图猜成语');
1294
+ return;
1295
+ }
1059
1296
  const key = getSessionKey(session);
1060
- const st = gameStates.get(key) || initState(key, cfg);
1297
+ const st = gameStates.get(key) || initState(key);
1061
1298
  if (checkGameRunning(st, 'chengyuImage')) {
1062
1299
  await session.send(d.common.gameRunning);
1063
1300
  return;
@@ -1088,7 +1325,7 @@ function apply(ctx, cfg) {
1088
1325
  await session.send(d.chengyuImage.apiError);
1089
1326
  }
1090
1327
  gameStates.set(key, st);
1091
- setupAutoStop(session, st.chengyuImage, cfg, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
1328
+ setupAutoStop(session, st.chengyuImage, 'chengyuImage', d.chengyuImage.autoStop, cfg.chengyuImage.showRank, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
1092
1329
  }
1093
1330
  else if (action === '结束') {
1094
1331
  clearGameData(st.chengyuImage, cfg.chengyuImage.showRank && !isPrivate(session), session, d.chengyuImage.rankTitle, d.chengyuImage.rankEmpty);
@@ -1096,7 +1333,7 @@ function apply(ctx, cfg) {
1096
1333
  gameStates.set(key, st);
1097
1334
  }
1098
1335
  else {
1099
- await session.send(d.chengyuImage.submitUsage);
1336
+ await session.send(d.chengyuImage.usage);
1100
1337
  }
1101
1338
  });
1102
1339
  ctx.command('成语接龙 <action>', '成语接龙')
@@ -1104,8 +1341,12 @@ function apply(ctx, cfg) {
1104
1341
  const session = argv.session;
1105
1342
  if (!session)
1106
1343
  return;
1344
+ if (isPrivate(session) && !canPlayPrivate('chengyuJielong')) {
1345
+ await session.send('私聊已禁用成语接龙');
1346
+ return;
1347
+ }
1107
1348
  const key = getSessionKey(session);
1108
- const st = gameStates.get(key) || initState(key, cfg);
1349
+ const st = gameStates.get(key) || initState(key);
1109
1350
  if (checkGameRunning(st, 'chengyuJielong')) {
1110
1351
  await session.send(d.common.gameRunning);
1111
1352
  return;
@@ -1115,10 +1356,13 @@ function apply(ctx, cfg) {
1115
1356
  st.chengyuJielong.currentRound = 1;
1116
1357
  st.chengyuJielong.hasTriggeredAutoPlay = false;
1117
1358
  st.chengyuJielong.autoPlayCount = 0;
1359
+ st.chengyuJielong.jielongCount = 0;
1118
1360
  await session.send(d.chengyuJielong.start.replace('{0}', st.chengyuJielong.totalRounds.toString()));
1361
+ setTimeout(() => {
1362
+ scheduleAutoPlay(session, key, st);
1363
+ }, 100);
1119
1364
  gameStates.set(key, st);
1120
- scheduleAutoPlay(session, key, st);
1121
- setupAutoStop(session, st.chengyuJielong, cfg, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
1365
+ setupAutoStop(session, st.chengyuJielong, 'chengyuJielong', d.chengyuJielong.autoStop, cfg.chengyuJielong.showRank, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
1122
1366
  }
1123
1367
  else if (action === '结束') {
1124
1368
  clearGameData(st.chengyuJielong, cfg.chengyuJielong.showRank && !isPrivate(session), session, d.chengyuJielong.rankTitle, d.chengyuJielong.rankEmpty);
@@ -1126,7 +1370,7 @@ function apply(ctx, cfg) {
1126
1370
  gameStates.set(key, st);
1127
1371
  }
1128
1372
  else {
1129
- await session.send(d.chengyuJielong.joinUsage);
1373
+ await session.send(d.chengyuJielong.usage);
1130
1374
  }
1131
1375
  });
1132
1376
  ctx.command('算24点 <action>', '算24点游戏')
@@ -1134,8 +1378,12 @@ function apply(ctx, cfg) {
1134
1378
  const session = argv.session;
1135
1379
  if (!session)
1136
1380
  return;
1381
+ if (isPrivate(session) && !canPlayPrivate('calc24')) {
1382
+ await session.send('私聊已禁用算24点');
1383
+ return;
1384
+ }
1137
1385
  const key = getSessionKey(session);
1138
- const st = gameStates.get(key) || initState(key, cfg);
1386
+ const st = gameStates.get(key) || initState(key);
1139
1387
  if (checkGameRunning(st, 'calc24')) {
1140
1388
  await session.send(d.common.gameRunning);
1141
1389
  return;
@@ -1153,7 +1401,7 @@ function apply(ctx, cfg) {
1153
1401
  .replace('{1}', st.calc24.difficulty)
1154
1402
  .replace('{2}', st.calc24.numbers.join('、')));
1155
1403
  gameStates.set(key, st);
1156
- setupAutoStop(session, st.calc24, cfg, 'calc24', d.calc24.autoStop, cfg.calc24.showRank, d.calc24.rankTitle, d.calc24.rankEmpty);
1404
+ setupAutoStop(session, st.calc24, 'calc24', d.calc24.autoStop, cfg.calc24.showRank, d.calc24.rankTitle, d.calc24.rankEmpty);
1157
1405
  }
1158
1406
  else if (action === '结束') {
1159
1407
  clearGameData(st.calc24, cfg.calc24.showRank && !isPrivate(session), session, d.calc24.rankTitle, d.calc24.rankEmpty);
@@ -1161,7 +1409,27 @@ function apply(ctx, cfg) {
1161
1409
  gameStates.set(key, st);
1162
1410
  }
1163
1411
  else {
1164
- await session.send('请输入:算24点 开始 或 算24点 结束');
1412
+ await session.send(d.calc24.usage);
1165
1413
  }
1166
1414
  });
1415
+ if (cfg.rank.enableCommand) {
1416
+ ctx.command('排行榜', '查看本群游戏排行榜')
1417
+ .action(async ({ session }) => {
1418
+ if (!session || !session.channelId)
1419
+ return;
1420
+ const rankText = await generateTotalRankText(session);
1421
+ await session.send(rankText);
1422
+ });
1423
+ ctx.command('清零', '清零本群所有玩家数据')
1424
+ .action(async ({ session }) => {
1425
+ if (!session || !session.channelId)
1426
+ return;
1427
+ if (session.user?.authority < cfg.rank.clearDataPermission) {
1428
+ await session.send(d.rank.noPermission);
1429
+ return;
1430
+ }
1431
+ await ctx.database.remove('game_mini_player', { guildId: session.channelId });
1432
+ await session.send(d.rank.clearSuccess);
1433
+ });
1434
+ }
1167
1435
  }