nonebot-plugin-fishing2 0.0.4__py3-none-any.whl → 0.1.1__py3-none-any.whl

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.
@@ -2,6 +2,7 @@ from nonebot import require
2
2
 
3
3
  require("nonebot_plugin_orm") # noqa
4
4
 
5
+ import copy
5
6
  import shlex
6
7
  from typing import Union
7
8
 
@@ -39,37 +40,43 @@ from .data_source import (
39
40
  get_shop,
40
41
  buy_fish,
41
42
  predict,
42
- get_all_special_fish,
43
+ get_pool,
44
+ remove_special_fish,
43
45
  )
44
46
  from .fish_helper import fish_list, get_fish_by_name
45
47
 
46
48
  fishing_coin_name = config.fishing_coin_name
49
+ cool_down = (
50
+ f"{config.fishing_cooldown_time_min}s~{config.fishing_cooldown_time_max}s"
51
+ if config.fishing_cooldown_time_min != config.fishing_cooldown_time_max
52
+ else f"{config.fishing_cooldown_time_min}s"
53
+ ) # 浮动 CD 法力无边,有效遏制频繁钓鱼
47
54
 
48
55
  __plugin_meta__ = PluginMetadata(
49
56
  name="更好的电子钓鱼",
50
57
  description="赛博钓鱼……但是加强版本",
51
- usage=f"""▶ 查询 [物品]:查询某个物品的信息
58
+ usage=f"""▶ 钓鱼帮助:打印本信息
59
+ ▶ 查询 [物品]:查询某个物品的信息
52
60
  ▶ 钓鱼 [鱼竿] [鱼饵]:
53
- {config.fishing_limit}s 的冷却
54
- ▷ {config.no_fish_probability} 概率空军,{config.special_fish_probability} 概率掉到特殊鱼
61
+ 钓鱼后有 {cool_down} 的冷却,频繁钓鱼会触怒河神
62
+ ▷ {config.no_fish_probability} 概率空军,{config.special_fish_probability} 概率钓到特殊鱼
55
63
  ▷ 加参数可以使用鱼饵或鱼竿,同类物品同时只能使用一种
56
- 频繁钓鱼会触怒河神
57
- 出售 <物品> <数量>:出售物品获得{fishing_coin_name}
58
- 如果卖不出去,尝试用英文双引号框住鱼名
59
- ▶ 购买 <物品> <份数>:购买渔具店的物品
64
+ 出售 [-i] [-s] <物品或序号> [数量]:出售物品获得{fishing_coin_name}
65
+ -i 按照序号卖鱼 -s 卖特殊鱼
66
+ 购买 <物品> [份数]:购买物品
60
67
  ▶ 放生 <鱼名>:给一条鱼取名并放生
61
68
  ▷ 不要放生奇怪名字的鱼
62
69
  ▶ 商店:看看渔具店都有些啥
63
- 祈愿:向神祈愿,随机获取/损失{fishing_coin_name}
70
+ 祈愿:向神祈愿{fishing_coin_name}
64
71
  ▶ 背包:查看背包中的{fishing_coin_name}与物品
65
72
  ▶ 成就:查看拥有的成就
66
73
  ▶ 钓鱼排行榜:查看{fishing_coin_name}排行榜
67
74
  """,
68
75
  type="application",
69
- homepage="https://github.com/FDCraft/nonebot-plugin-fishing2",
76
+ homepage="https://github.com/GLDYM/nonebot-plugin-fishing2",
70
77
  config=Config,
71
78
  supported_adapters={"~onebot.v11"},
72
- extra={"author": "Polaris_Light", "version": "0.0.4", "priority": 5},
79
+ extra={"author": "Polaris_Light", "version": "0.1.1", "priority": 5},
73
80
  )
74
81
 
75
82
 
@@ -87,18 +94,36 @@ sell = on_command("sell", aliases={"卖鱼", "出售", "售卖"}, force_whitespa
87
94
  free_fish_cmd = on_command("free_fish", aliases={"放生", "钓鱼放生"}, force_whitespace=True, priority=5)
88
95
  lottery_cmd = on_command("lottery", aliases={"祈愿"}, force_whitespace=True, priority=5)
89
96
  achievement_cmd = on_command("achievement", aliases={"成就", "钓鱼成就"}, force_whitespace=True, priority=5)
90
- give_cmd = on_command("give", aliases={"赐予"}, force_whitespace=True, priority=5)
91
97
  board_cmd = on_command("board", aliases={"排行榜", "钓鱼排行榜"}, force_whitespace=True, priority=5)
92
98
 
93
99
  # hidden cmd
100
+ give_cmd = on_command("give", aliases={"赐予"}, force_whitespace=True, priority=5)
94
101
  predict_cmd = on_command("predict", aliases={"钓鱼预测"}, force_whitespace=True, priority=5)
95
102
  pool_cmd = on_command("pool", aliases={"鱼池"}, force_whitespace=True, priority=5)
103
+ remove_cmd = on_command("remove", aliases={"捞鱼"}, force_whitespace=True, priority=5)
96
104
  # fmt:on
97
105
 
98
106
 
99
107
  @fishing_help.handle()
100
- async def _():
101
- await fishing_help.finish(__plugin_meta__.usage)
108
+ async def _(bot: Bot, event: Union[GroupMessageEvent, PrivateMessageEvent]):
109
+ user_id = event.get_user_id()
110
+ is_superuser = str(user_id) in bot.config.superusers
111
+ is_self = event.self_id == user_id
112
+
113
+ if not is_superuser and not is_self:
114
+ await fishing_help.finish(__plugin_meta__.usage)
115
+ else:
116
+ messages: list[MessageSegment] = []
117
+ messages.append(MessageSegment.text(__plugin_meta__.usage))
118
+ message2 = """以下为管理员命令:
119
+ ▶ 背包 [QQ或at]:让我看看
120
+ ▶ 赐予 [-i] [-s] <QQ或at> <物品或序号> [数量]:神秘力量
121
+ ▶ 钓鱼预测 [鱼竿] [鱼饵]:预测钓鱼
122
+ ▶ 鱼池 [鱼名长度最大值] [单页长度最大值]:查看所有特殊鱼
123
+ ▶ 捞鱼 [-i] <物品或序号>:捞出鱼池内特殊鱼
124
+ """
125
+ messages.append(MessageSegment.text(message2))
126
+ await forward_send(bot, event, messages)
102
127
 
103
128
 
104
129
  @shop.handle()
@@ -127,19 +152,26 @@ async def _(
127
152
  )
128
153
  elif arg not in fish_list:
129
154
  await fishing_lookup.finish(MessageSegment.at(user_id) + " 查无此鱼。")
130
- await forward_send(bot, event, get_fish_by_name(arg).print_info())
155
+
156
+ messages = get_fish_by_name(arg).print_info()
157
+ await forward_send(bot, event, messages)
131
158
  return None
132
159
 
133
160
 
134
161
  @fishing.handle()
135
- async def _(bot: Bot, event: Event, matcher: Matcher, arg: Message = CommandArg()):
162
+ async def _(
163
+ bot: Bot,
164
+ event: Union[GroupMessageEvent, PrivateMessageEvent],
165
+ matcher: Matcher,
166
+ arg: Message = CommandArg(),
167
+ ):
136
168
  user_id = event.get_user_id()
137
169
  if user_id in block_user_list:
138
170
  await fishing.finish()
139
171
 
140
172
  tools = shlex.split((arg.extract_plain_text()))[:2]
141
173
 
142
- logger.debug(f"Fishing: {user_id} try to use {tools}")
174
+ logger.info(f"Fishing: {user_id} try to use {tools}")
143
175
 
144
176
  check_result = await check_tools(user_id, tools)
145
177
  if check_result:
@@ -160,6 +192,7 @@ async def _(bot: Bot, event: Event, matcher: Matcher, arg: Message = CommandArg(
160
192
  for achievement in achievements:
161
193
  await fishing.send(achievement)
162
194
  except Exception as e:
195
+ result = "河神睡着了……"
163
196
  logger.error(e)
164
197
  finally:
165
198
  block_user_list.remove(user_id)
@@ -192,46 +225,85 @@ async def _(
192
225
 
193
226
 
194
227
  @pool_cmd.handle()
195
- async def _(bot: Bot, event: Union[GroupMessageEvent, PrivateMessageEvent]):
228
+ async def _(
229
+ bot: Bot,
230
+ event: Union[GroupMessageEvent, PrivateMessageEvent],
231
+ arg: Message = CommandArg(),
232
+ ):
196
233
  user_id = event.get_user_id()
197
234
  is_superuser = str(user_id) in bot.config.superusers
198
235
  is_self = event.self_id == user_id
199
236
  if not is_superuser and not is_self:
200
237
  return None
201
238
 
202
- message: list[MessageSegment] = []
203
- pool = await get_all_special_fish()
204
- message.append(MessageSegment.text(f"现在鱼池里面有 {len(pool)} 条鱼。"))
239
+ args = shlex.split(arg.extract_plain_text())
205
240
 
206
- result = dict()
207
- for fish in pool:
208
- try:
209
- result[fish] += 1
210
- except KeyError:
211
- result[fish] = 1
212
-
213
- msg = "鱼池列表:\n"
214
- for fish, num in result.items():
215
- if len(msg) > 300:
216
- msg += f"{fish} x {num}"
217
- message.append(MessageSegment.text(msg))
218
- msg = ""
219
- else:
220
- msg += f"{fish} x {num}\n"
221
- else:
222
- message.append(MessageSegment.text(msg))
241
+ match len(args):
242
+ case 0:
243
+ messages = await get_pool()
244
+ case 1:
245
+ if not args[0].isdigit():
246
+ await pool_cmd.finish(MessageSegment.text("你完全不看帮助是吗  ̄へ ̄"))
247
+ messages = await get_pool(int(args[0]))
248
+ case 2:
249
+ if not args[0].isdigit() or not args[1].isdigit():
250
+ await pool_cmd.finish(MessageSegment.text("你完全不看帮助是吗  ̄へ ̄"))
251
+ messages = await get_pool(int(args[0]), int(args[1]))
223
252
 
224
- await forward_send(bot, event, message)
253
+ await forward_send(bot, event, messages)
225
254
  return None
226
255
 
227
256
 
257
+ @remove_cmd.handle()
258
+ async def _(
259
+ bot: Bot,
260
+ event: Union[GroupMessageEvent, PrivateMessageEvent],
261
+ arg: Message = CommandArg(),
262
+ ):
263
+ user_id = event.get_user_id()
264
+ is_superuser = str(user_id) in bot.config.superusers
265
+ is_self = event.self_id == user_id
266
+ if not is_superuser and not is_self:
267
+ return None
268
+
269
+ args = shlex.split(arg.extract_plain_text())
270
+ as_index = False
271
+ for arg in copy.deepcopy(args):
272
+ if arg in ["-i", "--index"]:
273
+ as_index = True
274
+ args.remove(arg)
275
+
276
+ name_or_index = args[0]
277
+ result = await remove_special_fish(name_or_index, as_index)
278
+ await remove_cmd.finish(result)
279
+
280
+
228
281
  @backpack.handle()
229
- async def _(bot: Bot, event: Union[GroupMessageEvent, PrivateMessageEvent]):
282
+ async def _(
283
+ bot: Bot,
284
+ event: Union[GroupMessageEvent, PrivateMessageEvent],
285
+ arg: Message = CommandArg(),
286
+ ):
230
287
  user_id = event.get_user_id()
288
+ is_superuser = str(user_id) in bot.config.superusers
289
+ is_self = event.self_id == user_id
290
+ if not is_superuser and not is_self:
291
+ user_id = user_id
292
+ else:
293
+ args = shlex.split(arg.extract_plain_text())
294
+ target = await get_at(event)
295
+ if target:
296
+ args.insert(0, target)
297
+ if len(args) >= 1:
298
+ user_id = args[0]
299
+ else:
300
+ user_id = user_id
301
+
231
302
  if not config.backpack_forward:
232
303
  await backpack.finish(
233
- MessageSegment.at(user_id)
234
- + " \n"
304
+ (MessageSegment.at(user_id) + " \n")
305
+ if isinstance(event, GroupMessageEvent)
306
+ else ""
235
307
  + await get_stats(user_id)
236
308
  + "\n"
237
309
  + await get_balance(user_id)
@@ -239,17 +311,20 @@ async def _(bot: Bot, event: Union[GroupMessageEvent, PrivateMessageEvent]):
239
311
  + "\n\n".join(await get_backpack(user_id))
240
312
  )
241
313
  else:
242
- message: list[MessageSegment] = []
243
- message.append(MessageSegment.at(user_id))
244
- message.append(await get_stats(user_id))
245
- message.append(await get_balance(user_id))
314
+ messages: list[MessageSegment] = []
315
+ if isinstance(event, GroupMessageEvent):
316
+ messages.append(MessageSegment.at(user_id))
317
+ messages.append(await get_stats(user_id))
318
+ messages.append(await get_balance(user_id))
246
319
  backpacks = await get_backpack(user_id)
247
- message += [MessageSegment.text(msg) for msg in backpacks]
248
- await forward_send(bot, event, message)
320
+ messages += [MessageSegment.text(msg) for msg in backpacks]
321
+ await forward_send(bot, event, messages)
249
322
 
250
323
 
251
324
  @buy.handle()
252
- async def _(event: Event, arg: Message = CommandArg()):
325
+ async def _(
326
+ event: Union[GroupMessageEvent, PrivateMessageEvent], arg: Message = CommandArg()
327
+ ):
253
328
  args = arg.extract_plain_text().split(" ")
254
329
  args = [x for x in args if x != ""]
255
330
 
@@ -274,36 +349,62 @@ async def _(event: Event, arg: Message = CommandArg()):
274
349
 
275
350
 
276
351
  @sell.handle()
277
- async def _(event: Event, arg: Message = CommandArg()):
352
+ async def _(
353
+ event: Union[GroupMessageEvent, PrivateMessageEvent], arg: Message = CommandArg()
354
+ ):
278
355
  args = shlex.split(arg.extract_plain_text())
279
-
280
356
  user_id = event.get_user_id()
357
+ as_index = False
358
+ as_special = False
359
+
360
+ logger.info(f"Sell: {user_id} sells :{args}")
361
+
281
362
  if args == []:
282
363
  await sell.finish(
283
364
  MessageSegment.at(user_id)
284
365
  + " "
285
366
  + "请输入要卖出的鱼的名字和数量 (数量为1时可省略), 如 /卖鱼 小鱼 1"
286
367
  )
368
+
369
+ for arg in copy.deepcopy(args):
370
+ if arg in ["-i", "--index"]:
371
+ as_index = True
372
+ args.remove(arg)
373
+ if arg in ["-s", "--spec", "--special"]:
374
+ as_special = True
375
+ args.remove(arg)
376
+
287
377
  if len(args) == 1:
288
- fish_name = args[0]
289
- await sell.finish(
290
- MessageSegment.at(user_id) + " " + await sell_fish(user_id, fish_name)
291
- )
378
+ name_or_index = args[0]
379
+ fish_quantity = 1
292
380
  else:
293
- fish_name, fish_quantity = args[0], args[1]
294
- result = await sell_fish(user_id, fish_name, int(fish_quantity))
295
- await sell.finish(MessageSegment.at(user_id) + " " + result)
381
+ name_or_index, fish_quantity = args[0], args[1]
382
+
383
+ result = await sell_fish(
384
+ user_id, name_or_index, int(fish_quantity), as_index, as_special
385
+ )
386
+ await sell.finish(MessageSegment.at(user_id) + " " + result)
296
387
 
297
388
 
298
389
  @free_fish_cmd.handle()
299
- async def _(bot: Bot, event: Event, arg: Message = CommandArg()):
390
+ async def _(
391
+ bot: Bot,
392
+ event: Union[GroupMessageEvent, PrivateMessageEvent],
393
+ arg: Message = CommandArg(),
394
+ ):
300
395
  if not config.special_fish_enabled:
301
396
  await free_fish_cmd.finish("未开启此功能, 请联系机器人管理员")
302
397
 
303
398
  fish_name = arg.extract_plain_text()
304
399
  user_id = event.get_user_id()
305
400
 
306
- if '"' in fish_name:
401
+ if (
402
+ "\u200b" in fish_name
403
+ or "\u200c" in fish_name
404
+ or "\u200d" in fish_name
405
+ or "\u2060" in fish_name
406
+ or "\ufeff" in fish_name
407
+ ): # TODO: 检测特殊字符
307
408
  if isinstance(event, GroupMessageEvent):
308
409
  group_id = event.group_id
309
410
  await bot.set_group_ban(group_id=group_id, user_id=user_id, duration=1800)
@@ -321,13 +422,15 @@ async def _(bot: Bot, event: Event, arg: Message = CommandArg()):
321
422
 
322
423
 
323
424
  @lottery_cmd.handle()
324
- async def _(bot: Bot, event: Event, matcher: Matcher):
425
+ async def _(
426
+ bot: Bot, event: Union[GroupMessageEvent, PrivateMessageEvent], matcher: Matcher
427
+ ):
325
428
  user_id = event.get_user_id()
326
429
  try:
327
430
  await punish(bot, event, matcher, user_id)
328
431
  result = await lottery(user_id)
329
432
  except:
330
- pass
433
+ result = "河神睡着了……"
331
434
  finally:
332
435
  punish_user_dict.pop(user_id, None)
333
436
  await lottery_cmd.finish(MessageSegment.at(user_id) + " " + result)
@@ -352,17 +455,27 @@ async def _(
352
455
  if not is_superuser and not is_self:
353
456
  return None
354
457
 
355
- target = await get_at(event)
356
458
  args = shlex.split(arg.extract_plain_text())
459
+
460
+ for arg in copy.deepcopy(args):
461
+ if arg in ["-i", "--index"]:
462
+ as_index = True
463
+ args.remove(arg)
464
+ if arg in ["-s", "--spec", "--special"]:
465
+ as_special = True
466
+ args.remove(arg)
467
+
468
+ target = await get_at(event)
357
469
  if target:
358
470
  args.insert(0, target)
471
+
359
472
  if len(args) < 2 or len(args) > 3:
360
473
  await give_cmd.finish(
361
474
  "请输入用户的 id 和鱼的名字和数量 (数量为1时可省略), 如 /give 114514 开发鱼 1"
362
475
  )
363
476
  else:
364
477
  quantity = int(args[2]) if len(args) == 3 else 1
365
- result = await give(args[0], args[1], quantity)
478
+ result = await give(args[0], args[1], quantity, as_index, as_special)
366
479
  achievements = await check_achievement(args[0])
367
480
  if achievements is not None:
368
481
  for achievement in achievements:
@@ -397,7 +510,12 @@ async def _(bot: Bot, event: Union[GroupMessageEvent, PrivateMessageEvent]):
397
510
  await board_cmd.finish(msg)
398
511
 
399
512
 
400
- async def punish(bot: Bot, event: Event, matcher: Matcher, user_id: int):
513
+ async def punish(
514
+ bot: Bot,
515
+ event: Union[GroupMessageEvent, PrivateMessageEvent],
516
+ matcher: Matcher,
517
+ user_id: int,
518
+ ):
401
519
  global punish_user_dict
402
520
 
403
521
  if not await can_fishing(user_id):
@@ -1,12 +1,8 @@
1
1
  from pydantic import BaseModel
2
2
  from typing import List, Dict
3
3
 
4
- try:
5
- # pydantic v2
6
- from nonebot import get_plugin_config
7
- except ImportError:
8
- # pydantic v1
9
- from nonebot import get_driver
4
+ from nonebot import get_plugin_config
5
+
10
6
 
11
7
  # fmt:off
12
8
  class Config(BaseModel):
@@ -126,7 +122,7 @@ class Config(BaseModel):
126
122
  {
127
123
  "type": "item",
128
124
  "name": "钛金鱼竿",
129
- "price": 20,
125
+ "price": 40,
130
126
  "amount": 20,
131
127
  "props": [
132
128
  {
@@ -141,12 +137,13 @@ class Config(BaseModel):
141
137
  "description": "更坚韧的鱼竿,显著提升钓上大鱼的概率。",
142
138
  "can_catch": False,
143
139
  "can_buy": True,
140
+ "buy_price": 40,
144
141
  "can_sell": False
145
142
  },
146
143
  {
147
144
  "type": "item",
148
145
  "name": "附魔鱼竿",
149
- "price": 35,
146
+ "price": 20,
150
147
  "amount": 20,
151
148
  "props": [
152
149
  {
@@ -157,7 +154,7 @@ class Config(BaseModel):
157
154
  "description": "附魔的鱼竿,大幅减少钓上垃圾的概率。",
158
155
  "can_catch": True,
159
156
  "sleep_time": 30,
160
- "weight": 100,
157
+ "weight": 40,
161
158
  "can_buy": False,
162
159
  "can_sell": False
163
160
  },
@@ -211,7 +208,7 @@ class Config(BaseModel):
211
208
  "value": -1
212
209
  }
213
210
  ],
214
- "description": "必定钓到特殊鱼。这是个管理员物品",
211
+ "description": "必定钓到特殊鱼。",
215
212
  "can_catch": False,
216
213
  "can_buy": False,
217
214
  "can_sell": False
@@ -277,7 +274,9 @@ class Config(BaseModel):
277
274
 
278
275
  fishing_coin_name: str = "绿宝石" # 货币名称
279
276
 
280
- fishing_limit: int = 60 # 每次钓鱼后,限制钓鱼的秒数
277
+ fishing_cooldown_time_min: int = 60 # 钓鱼冷却下限,单位为秒
278
+
279
+ fishing_cooldown_time_max: int = 90 # 钓鱼冷却上限
281
280
 
282
281
  punish_limit: int = 3 # 短时间多次钓鱼后,禁言所需次数,防止刷屏
283
282
 
@@ -298,9 +297,5 @@ class Config(BaseModel):
298
297
  backpack_forward: bool = True # 背包是否使用聊天记录
299
298
  # fmt:on
300
299
 
301
- try:
302
- # pydantic v2
303
- config = get_plugin_config(Config)
304
- except:
305
- # pydantic v1
306
- config = Config.parse_obj(get_driver().config)
300
+ config = get_plugin_config(Config)
301
+
@@ -4,7 +4,7 @@ import random
4
4
  import time
5
5
  import json
6
6
 
7
- from typing import Union
7
+ from collections.abc import Hashable
8
8
  from sqlalchemy import select, update, delete
9
9
  from sqlalchemy.sql.expression import func
10
10
  from nonebot.adapters.onebot.v11 import MessageSegment
@@ -15,6 +15,23 @@ from .model import FishingRecord, SpecialFishes
15
15
  from .fish_helper import *
16
16
 
17
17
 
18
+ def get_key_by_index(
19
+ dict: dict, index: int, default: Hashable | None = None
20
+ ) -> Hashable | None:
21
+ """Utils: get the key of OrderedDict by index.
22
+
23
+ Args:
24
+ dict (dict)
25
+ index (int)
26
+ default (Hashable | None, optional): default value. Defaults to None.
27
+
28
+ Returns:
29
+ Hashable | None: a key of dict.
30
+ """
31
+ key_list = list(dict.keys())
32
+ return key_list[index] if index < len(key_list) else default
33
+
34
+
18
35
  async def can_fishing(user_id: str) -> bool:
19
36
  time_now = int(time.time())
20
37
  session = get_session()
@@ -227,15 +244,6 @@ async def random_get_a_special_fish() -> str:
227
244
  return data.fish
228
245
 
229
246
 
230
- async def get_all_special_fish() -> list[str]:
231
- session = get_session()
232
- async with session.begin():
233
- random_select = select(SpecialFishes.fish).order_by(SpecialFishes.fish.asc())
234
- data = await session.scalars(random_select)
235
- result = data.all()
236
- return result
237
-
238
-
239
247
  async def check_achievement(user_id: str) -> str | None:
240
248
  session = get_session()
241
249
  async with session.begin():
@@ -309,7 +317,9 @@ async def save_achievement(user_id: str, achievement_name: str):
309
317
 
310
318
  async def save_fish(user_id: str, fish_name: str) -> None:
311
319
  time_now = int(time.time())
312
- fishing_limit = config.fishing_limit
320
+ fishing_cooldown = random.randint(
321
+ config.fishing_cooldown_time_min, config.fishing_cooldown_time_max
322
+ )
313
323
  amount = get_fish_by_name(fish_name).amount
314
324
  session = get_session()
315
325
  async with session.begin():
@@ -327,7 +337,7 @@ async def save_fish(user_id: str, fish_name: str) -> None:
327
337
  update(FishingRecord)
328
338
  .where(FishingRecord.user_id == user_id)
329
339
  .values(
330
- time=time_now + fishing_limit,
340
+ time=time_now + fishing_cooldown,
331
341
  frequency=new_frequency,
332
342
  fishes=dump_fishes,
333
343
  )
@@ -339,7 +349,7 @@ async def save_fish(user_id: str, fish_name: str) -> None:
339
349
  dump_fishes = json.dumps(data)
340
350
  new_record = FishingRecord(
341
351
  user_id=user_id,
342
- time=time_now + fishing_limit,
352
+ time=time_now + fishing_cooldown,
343
353
  frequency=1,
344
354
  fishes=dump_fishes,
345
355
  special_fishes="{}",
@@ -352,7 +362,9 @@ async def save_fish(user_id: str, fish_name: str) -> None:
352
362
 
353
363
  async def save_special_fish(user_id: str, fish_name: str) -> None:
354
364
  time_now = int(time.time())
355
- fishing_limit = config.fishing_limit
365
+ fishing_cooldown = random.randint(
366
+ config.fishing_cooldown_time_min, config.fishing_cooldown_time_max
367
+ )
356
368
  session = get_session()
357
369
  async with session.begin():
358
370
  select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
@@ -368,7 +380,7 @@ async def save_special_fish(user_id: str, fish_name: str) -> None:
368
380
  update(FishingRecord)
369
381
  .where(FishingRecord.user_id == user_id)
370
382
  .values(
371
- time=time_now + fishing_limit,
383
+ time=time_now + fishing_cooldown,
372
384
  frequency=record.frequency + 1,
373
385
  special_fishes=dump_fishes,
374
386
  )
@@ -379,7 +391,7 @@ async def save_special_fish(user_id: str, fish_name: str) -> None:
379
391
  dump_fishes = json.dumps(data)
380
392
  new_record = FishingRecord(
381
393
  user_id=user_id,
382
- time=time_now + fishing_limit,
394
+ time=time_now + fishing_cooldown,
383
395
  frequency=1,
384
396
  fishes="{}",
385
397
  special_fishes=dump_fishes,
@@ -400,17 +412,44 @@ async def save_special_fish(user_id: str, fish_name: str) -> None:
400
412
  await session.commit()
401
413
 
402
414
 
403
- async def sell_fish(user_id: str, fish_name: str, quantity: int = 1) -> str:
415
+ async def sell_fish(
416
+ user_id: str,
417
+ name_or_index: str,
418
+ quantity: int = 1,
419
+ as_index: bool = False,
420
+ as_special: bool = False,
421
+ ) -> str:
404
422
  if quantity <= 0:
405
423
  return "你在卖什么 w(゚Д゚)w"
424
+
406
425
  session = get_session()
407
426
  async with session.begin():
408
427
  select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
409
428
  fishes_record = await session.scalar(select_user)
410
429
  if fishes_record := fishes_record:
411
430
  loads_fishes = json.loads(fishes_record.fishes)
431
+ loads_fishes = {
432
+ key: loads_fishes[key] for key in fish_list if key in loads_fishes
433
+ }
434
+
412
435
  spec_fishes = json.loads(fishes_record.special_fishes)
413
- if fish_name in loads_fishes and loads_fishes[fish_name] > 0:
436
+ spec_fishes = dict(sorted(spec_fishes.items()))
437
+
438
+ if as_index:
439
+ if not name_or_index.isdigit():
440
+ return "你完全不看帮助是吗  ̄へ ̄"
441
+ load_dict = loads_fishes if not as_special else spec_fishes
442
+ fish_name = get_key_by_index(load_dict, int(name_or_index))
443
+ if not fish_name:
444
+ return "查无此鱼"
445
+ else:
446
+ fish_name = name_or_index
447
+
448
+ if (
449
+ not as_special
450
+ and fish_name in loads_fishes
451
+ and loads_fishes[fish_name] > 0
452
+ ):
414
453
  if fish_name not in can_sell_fishes:
415
454
  return f"这个 {fish_name} 不可以卖哦~"
416
455
  if loads_fishes[fish_name] < quantity:
@@ -430,6 +469,7 @@ async def sell_fish(user_id: str, fish_name: str, quantity: int = 1) -> str:
430
469
  )
431
470
  await session.execute(user_update)
432
471
  await session.commit()
472
+
433
473
  return (
434
474
  f"你以 {fish_price} {fishing_coin_name} / 条的价格卖出了 {quantity} 条 {fish_name}, "
435
475
  f"你获得了 {fish_price * quantity} {fishing_coin_name}"
@@ -549,7 +589,9 @@ async def lottery(user_id: str) -> str:
549
589
  """算法来自于 https://github.com/fossifer/minesweeperbot/blob/master/cards.py"""
550
590
  session = get_session()
551
591
  time_now = int(time.time())
552
- fishing_limit = config.fishing_limit
592
+ fishing_cooldown = random.randint(
593
+ config.fishing_cooldown_time_min, config.fishing_cooldown_time_max
594
+ )
553
595
  async with session.begin():
554
596
  select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
555
597
  fishes_record = await session.scalar(select_user)
@@ -561,7 +603,7 @@ async def lottery(user_id: str) -> str:
561
603
  update(FishingRecord)
562
604
  .where(FishingRecord.user_id == user_id)
563
605
  .values(
564
- time=time_now + fishing_limit,
606
+ time=time_now + fishing_cooldown,
565
607
  coin=fishes_record.coin + new_coin,
566
608
  )
567
609
  )
