koishi-plugin-game-mini 0.2.6 → 0.2.7

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