@@ -576,7 +618,7 @@ async def lottery(user_id: str) -> str:
576
618
  update(FishingRecord)
577
619
  .where(FishingRecord.user_id == user_id)
578
620
  .values(
579
- time=time_now + fishing_limit,
621
+ time=time_now + fishing_cooldown,
580
622
  coin=fishes_record.coin + new_coin,
581
623
  )
582
624
  )
@@ -587,13 +629,20 @@ async def lottery(user_id: str) -> str:
587
629
  return "河神没有回应你……"
588
630
 
589
631
 
590
- async def give(user_id: str, fish_name: str, quantity: int = 1) -> str:
632
+ async def give(
633
+ user_id: str,
634
+ name_or_index: str,
635
+ quantity: int = 1,
636
+ as_index: bool = False,
637
+ as_special: bool = False,
638
+ ) -> str:
591
639
  session = get_session()
592
640
  async with session.begin():
593
641
  select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
594
642
  record = await session.scalar(select_user)
595
643
  if record:
596
- if fish_name == "coin" or fish_name == fishing_coin_name:
644
+
645
+ if name_or_index == "coin" or name_or_index == fishing_coin_name:
597
646
  user_update = (
598
647
  update(FishingRecord)
599
648
  .where(FishingRecord.user_id == user_id)
@@ -604,13 +653,27 @@ async def give(user_id: str, fish_name: str, quantity: int = 1) -> str:
604
653
  await session.execute(user_update)
605
654
  await session.commit()
606
655
  return f"使用滥权之力成功为 {user_id} {"增加" if quantity >= 0 else "减少"} {abs(quantity)} {fishing_coin_name} ヾ(≧▽≦*)o"
656
+
607
657
  loads_fishes = json.loads(record.fishes)
608
658
  spec_fishes = json.loads(record.special_fishes)
609
- if fish_name in fish_list:
659
+
660
+ if as_index:
661
+ if not name_or_index.isdigit():
662
+ return "你完全不看帮助是吗  ̄へ ̄"
663
+ load_dict = loads_fishes if not as_special else spec_fishes
664
+ fish_name = get_key_by_index(load_dict, int(name_or_index))
665
+ if not fish_name:
666
+ return "查无此鱼,你再看看这人背包呢?"
667
+ else:
668
+ fish_name = name_or_index
669
+
670
+ if not as_special and fish_name in fish_list:
610
671
  try:
611
672
  loads_fishes[fish_name] += quantity
612
673
  except KeyError:
613
674
  loads_fishes[fish_name] = quantity
675
+ if loads_fishes[fish_name] <= 0:
676
+ del loads_fishes[fish_name]
614
677
  dump_fishes = json.dumps(loads_fishes)
615
678
  user_update = (
616
679
  update(FishingRecord)
@@ -624,6 +687,8 @@ async def give(user_id: str, fish_name: str, quantity: int = 1) -> str:
624
687
  spec_fishes[fish_name] += quantity
625
688
  except KeyError:
626
689
  spec_fishes[fish_name] = quantity
690
+ if spec_fishes[fish_name] <= 0:
691
+ del spec_fishes[fish_name]
627
692
  dump_fishes = json.dumps(spec_fishes)
628
693
  user_update = (
629
694
  update(FishingRecord)
@@ -632,12 +697,97 @@ async def give(user_id: str, fish_name: str, quantity: int = 1) -> str:
632
697
  )
633
698
  await session.execute(user_update)
634
699
  await session.commit()
700
+
701
+ fish_name = (
702
+ fish_name[:20] + "..." + str(len(fish_name) - 20)
703
+ if len(fish_name) > 20
704
+ else fish_name
705
+ )
635
706
  return (
636
- f"使用滥权之力成功将 {fish_name} 添加到 {user_id} 的背包之中 ヾ(≧▽≦*)o"
707
+ f"使用滥权之力成功为 {user_id} {"增加" if quantity >= 0 else "减少"} {abs(quantity)} {fish_name} ヾ(≧▽≦*)o"
637
708
  )
638
709
  return "未查找到用户信息, 无法执行滥权操作 w(゚Д゚)w"
639
710
 
640
711
 
712
+ async def get_all_special_fish() -> dict[str, int]:
713
+ session = get_session()
714
+ async with session.begin():
715
+ random_select = select(SpecialFishes.fish).order_by(SpecialFishes.fish.asc())
716
+ data = await session.scalars(random_select)
717
+ pool = data.all()
718
+
719
+ result = dict()
720
+ for fish in pool:
721
+ try:
722
+ result[fish] += 1
723
+ except KeyError:
724
+ result[fish] = 1
725
+
726
+ return result
727
+
728
+
729
+ async def remove_special_fish(name_or_index: str, as_index: bool = False) -> str | None:
730
+ pool = await get_all_special_fish()
731
+
732
+ if as_index:
733
+ if not name_or_index.isdigit():
734
+ return "你完全不看帮助是吗  ̄へ ̄"
735
+ fish_name = get_key_by_index(pool, int(name_or_index))
736
+ if not fish_name:
737
+ return "查无此鱼"
738
+ else:
739
+ fish_name = name_or_index
740
+ if fish_name not in pool:
741
+ return "查无此鱼"
742
+
743
+ session = get_session()
744
+ async with session.begin():
745
+ delete_fishes = delete(SpecialFishes).where(SpecialFishes.fish == fish_name)
746
+ await session.execute(delete_fishes)
747
+ await session.commit()
748
+
749
+ fish_name = (
750
+ fish_name[:20] + "..." + str(len(fish_name) - 20)
751
+ if len(fish_name) > 20
752
+ else fish_name
753
+ )
754
+
755
+ return f"已成功捞出 {fish_name}"
756
+
757
+
758
+ async def get_pool(name_limit: int = 30, page_limit: int = 200) -> list[MessageSegment]:
759
+ messages: list[MessageSegment] = []
760
+ pool = await get_all_special_fish()
761
+ messages.append(
762
+ MessageSegment.text(f"现在鱼池里面有 {sum(list(pool.values()))} 条鱼。")
763
+ )
764
+
765
+ msg = "鱼池列表:\n"
766
+ i = 0
767
+ j = 1
768
+ for fish, num in pool.items():
769
+ if len(msg) > page_limit:
770
+ fish = (
771
+ fish[:name_limit] + "..." + str(len(fish) - name_limit)
772
+ if len(fish) > name_limit
773
+ else fish
774
+ )
775
+ msg += f"{i}. {fish} x {num}\n"
776
+ msg += f"【第 {j} 页结束】"
777
+ messages.append(MessageSegment.text(msg))
778
+ msg = ""
779
+ i += 1
780
+ j += 1
781
+ else:
782
+ fish = fish[:name_limit] + "..." if len(fish) > name_limit else fish
783
+ msg += f"{i}. {fish} x {num}\n"
784
+ i += 1
785
+ else:
786
+ messages.append(MessageSegment.text(msg))
787
+
788
+ return messages
789
+
790
+
641
791
  async def get_stats(user_id: str) -> str:
642
792
  session = get_session()
643
793
  async with session.begin():
@@ -664,33 +814,35 @@ async def get_backpack(user_id: str) -> list[str]:
664
814
  select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
665
815
  fishes_record = await session.scalar(select_user)
666
816
  if fishes_record:
667
- load_fishes = json.loads(fishes_record.fishes)
668
- sorted_fishes = {
669
- key: load_fishes[key] for key in fish_list if key in load_fishes
817
+ loads_fishes = json.loads(fishes_record.fishes)
818
+ loads_fishes = {
819
+ key: loads_fishes[key] for key in fish_list if key in loads_fishes
670
820
  }
671
- load_special_fishes = json.loads(fishes_record.special_fishes)
672
- if load_special_fishes:
673
- sorted_special_fishes = {
674
- key: load_special_fishes[key] for key in sorted(load_special_fishes)
675
- }
676
- return print_backpack(sorted_fishes, sorted_special_fishes)
821
+ spec_fishes: dict = json.loads(fishes_record.special_fishes)
822
+ if spec_fishes:
823
+ spec_fishes = dict(sorted(spec_fishes.items()))
824
+ return print_backpack(loads_fishes, spec_fishes)
677
825
  return (
678
826
  ["🎒你的背包里空无一物"]
679
- if sorted_fishes == {}
680
- else print_backpack(sorted_fishes)
827
+ if loads_fishes == {}
828
+ else print_backpack(loads_fishes)
681
829
  )
682
830
  return ["🎒你的背包里空无一物"]
683
831
 
684
832
 
685
- def print_backpack(backpack: dict, special_backpack=None) -> list[str]:
686
- result = [
687
- f"{fish_name}×{str(quantity)}" for fish_name, quantity in backpack.items()
688
- ]
833
+ def print_backpack(backpack: dict, special_backpack: dict = None) -> list[str]:
834
+ i = 0
835
+ result = []
836
+ for fish_name, quantity in backpack.items():
837
+ result.append(f"{i}. {fish_name}×{str(quantity)}")
838
+ i += 1
839
+
689
840
  if special_backpack:
690
- special_result = [
691
- f"{fish_name}×{str(quantity)}"
692
- for fish_name, quantity in special_backpack.items()
693
- ]
841
+ i = 0
842
+ special_result: list[str] = []
843
+ for fish_name, quantity in special_backpack.items():
844
+ special_result.append(f"{i}. {fish_name}×{str(quantity)}")
845
+ i += 1
694
846
  return [
695
847
  "🎒普通鱼:\n" + "\n".join(result),
696
848
  "🎒特殊鱼:\n" + "\n".join(special_result),
@@ -1,168 +1,165 @@
1
- Metadata-Version: 2.4
2
- Name: nonebot-plugin-fishing2
3
- Version: 0.0.4
4
- Summary: 更好的电子钓鱼
5
- Author-email: ALittleBot <160833462+C14H22O@users.noreply.github.com>, Polaris_Light <995905922@qq.com>
6
- License-Expression: MIT
7
- Project-URL: Homepage, https://github.com/FDCraft/nonebot-plugin-fishing2
8
- Keywords: fishing
9
- Requires-Python: >=3.8
10
- Description-Content-Type: text/markdown
11
- License-File: LICENSE
12
- Requires-Dist: nonebot2>=2.2.1
13
- Requires-Dist: nonebot-adapter-onebot>=2.0.0-beta.1
14
- Requires-Dist: pydantic>=1.10
15
- Requires-Dist: nonebot-plugin-localstore>=0.6.0
16
- Requires-Dist: sqlalchemy>=2.0.27
17
- Requires-Dist: aiosqlite>=0.20.0
18
- Requires-Dist: nonebot-plugin-orm>=0.7.1
19
- Dynamic: license-file
20
-
21
- <div align="center">
22
- <a href="https://v2.nonebot.dev/store"><img src="https://github.com/A-kirami/nonebot-plugin-template/blob/resources/nbp_logo.png" width="180" height="180" alt="NoneBotPluginLogo"></a>
23
- <br>
24
- <p><img src="https://github.com/A-kirami/nonebot-plugin-template/blob/resources/NoneBotPlugin.svg" width="240" alt="NoneBotPluginText"></p>
25
- </div>
26
-
27
- <div align="center">
28
-
29
- # nonebot-plugin-fishing2
30
-
31
- _✨ 更好的电子钓鱼 ✨_
32
-
33
- <a href="./LICENSE">
34
- <img src="https://img.shields.io/github/license/FDCraft/nonebot-plugin-fishing2.svg" alt="license">
35
- </a>
36
- <a href="https://pypi.python.org/pypi/nonebot-plugin-fishing2">
37
- <img src="https://img.shields.io/pypi/v/nonebot-plugin-fishing2.svg" alt="pypi">
38
- </a>
39
- <img src="https://img.shields.io/badge/python-3.8+-blue.svg" alt="python">
40
-
41
- </div>
42
-
43
- ## 💿 安装
44
-
45
- <details open>
46
- <summary>使用 nb-cli 安装</summary>
47
- nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
48
-
49
- nb plugin install nonebot-plugin-fishing2
50
-
51
- </details>
52
-
53
- <details>
54
- <summary>使用包管理器安装</summary>
55
- 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
56
-
57
- <details>
58
- <summary>pip</summary>
59
-
60
- pip install nonebot-plugin-fishing2
61
- </details>
62
- <details>
63
- <summary>pdm</summary>
64
-
65
- pdm add nonebot-plugin-fishing2
66
- </details>
67
- <details>
68
- <summary>poetry</summary>
69
-
70
- poetry add nonebot-plugin-fishing2
71
- </details>
72
- <details>
73
- <summary>conda</summary>
74
-
75
- conda install nonebot-plugin-fishing2
76
- </details>
77
-
78
- 打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
79
-
80
- plugins = ["nonebot_plugin_fishing2"]
81
-
82
- </details>
83
-
84
- 注意:安装过后,需在控制台输入 `nb orm upgrade` 指令以初始化数据库。本插件数据库与 [Nonebot-plugin-fishing](https://github.com/ALittleBot/nonebot-plugin-fishing) 通用,可以互换。
85
-
86
- ## ⚙️ 配置
87
-
88
- nonebot2 项目的`.env`文件中添加下表中的配置
89
-
90
- | 配置项 | 必填 | 说明 |
91
- |:------------------------:|:----:|:--------------------------------------------------------------:|
92
- | fishes | | 配置鱼塘内的普通鱼(大概是鱼……) |
93
- | fishing_achievement | 否 | 配置钓鱼成就 |
94
- | fishing_coin_name | 否 | 填入卖鱼获取的货币名称 |
95
- | fishing_limit | 否 | 填入每次钓鱼后,限制钓鱼的秒数 |
96
- | punish_limit | 否 | 短时间多次钓鱼后,禁言所需次数,防止刷屏 |
97
- | special_fish_enabled | 否 | 是否启用赛博放生 & 特殊鱼(默认为否) |
98
- | special_fish_price | 否 | 特殊鱼出售的价格 |
99
- | special_fish_free_price | 否 | 特殊鱼放生的价格 |
100
- | special_fish_probability | 否 | 钓上特殊鱼的概率,注意这个判定在空军判定之后 |
101
- | no_fish_probability | 否 | 空军的概率 |
102
- | rare_fish_weight | 否 | 稀有鱼权重分界线,影响 rare_fish 属性与 normal_fish 属性的区分 |
103
- | buy_rate | 否 | 在不指定 buy_price 时,购买价格/基准价格比,应大于 1 |
104
- | backpack_forward | 否 | 背包是否使用聊天记录 |
105
-
106
- 其中 `fishes` 配置项说明如下。预设配置经过了计算以平衡,如果需要自行填表,请使用“钓鱼预测”命令进行预测。
107
-
108
- ```dotenv
109
- FISHES='
110
- [
111
- {
112
- "type": "fish", # 类型,必填,可用值:fish, item,同类型物品不能同时作为鱼饵
113
- "name": "小鱼", # 名称,必填
114
- "price": 15, # 基准价格,必填
115
- "amount": 1, # 单份数量,模拟耐久
116
- "props": [ # 属性,选填,作为鱼饵时改变
117
- {
118
- "type": "rm_fish", # 可用值: rare_fish, normal_fish, fish, rm_fish, special_fish, no_fish
119
- "key": "小鱼", # 如果为 fish 或 rm_fish,需要填写鱼名
120
- "value": 0 # 如果为 rare_fish, normal_fish, fish,填写权重;如果为 special_fish, no_fish,填写概率
121
- }
122
- ],
123
- "description": "一条小鱼。把它当做鱼饵可以防止钓到小鱼。", # 描述,必填
124
- "can_catch": True, # 是否可以抓取,必填
125
- "sleep_time": 2, # 钓上来需要的时间,默认 60
126
- "weight": 1000, # 权重
127
- "can_buy": True, # 是否可以购买,必填
128
- "buy_price": 50, # 购买价格
129
- "can_sell": True # 是否可以出售,必填
130
- },
131
- ]
132
- '
133
- ```
134
-
135
- ## 🔨 更新
136
-
137
- 每一次更新后,需执行 `nb orm upgrade`。
138
-
139
- ## 🎉 使用
140
-
141
- ### 指令表
142
-
143
- 在群聊或私聊发送“钓鱼帮助”查看本插件的帮助,或者使用[NoneBot-Plugin-PicMenu-Next](https://github.com/lgc-NB2Dev/nonebot-plugin-picmenu-next)等帮助插件查看。
144
-
145
- ### 管理员指令表
146
-
147
- | 指令 | 范围 | 说明 |
148
- |:--------:|:----:|:----------------------------------------------:|
149
- | 钓鱼预测 | 所有 | 对钓鱼进行模拟,查看各鱼的概率与期望,便于填表 |
150
- | 鱼池 | 所有 | 查看数据库里面的所有特殊鱼 |
151
-
152
- ### 赛博放生
153
-
154
- 当用户使用货币放生由自己取名的一条鱼后,每个用户在钓鱼时都有机会钓到那一条鱼。但此功能开关 `special_fish_enabled` 默认关闭,原因是用户生成内容如果不符合规范,可能导致出现不可预料的情况,请谨慎开启。
155
-
156
- ## 📝 Todo
157
-
158
- - [x] 重写数据库逻辑(改为使用 [nonebot/plugin-orm](https://github.com/nonebot/plugin-orm))
159
- - [x] 增加系统商店,卖出钓到的鱼
160
- - [x] 赛博放生 [#4](https://github.com/C14H22O/nonebot-plugin-fishing/issues/4) (已基本完成)
161
- - [ ] ~~使用 [nonebot_plugin_chikari_economy](https://github.com/mrqx0195/nonebot_plugin_chikari_economy) 经济系统~~
162
- - [x] 为鱼竿增加耐久度,耐久度为0时需重新购买鱼竿
163
- - [x] 为钓鱼背包添加排序
164
- - [x] 添加成就系统
165
- - [x] 买装备!
166
- - [ ] 支持卖与普通鱼同名的特殊鱼
167
- - [ ] 管理员命令:捞鱼
168
- - [ ] 屏蔽词库
1
+ Metadata-Version: 2.3
2
+ Name: nonebot-plugin-fishing2
3
+ Version: 0.1.1
4
+ Summary: 更好的电子钓鱼
5
+ License: MIT
6
+ Keywords: fishing
7
+ Author: ALittleBot
8
+ Author-email: 160833462+C14H22O@users.noreply.github.com
9
+ Requires-Python: >=3.8
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Requires-Dist: nonebot-adapter-onebot (>=2.0.0-beta.1)
19
+ Requires-Dist: nonebot-plugin-localstore (>=0.6.0)
20
+ Requires-Dist: nonebot-plugin-orm (>=0.7.1)
21
+ Requires-Dist: nonebot2 (>=2.2.1)
22
+ Requires-Dist: pydantic (>=1.10)
23
+ Requires-Dist: sqlalchemy (>=2.0.27)
24
+ Project-URL: Homepage, https://github.com/GLDYM/nonebot-plugin-fishing2
25
+ Description-Content-Type: text/markdown
26
+
27
+ <div align="center">
28
+ <a href="https://v2.nonebot.dev/store">
29
+ <img src="https://raw.githubusercontent.com/fllesser/nonebot-plugin-template/refs/heads/resource/.docs/NoneBotPlugin.svg" width="310" alt="logo"></a>
30
+
31
+ # nonebot-plugin-fishing2
32
+
33
+ _✨ 更好的电子钓鱼 ✨_
34
+
35
+ <a href="./LICENSE">
36
+ <img src="https://img.shields.io/github/license/FDCraft/nonebot-plugin-fishing2.svg" alt="license">
37
+ </a>
38
+ <a href="https://pypi.python.org/pypi/nonebot-plugin-fishing2">
39
+ <img src="https://img.shields.io/pypi/v/nonebot-plugin-fishing2.svg" alt="pypi">
40
+ </a>
41
+ <img src="https://img.shields.io/badge/python-3.8+-blue.svg" alt="python">
42
+
43
+ </div>
44
+
45
+ ## 💿 安装
46
+
47
+ <details open>
48
+ <summary>使用 nb-cli 安装</summary>
49
+ nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
50
+
51
+ nb plugin install nonebot-plugin-fishing2
52
+
53
+ </details>
54
+
55
+ <details>
56
+ <summary>使用包管理器安装</summary>
57
+ 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
58
+
59
+ <details>
60
+ <summary>pip</summary>
61
+
62
+ pip install nonebot-plugin-fishing2
63
+ </details>
64
+ <details>
65
+ <summary>pdm</summary>
66
+
67
+ pdm add nonebot-plugin-fishing2
68
+ </details>
69
+ <details>
70
+ <summary>poetry</summary>
71
+
72
+ poetry add nonebot-plugin-fishing2
73
+ </details>
74
+ <details>
75
+ <summary>conda</summary>
76
+
77
+ conda install nonebot-plugin-fishing2
78
+ </details>
79
+
80
+ 打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分追加写入
81
+
82
+ plugins = ["nonebot_plugin_fishing2"]
83
+
84
+ </details>
85
+
86
+ 注意:安装过后,需在控制台输入 `nb orm upgrade` 指令以初始化数据库。本插件数据库与 [Nonebot-plugin-fishing](https://github.com/ALittleBot/nonebot-plugin-fishing) 通用,可以互换。
87
+
88
+ ## ⚙️ 配置
89
+
90
+ nonebot2 项目的`.env`文件中添加下表中的配置
91
+
92
+ | 配置项 | 必填 | 说明 |
93
+ |:-------------------------:|:----:|:--------------------------------------------------------------:|
94
+ | fishes | 否 | 鱼塘内的普通鱼(大概是鱼……) |
95
+ | fishing_achievement | 否 | 钓鱼成就 |
96
+ | fishing_coin_name | 否 | 卖鱼获取的货币名称 |
97
+ | fishing_cooldown_time_min | 否 | 钓鱼冷却下限,单位为秒 |
98
+ | fishing_cooldown_time_max | 否 | 钓鱼冷却上限 |
99
+ | punish_limit | 否 | 短时间多次钓鱼后,禁言所需次数,防止刷屏 |
100
+ | special_fish_enabled | 否 | 是否启用赛博放生 & 特殊鱼(默认为否) |
101
+ | special_fish_price | 否 | 特殊鱼出售的价格 |
102
+ | special_fish_free_price | 否 | 特殊鱼放生的价格 |
103
+ | special_fish_probability | 否 | 钓上特殊鱼的概率,注意这个判定在空军判定之后 |
104
+ | no_fish_probability | 否 | 空军的概率 |
105
+ | rare_fish_weight | 否 | 稀有鱼权重分界线,影响 rare_fish 属性与 normal_fish 属性的区分 |
106
+ | buy_rate | 否 | 在不指定 buy_price 时,购买价格/基准价格比,应大于 1 |
107
+ | backpack_forward | 否 | 背包是否使用聊天记录 |
108
+
109
+ 其中 `fishes` 配置项说明如下。预设配置经过了计算以平衡,如果需要自行填表,请使用“钓鱼预测”命令进行预测。
110
+
111
+ ```dotenv
112
+ FISHES='
113
+ [
114
+ {
115
+ "type": "fish", # 类型,必填,可用值:fish, item,同类型物品不能同时作为鱼饵
116
+ "name": "小鱼", # 名称,必填
117
+ "price": 15, # 基准价格,必填
118
+ "amount": 1, # 单份数量,模拟耐久
119
+ "props": [ # 属性,选填,作为鱼饵时改变
120
+ {
121
+ "type": "rm_fish", # 可用值: rare_fish, normal_fish, fish, rm_fish, special_fish, no_fish
122
+ "key": "小鱼", # 如果为 fish 或 rm_fish,需要填写鱼名
123
+ "value": 0 # 如果为 rare_fish, normal_fish, fish,填写权重;如果为 special_fish, no_fish,填写概率
124
+ }
125
+ ],
126
+ "description": "一条小鱼。把它当做鱼饵可以防止钓到小鱼。", # 描述,必填
127
+ "can_catch": True, # 是否可以抓取,必填
128
+ "sleep_time": 2, # 钓上来需要的时间,默认 60
129
+ "weight": 1000, # 权重
130
+ "can_buy": True, # 是否可以购买,必填
131
+ "buy_price": 50, # 购买价格
132
+ "can_sell": True # 是否可以出售,必填
133
+ },
134
+ ]
135
+ '
136
+ ```
137
+
138
+ ## 🔨 更新
139
+
140
+ 每一次更新后,需执行 `nb orm upgrade`。
141
+
142
+ ## 🎉 使用
143
+
144
+ ### 指令表
145
+
146
+ 在群聊或私聊发送“钓鱼帮助”查看本插件的帮助,或者使用[NoneBot-Plugin-PicMenu-Next](https://github.com/lgc-NB2Dev/nonebot-plugin-picmenu-next)等帮助插件查看。管理员指令默认隐藏,只能由 SUPERUSER 发送“钓鱼帮助”查看。
147
+
148
+ ### 赛博放生
149
+
150
+ 当用户使用货币放生由自己取名的一条鱼后,每个用户在钓鱼时都有机会钓到那一条鱼。但此功能开关 `special_fish_enabled` 默认关闭,原因是用户生成内容如果不符合规范,可能导致出现不可预料的情况,请谨慎开启。
151
+
152
+ ## 📝 Todo
153
+
154
+ - [x] 重写数据库逻辑(改为使用 [nonebot/plugin-orm](https://github.com/nonebot/plugin-orm))
155
+ - [x] 增加系统商店,卖出钓到的鱼
156
+ - [x] 赛博放生 [#4](https://github.com/C14H22O/nonebot-plugin-fishing/issues/4) (已基本完成)
157
+ - [ ] ~~使用 [nonebot_plugin_chikari_economy](https://github.com/mrqx0195/nonebot_plugin_chikari_economy) 经济系统~~
158
+ - [x] 为鱼竿增加耐久度,耐久度为0时需重新购买鱼竿
159
+ - [x] 为钓鱼背包添加排序
160
+ - [x] 添加成就系统
161
+ - [x] 买装备!
162
+ - [x] 支持卖与普通鱼同名的特殊鱼
163
+ - [x] 管理员命令:捞鱼
164
+ - [ ] 屏蔽词库
165
+
@@ -1,15 +1,14 @@
1
- nonebot_plugin_fishing2/__init__.py,sha256=69eM0yZaNrksVda9zWygA5JBr2gAua-mBugdLWVNHgg,16507
2
- nonebot_plugin_fishing2/config.py,sha256=FWrOFQXv-W7VAB8T0zN4Elm_fRycUpGua8Ee9ABPSG4,9882
3
- nonebot_plugin_fishing2/data_source.py,sha256=A1gWZFqBh1Exmmpy6RVXw9SvdPkWNcmdjCNaxbH-QGE,29791
1
+ nonebot_plugin_fishing2/__init__.py,sha256=P-rLNXG2ZmdfzU7UXSwWrnh4jT8OI2fsm3LPy6COrh8,20200
2
+ nonebot_plugin_fishing2/config.py,sha256=xYDdq9Rwce8vfg-M91lUd2TfZDQnToHlI77GdpLFp-U,9751
3
+ nonebot_plugin_fishing2/data_source.py,sha256=fbIWF4nJ1GVQ17UCue_RcEPxi_2oRmByhkveAXI_6oU,34488
4
4
  nonebot_plugin_fishing2/fish_helper.py,sha256=Rf3SX4UcM0-E6apLUbHB40I4onK-8qPZmZrsVBMnZ3I,6054
5
- nonebot_plugin_fishing2/model.py,sha256=_DtmxiQhJDiIvY1XOMQZ0HA-ruWY0bexWX9frdhnk0Q,752
6
5
  nonebot_plugin_fishing2/migrations/68463f3e5f33_.py,sha256=WnaV5T1uCHvYWcnepHqV9kOurDYddFUvXXfA2Rtd5Ok,776
7
6
  nonebot_plugin_fishing2/migrations/7609e6d106dd_init_db.py,sha256=tpuIfsS6yPsnGIeMPo16exsEfYZ_urgYAqlCyQ8aw-Y,1386
8
7
  nonebot_plugin_fishing2/migrations/c5ab992c9af3_add_achievements.py,sha256=KVj9ADeP03zfW4ZBDmnghbWdxLor3u1yKeho0GaddCI,1119
9
8
  nonebot_plugin_fishing2/migrations/e9015df43907_add_special_fishes_field.py,sha256=R4p9vPD5lgg4vmY2KUgF2qIlraxhPYkL93lM5l7wMZw,1094
10
9
  nonebot_plugin_fishing2/migrations/f70bdeaec7a4_add_specialfishes_table.py,sha256=DUqv9MTaOSZCBj_9oT2eY3pmWeMnyH0cPj9GyYa5Sag,1194
11
- nonebot_plugin_fishing2-0.0.4.dist-info/licenses/LICENSE,sha256=n-2xoOXX434-tBisMKX2-_FycV2VrmIiTP1rZvuW_fY,1091
12
- nonebot_plugin_fishing2-0.0.4.dist-info/METADATA,sha256=eEqw2ELRV8AHohuC-eMe2YxM-5OZptummJKA4Ky9QD4,7541
13
- nonebot_plugin_fishing2-0.0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
- nonebot_plugin_fishing2-0.0.4.dist-info/top_level.txt,sha256=nSgqw96Nh44l966KEYkw0rbdyEJyzi2V7jCZ1kCZIps,24
15
- nonebot_plugin_fishing2-0.0.4.dist-info/RECORD,,
10
+ nonebot_plugin_fishing2/model.py,sha256=_DtmxiQhJDiIvY1XOMQZ0HA-ruWY0bexWX9frdhnk0Q,752
11
+ nonebot_plugin_fishing2-0.1.1.dist-info/LICENSE,sha256=n-2xoOXX434-tBisMKX2-_FycV2VrmIiTP1rZvuW_fY,1091
12
+ nonebot_plugin_fishing2-0.1.1.dist-info/METADATA,sha256=-sV5ctEfIgmreAt6aDgmEPA6GRUeskeBk4XEpeV2JQ4,7355
13
+ nonebot_plugin_fishing2-0.1.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
14
+ nonebot_plugin_fishing2-0.1.1.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -1 +0,0 @@
1
- nonebot_plugin_fishing2