nonebot-plugin-fishing2 0.1.0__py3-none-any.whl → 1.0.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.
@@ -1,776 +1,920 @@
1
- import asyncio
2
- import copy
3
- import random
4
- import time
5
- import json
6
-
7
- from typing import Union
8
- from sqlalchemy import select, update, delete
9
- from sqlalchemy.sql.expression import func
10
- from nonebot.adapters.onebot.v11 import MessageSegment
11
- from nonebot_plugin_orm import get_session
12
-
13
- from .config import config
14
- from .model import FishingRecord, SpecialFishes
15
- from .fish_helper import *
16
-
17
-
18
- async def can_fishing(user_id: str) -> bool:
19
- time_now = int(time.time())
20
- session = get_session()
21
- async with session.begin():
22
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
23
- record = await session.scalar(select_user)
24
- return True if not record else record.time < time_now
25
-
26
-
27
- async def can_catch_special_fish(probability_add: int):
28
- session = get_session()
29
- async with session.begin():
30
- records = await session.execute(select(SpecialFishes))
31
- return (
32
- len(records.all()) != 0
33
- and random.random() <= config.special_fish_probability + probability_add
34
- )
35
-
36
-
37
- async def check_tools(
38
- user_id: str, tools: list[str] = None, check_have: bool = True
39
- ) -> str | None:
40
- if not tools or tools == []:
41
- return None
42
-
43
- # 这是工具吗?
44
- for tool in tools:
45
- fish = get_fish_by_name(tool)
46
- if not fish:
47
- return f"你在用什么钓鱼……?{tool}?"
48
-
49
- props = fish.props
50
- if not props or props == []:
51
- return f"搞啥嘞!{tool}既不是工具也不是鱼饵!"
52
-
53
- # 如果有两个工具,是一个工具一个鱼饵吗?
54
- if len(tools) == 2:
55
- if get_fish_by_name(tools[0]).type == get_fish_by_name(tools[1]).type:
56
- return "你为啥要用两个类型一样的东西?"
57
-
58
- # 有吗?有吗?
59
- if check_have:
60
- session = get_session()
61
- async with session.begin():
62
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
63
- fishes_record = await session.scalar(select_user)
64
- if fishes_record:
65
- loads_fishes = json.loads(fishes_record.fishes)
66
- for tool in tools:
67
- if tool not in loads_fishes:
68
- return f"你哪来的{tool}"
69
-
70
- return None
71
-
72
-
73
- async def remove_tools(user_id: str, tools: list[str] = None) -> None:
74
- if not tools or tools == []:
75
- return None
76
-
77
- session = get_session()
78
- async with session.begin():
79
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
80
- fishes_record = await session.scalar(select_user)
81
- if fishes_record:
82
- loads_fishes = json.loads(fishes_record.fishes)
83
- for tool_name in tools:
84
- loads_fishes[tool_name] -= 1
85
- if loads_fishes[tool_name] == 0:
86
- del loads_fishes[tool_name]
87
- dump_fishes = json.dumps(loads_fishes)
88
- user_update = (
89
- update(FishingRecord)
90
- .where(FishingRecord.user_id == user_id)
91
- .values(fishes=dump_fishes)
92
- )
93
- await session.execute(user_update)
94
- await session.commit()
95
- else:
96
- pass
97
- # raise ValueError("?你的 Check 是怎么通过的?")
98
-
99
-
100
- def get_adjusts_from_tools(tools: list = None) -> list:
101
- no_add = 0
102
- sp_add = 0
103
- adjusts: list[Property] = []
104
-
105
- if tools:
106
- for tool in tools:
107
- adjusts += get_fish_by_name(tool).props
108
-
109
- for adjust in adjusts:
110
- if adjust.type == "special_fish":
111
- sp_add += adjust.value
112
- if adjust.type == "no_fish":
113
- no_add += adjust.value
114
-
115
- return adjusts, no_add, sp_add
116
-
117
-
118
- def adjusted(adjusts: list[Property] = None) -> tuple:
119
- adjusted_fishes = copy.deepcopy(can_catch_fishes)
120
-
121
- for adjust in adjusts:
122
- if adjust.key and adjust.key not in adjusted_fishes:
123
- continue
124
- match adjust.type:
125
- case "normal_fish":
126
- for key, weight in can_catch_fishes.items():
127
- if weight >= config.rare_fish_weight and key in adjusted_fishes:
128
- adjusted_fishes[key] += adjust.value
129
- case "rare_fish":
130
- for key, weight in can_catch_fishes.items():
131
- if weight < config.rare_fish_weight and key in adjusted_fishes:
132
- adjusted_fishes[key] += adjust.value
133
- case "fish":
134
- adjusted_fishes[adjust.key] += adjust.value
135
- case "rm_fish":
136
- adjusted_fishes.pop(adjust.key)
137
- case "special_fish" | "no_fish":
138
- pass
139
- case _:
140
- pass
141
-
142
- adjusted_fishes_list = list(adjusted_fishes.keys())
143
- adjusted_weights = list(adjusted_fishes.values())
144
-
145
- for i in range(len(adjusted_weights)):
146
- if adjusted_weights[i] < 0:
147
- adjusted_weights[i] = 0
148
-
149
- return adjusted_fishes_list, adjusted_weights
150
-
151
-
152
- def choice(adjusts: list[Property] = None) -> str:
153
- adjusted_fishes_list, adjusted_weights = adjusted(adjusts)
154
- choices = random.choices(
155
- adjusted_fishes_list,
156
- weights=adjusted_weights,
157
- )
158
- return choices[0]
159
-
160
-
161
- async def get_fish(user_id: int, tools: list = None) -> str:
162
- adjusts, no_add, sp_add = get_adjusts_from_tools(tools)
163
-
164
- if random.random() < config.no_fish_probability + no_add:
165
- await asyncio.sleep(random.randint(10, 20))
166
- return "QAQ你空军了,什么都没钓到"
167
-
168
- if await can_catch_special_fish(sp_add):
169
- special_fish_name = await random_get_a_special_fish()
170
- await asyncio.sleep(random.randint(10, 20))
171
- await save_special_fish(user_id, special_fish_name)
172
- result = f"你钓到了别人放生的 {special_fish_name}"
173
- return result
174
-
175
- fish = choice(adjusts)
176
- sleep_time = get_fish_by_name(fish).sleep_time
177
- result = f"钓到了一条{fish}, 你把它收进了背包里"
178
- await asyncio.sleep(sleep_time)
179
- await save_fish(user_id, fish)
180
- return result
181
-
182
-
183
- def predict(tools: list = None) -> str:
184
- no = config.no_fish_probability
185
- sp = config.special_fish_probability
186
- sp_price = config.special_fish_price
187
- result = ""
188
-
189
- adjusts, no_add, sp_add = get_adjusts_from_tools(tools)
190
- sp_t = min(max(sp + sp_add, 0), 1)
191
- no_t = min(max(no + no_add, 0), 1)
192
-
193
- # 拉取矫正权重
194
- adjusted_fishes_list, adjusted_weights = adjusted(adjusts)
195
-
196
- adjusted_fishes_value = []
197
- for fish_name in adjusted_fishes_list:
198
- fish = get_fish_by_name(fish_name)
199
- adjusted_fishes_value.append(int(fish.price * fish.amount))
200
-
201
- # 归一化
202
- total_weight = sum(adjusted_weights)
203
- probabilities = [w / total_weight for w in adjusted_weights]
204
- expected_value = sum(v * p for v, p in zip(adjusted_fishes_value, probabilities))
205
-
206
- result += f"鱼列表:[{', '.join(adjusted_fishes_list)}]\n"
207
- result += f"概率列表: [{', '.join([str(round(w * 100, 2)) + "%" for w in probabilities])}]\n"
208
- result += f"特殊鱼概率:{round(sp_t * (1 - no_t), 6)}\n"
209
- result += f"空军概率:{round(no_t, 6)}\n"
210
-
211
- # 无特殊鱼
212
- expected_value = expected_value * (1 - no_t)
213
- result += f"无特殊鱼时期望为:{expected_value:.3f}\n"
214
-
215
- # 有特殊鱼
216
- expected_value = expected_value * (1 - sp_t) + sp_price * sp_t * (1 - no_t)
217
- result += f"有特殊鱼期望为:{expected_value:.3f}"
218
-
219
- return result
220
-
221
-
222
- async def random_get_a_special_fish() -> str:
223
- session = get_session()
224
- async with session.begin():
225
- random_select = select(SpecialFishes).order_by(func.random())
226
- data = await session.scalar(random_select)
227
- return data.fish
228
-
229
-
230
- async def check_achievement(user_id: str) -> str | None:
231
- session = get_session()
232
- async with session.begin():
233
- record = await session.scalar(
234
- select(FishingRecord).where(FishingRecord.user_id == user_id)
235
- )
236
- if not record:
237
- return None
238
- fishing_frequency = record.frequency
239
- user_fishes = json.loads(record.fishes)
240
- achievements = config_achievements
241
- result_list = []
242
- for achievement in achievements:
243
- achievement_name = achievement.name
244
- if await is_exists_achievement(user_id, achievement_name):
245
- continue
246
- if (
247
- achievement.type == "fishing_frequency"
248
- and achievement.data <= fishing_frequency
249
- ) or (achievement.type == "fish_type" and achievement.data in user_fishes):
250
- await save_achievement(user_id, achievement_name)
251
- result_list.append(
252
- f"""达成成就: {achievement_name}\n{achievement.description}"""
253
- )
254
- return result_list if result_list != [] else None
255
-
256
-
257
- async def is_exists_achievement(user_id: str, achievement_name: str) -> bool:
258
- session = get_session()
259
- async with session.begin():
260
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
261
- record = await session.scalar(select_user)
262
- if record:
263
- loads_achievements = json.loads(record.achievements)
264
- return achievement_name in loads_achievements
265
- return False
266
-
267
-
268
- async def save_achievement(user_id: str, achievement_name: str):
269
- time_now = int(time.time())
270
- session = get_session()
271
- async with session.begin():
272
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
273
- record = await session.scalar(select_user)
274
- if record:
275
- loads_achievements = json.loads(record.achievements)
276
- loads_achievements.append(achievement_name)
277
- dump_achievements = json.dumps(loads_achievements)
278
- user_update = (
279
- update(FishingRecord)
280
- .where(FishingRecord.user_id == user_id)
281
- .values(achievements=dump_achievements)
282
- )
283
- await session.execute(user_update)
284
- await session.commit()
285
- return
286
- data = []
287
- dump_achievements = json.dumps(data)
288
- new_record = FishingRecord(
289
- user_id=user_id,
290
- time=time_now,
291
- frequency=0,
292
- fishes="{}",
293
- special_fishes="{}",
294
- coin=0,
295
- achievements=dump_achievements,
296
- )
297
- session.add(new_record)
298
- await session.commit()
299
-
300
-
301
- async def save_fish(user_id: str, fish_name: str) -> None:
302
- time_now = int(time.time())
303
- fishing_cooldown = random.randint(
304
- config.fishing_cooldown_time_min, config.fishing_cooldown_time_max
305
- )
306
- amount = get_fish_by_name(fish_name).amount
307
- session = get_session()
308
- async with session.begin():
309
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
310
- record = await session.scalar(select_user)
311
- if record:
312
- loads_fishes = json.loads(record.fishes)
313
- try:
314
- loads_fishes[fish_name] += amount
315
- except KeyError:
316
- loads_fishes[fish_name] = amount
317
- dump_fishes = json.dumps(loads_fishes)
318
- new_frequency = record.frequency + 1
319
- user_update = (
320
- update(FishingRecord)
321
- .where(FishingRecord.user_id == user_id)
322
- .values(
323
- time=time_now + fishing_cooldown,
324
- frequency=new_frequency,
325
- fishes=dump_fishes,
326
- )
327
- )
328
- await session.execute(user_update)
329
- await session.commit()
330
- return
331
- data = {fish_name: amount}
332
- dump_fishes = json.dumps(data)
333
- new_record = FishingRecord(
334
- user_id=user_id,
335
- time=time_now + fishing_cooldown,
336
- frequency=1,
337
- fishes=dump_fishes,
338
- special_fishes="{}",
339
- coin=0,
340
- achievements="[]",
341
- )
342
- session.add(new_record)
343
- await session.commit()
344
-
345
-
346
- async def save_special_fish(user_id: str, fish_name: str) -> None:
347
- time_now = int(time.time())
348
- fishing_cooldown = random.randint(
349
- config.fishing_cooldown_time_min, config.fishing_cooldown_time_max
350
- )
351
- session = get_session()
352
- async with session.begin():
353
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
354
- record = await session.scalar(select_user)
355
- if record:
356
- loads_fishes = json.loads(record.special_fishes)
357
- try:
358
- loads_fishes[fish_name] += 1
359
- except KeyError:
360
- loads_fishes[fish_name] = 1
361
- dump_fishes = json.dumps(loads_fishes)
362
- user_update = (
363
- update(FishingRecord)
364
- .where(FishingRecord.user_id == user_id)
365
- .values(
366
- time=time_now + fishing_cooldown,
367
- frequency=record.frequency + 1,
368
- special_fishes=dump_fishes,
369
- )
370
- )
371
- await session.execute(user_update)
372
- else:
373
- data = {fish_name: 1}
374
- dump_fishes = json.dumps(data)
375
- new_record = FishingRecord(
376
- user_id=user_id,
377
- time=time_now + fishing_cooldown,
378
- frequency=1,
379
- fishes="{}",
380
- special_fishes=dump_fishes,
381
- coin=0,
382
- achievements=[],
383
- )
384
- session.add(new_record)
385
- select_fish = (
386
- select(SpecialFishes)
387
- .where(SpecialFishes.fish == fish_name)
388
- .order_by(SpecialFishes.id)
389
- .limit(1)
390
- )
391
- record = await session.scalar(select_fish)
392
- fish_id = record.id
393
- delete_fishes = delete(SpecialFishes).where(SpecialFishes.id == fish_id)
394
- await session.execute(delete_fishes)
395
- await session.commit()
396
-
397
-
398
- async def sell_fish(user_id: str, fish_name: str, quantity: int = 1) -> str:
399
- if quantity <= 0:
400
- return "你在卖什么 w(゚Д゚)w"
401
- session = get_session()
402
- async with session.begin():
403
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
404
- fishes_record = await session.scalar(select_user)
405
- if fishes_record := fishes_record:
406
- loads_fishes = json.loads(fishes_record.fishes)
407
- spec_fishes = json.loads(fishes_record.special_fishes)
408
- if fish_name in loads_fishes and loads_fishes[fish_name] > 0:
409
- if fish_name not in can_sell_fishes:
410
- return f"这个 {fish_name} 不可以卖哦~"
411
- if loads_fishes[fish_name] < quantity:
412
- return f"你没有那么多 {fish_name}"
413
- fish_price = get_fish_by_name(fish_name).price
414
- loads_fishes[fish_name] -= quantity
415
- if loads_fishes[fish_name] == 0:
416
- del loads_fishes[fish_name]
417
- dump_fishes = json.dumps(loads_fishes)
418
- user_update = (
419
- update(FishingRecord)
420
- .where(FishingRecord.user_id == user_id)
421
- .values(
422
- coin=fishes_record.coin + fish_price * quantity,
423
- fishes=dump_fishes,
424
- )
425
- )
426
- await session.execute(user_update)
427
- await session.commit()
428
- return (
429
- f"你以 {fish_price} {fishing_coin_name} / 条的价格卖出了 {quantity} 条 {fish_name}, "
430
- f"你获得了 {fish_price * quantity} {fishing_coin_name}"
431
- )
432
- elif fish_name in spec_fishes and spec_fishes[fish_name] > 0:
433
- fish_price = config.special_fish_price
434
- if spec_fishes[fish_name] < quantity:
435
- return f"你没有那么多 {fish_name}"
436
- spec_fishes[fish_name] -= quantity
437
- if spec_fishes[fish_name] == 0:
438
- del spec_fishes[fish_name]
439
- dump_fishes = json.dumps(spec_fishes)
440
- user_update = (
441
- update(FishingRecord)
442
- .where(FishingRecord.user_id == user_id)
443
- .values(
444
- coin=fishes_record.coin + fish_price * quantity,
445
- special_fishes=dump_fishes,
446
- )
447
- )
448
- await session.execute(user_update)
449
- await session.commit()
450
- return (
451
- f"你以 {fish_price} {fishing_coin_name} / 条的价格卖出了 {quantity} 条 {fish_name}, "
452
- f"获得了 {fish_price * quantity} {fishing_coin_name}"
453
- )
454
- else:
455
- return "查无此鱼"
456
- else:
457
- return "还没钓鱼就想卖鱼?"
458
-
459
-
460
- async def buy_fish(user_id: str, fish_name: str, quantity: int = 1) -> str:
461
- if quantity <= 0:
462
- return "别在渔具店老板面前炫耀自己的鱼 (..-˘ ˘-.#)"
463
- if fish_name not in can_buy_fishes:
464
- return "商店不卖这个!"
465
-
466
- fish = get_fish_by_name(fish_name)
467
- total_price = int(fish.buy_price * fish.amount * quantity)
468
-
469
- session = get_session()
470
- async with session.begin():
471
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
472
- fishes_record = await session.scalar(select_user)
473
- if fishes_record := fishes_record:
474
- loads_fishes = json.loads(fishes_record.fishes)
475
- user_coin = fishes_record.coin
476
- if user_coin < total_price:
477
- coin_less = str(total_price - fishes_record.coin)
478
- return f"你没有足够的 {fishing_coin_name}, 还需 {coin_less} {fishing_coin_name}"
479
- user_coin -= total_price
480
- try:
481
- loads_fishes[fish_name] += fish.amount * quantity
482
- except KeyError:
483
- loads_fishes[fish_name] = fish.amount * quantity
484
- dump_fishes = json.dumps(loads_fishes)
485
- user_update = (
486
- update(FishingRecord)
487
- .where(FishingRecord.user_id == user_id)
488
- .values(coin=user_coin, fishes=dump_fishes)
489
- )
490
- await session.execute(user_update)
491
- await session.commit()
492
- return f"你用 {total_price} {fishing_coin_name} 买入了 {quantity} 份 {fish_name}"
493
- else:
494
- return "不想钓鱼的人就别在渔具店逛了~"
495
-
496
-
497
- async def free_fish(user_id: str, fish_name: str) -> str:
498
- session = get_session()
499
- async with session.begin():
500
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
501
- fishes_record = await session.scalar(select_user)
502
- if fishes_record:
503
- user_coin = fishes_record.coin
504
- spec_fishes = json.loads(fishes_record.special_fishes)
505
- if fish_name in spec_fishes and spec_fishes[fish_name] > 0:
506
- spec_fishes[fish_name] -= 1
507
- if spec_fishes[fish_name] == 0:
508
- del spec_fishes[fish_name]
509
- new_record = SpecialFishes(user_id=user_id, fish=fish_name)
510
- session.add(new_record)
511
- dump_fishes = json.dumps(spec_fishes)
512
- user_update = (
513
- update(FishingRecord)
514
- .where(FishingRecord.user_id == user_id)
515
- .values(special_fishes=dump_fishes)
516
- )
517
- await session.execute(user_update)
518
- await session.commit()
519
- return f"你再次放生了 {fish_name}, 未来或许会被有缘人钓到呢"
520
- else:
521
- if fish_name in fish_list:
522
- return "普通鱼不能放生哦~"
523
-
524
- if user_coin < config.special_fish_free_price:
525
- special_fish_coin_less = str(
526
- config.special_fish_free_price - fishes_record.coin
527
- )
528
- return f"你没有足够的 {fishing_coin_name}, 还需 {special_fish_coin_less} {fishing_coin_name}"
529
- user_coin -= config.special_fish_free_price
530
- new_record = SpecialFishes(user_id=user_id, fish=fish_name)
531
- session.add(new_record)
532
- user_update = (
533
- update(FishingRecord)
534
- .where(FishingRecord.user_id == user_id)
535
- .values(coin=user_coin)
536
- )
537
- await session.execute(user_update)
538
- await session.commit()
539
- return f"你花费 {config.special_fish_free_price} {fishing_coin_name} 放生了 {fish_name}, 未来或许会被有缘人钓到呢"
540
- return "你甚至还没钓过鱼"
541
-
542
-
543
- async def lottery(user_id: str) -> str:
544
- """算法来自于 https://github.com/fossifer/minesweeperbot/blob/master/cards.py"""
545
- session = get_session()
546
- time_now = int(time.time())
547
- fishing_cooldown = random.randint(
548
- config.fishing_cooldown_time_min, config.fishing_cooldown_time_max
549
- )
550
- async with session.begin():
551
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
552
- fishes_record = await session.scalar(select_user)
553
- if fishes_record:
554
- user_coin = fishes_record.coin
555
- if user_coin <= 30:
556
- new_coin = random.randrange(1, 50)
557
- user_update = (
558
- update(FishingRecord)
559
- .where(FishingRecord.user_id == user_id)
560
- .values(
561
- time=time_now + fishing_cooldown,
562
- coin=fishes_record.coin + new_coin,
563
- )
564
- )
565
- await session.execute(user_update)
566
- await session.commit()
567
- return f"你穷得连河神都看不下去了,给了你 {new_coin} {fishing_coin_name} w(゚Д゚)w"
568
- new_coin = abs(user_coin) / 3
569
- new_coin = random.randrange(5000, 15000) / 10000 * new_coin
570
- new_coin = int(new_coin) if new_coin > 1 else 1
571
- new_coin *= random.randrange(-1, 2, 2)
572
- user_update = (
573
- update(FishingRecord)
574
- .where(FishingRecord.user_id == user_id)
575
- .values(
576
- time=time_now + fishing_cooldown,
577
- coin=fishes_record.coin + new_coin,
578
- )
579
- )
580
- await session.execute(user_update)
581
- await session.commit()
582
- return f'你{"获得" if new_coin >= 0 else "血亏"}了 {abs(new_coin)} {fishing_coin_name}'
583
- else:
584
- return "河神没有回应你……"
585
-
586
-
587
- async def give(user_id: str, fish_name: str, quantity: int = 1) -> str:
588
- session = get_session()
589
- async with session.begin():
590
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
591
- record = await session.scalar(select_user)
592
- if record:
593
- if fish_name == "coin" or fish_name == fishing_coin_name:
594
- user_update = (
595
- update(FishingRecord)
596
- .where(FishingRecord.user_id == user_id)
597
- .values(
598
- coin=record.coin + quantity,
599
- )
600
- )
601
- await session.execute(user_update)
602
- await session.commit()
603
- return f"使用滥权之力成功为 {user_id} {"增加" if quantity >= 0 else "减少"} {abs(quantity)} {fishing_coin_name} ヾ(≧▽≦*)o"
604
- loads_fishes = json.loads(record.fishes)
605
- spec_fishes = json.loads(record.special_fishes)
606
- if fish_name in fish_list:
607
- try:
608
- loads_fishes[fish_name] += quantity
609
- except KeyError:
610
- loads_fishes[fish_name] = quantity
611
- dump_fishes = json.dumps(loads_fishes)
612
- user_update = (
613
- update(FishingRecord)
614
- .where(FishingRecord.user_id == user_id)
615
- .values(fishes=dump_fishes)
616
- )
617
- await session.execute(user_update)
618
- await session.commit()
619
- else:
620
- try:
621
- spec_fishes[fish_name] += quantity
622
- except KeyError:
623
- spec_fishes[fish_name] = quantity
624
- dump_fishes = json.dumps(spec_fishes)
625
- user_update = (
626
- update(FishingRecord)
627
- .where(FishingRecord.user_id == user_id)
628
- .values(special_fishes=dump_fishes)
629
- )
630
- await session.execute(user_update)
631
- await session.commit()
632
- return (
633
- f"使用滥权之力成功将 {fish_name} 添加到 {user_id} 的背包之中 ヾ(≧▽≦*)o"
634
- )
635
- return "未查找到用户信息, 无法执行滥权操作 w(゚Д゚)w"
636
-
637
-
638
- async def get_all_special_fish() -> list[str]:
639
- session = get_session()
640
- async with session.begin():
641
- random_select = select(SpecialFishes.fish).order_by(SpecialFishes.fish.asc())
642
- data = await session.scalars(random_select)
643
- result = data.all()
644
- return result
645
-
646
-
647
- async def get_pool() -> list[MessageSegment]:
648
-
649
- messages: list[MessageSegment] = []
650
- pool = await get_all_special_fish()
651
- messages.append(MessageSegment.text(f"现在鱼池里面有 {len(pool)} 条鱼。"))
652
-
653
- result = dict()
654
- for fish in pool:
655
- try:
656
- result[fish] += 1
657
- except KeyError:
658
- result[fish] = 1
659
-
660
- msg = "鱼池列表:\n"
661
- for fish, num in result.items():
662
- if len(msg) > 300:
663
- msg += f"{fish} x {num}"
664
- messages.append(MessageSegment.text(msg))
665
- msg = ""
666
- else:
667
- msg += f"{fish} x {num}\n"
668
- else:
669
- messages.append(MessageSegment.text(msg))
670
-
671
- return messages
672
-
673
-
674
- async def get_stats(user_id: str) -> str:
675
- session = get_session()
676
- async with session.begin():
677
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
678
- fishing_record = await session.scalar(select_user)
679
- if fishing_record:
680
- return f"🐟你钓上了 {fishing_record.frequency} 条鱼"
681
- return "🐟你还没有钓过鱼,快去钓鱼吧"
682
-
683
-
684
- async def get_balance(user_id: str) -> str:
685
- session = get_session()
686
- async with session.begin():
687
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
688
- fishes_record = await session.scalar(select_user)
689
- if fishes_record:
690
- return f"🪙你有 {fishes_record.coin} {fishing_coin_name}"
691
- return "🪙你什么也没有 :)"
692
-
693
-
694
- async def get_backpack(user_id: str) -> list[str]:
695
- session = get_session()
696
- async with session.begin():
697
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
698
- fishes_record = await session.scalar(select_user)
699
- if fishes_record:
700
- load_fishes = json.loads(fishes_record.fishes)
701
- sorted_fishes = {
702
- key: load_fishes[key] for key in fish_list if key in load_fishes
703
- }
704
- load_special_fishes = json.loads(fishes_record.special_fishes)
705
- if load_special_fishes:
706
- sorted_special_fishes = {
707
- key: load_special_fishes[key] for key in sorted(load_special_fishes)
708
- }
709
- return print_backpack(sorted_fishes, sorted_special_fishes)
710
- return (
711
- ["🎒你的背包里空无一物"]
712
- if sorted_fishes == {}
713
- else print_backpack(sorted_fishes)
714
- )
715
- return ["🎒你的背包里空无一物"]
716
-
717
-
718
- def print_backpack(backpack: dict, special_backpack=None) -> list[str]:
719
- result = [
720
- f"{fish_name}×{str(quantity)}" for fish_name, quantity in backpack.items()
721
- ]
722
- if special_backpack:
723
- special_result = [
724
- f"{fish_name}×{str(quantity)}"
725
- for fish_name, quantity in special_backpack.items()
726
- ]
727
- return [
728
- "🎒普通鱼:\n" + "\n".join(result),
729
- "🎒特殊鱼:\n" + "\n".join(special_result),
730
- ]
731
- return ["🎒普通鱼:\n" + "\n".join(result)]
732
-
733
-
734
- async def get_achievements(user_id: str) -> str:
735
- session = get_session()
736
- async with session.begin():
737
- select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
738
- record = await session.scalar(select_user)
739
- if record:
740
- achievements = json.loads(record.achievements)
741
- return "已完成成就:\n" + "\n".join(achievements)
742
- return "你甚至还没钓过鱼 (╬▔皿▔)╯"
743
-
744
-
745
- async def get_board() -> list[tuple]:
746
- session = get_session()
747
- async with session.begin():
748
- select_users = (
749
- select(FishingRecord).order_by(FishingRecord.coin.desc()).limit(10)
750
- )
751
- record = await session.scalars(select_users)
752
- if record:
753
- top_users_list = []
754
- for user in record:
755
- top_users_list.append((user.user_id, user.coin))
756
- top_users_list.sort(key=lambda user: user[1], reverse=True)
757
- return top_users_list
758
- return []
759
-
760
-
761
- def get_shop() -> list[MessageSegment]:
762
- messages: list[MessageSegment] = []
763
-
764
- messages.append(MessageSegment.text("===== 钓鱼用具店 ====="))
765
-
766
- for fish in config_fishes:
767
- if fish.can_buy:
768
- total_price = int(fish.buy_price * fish.amount)
769
- messages.append(
770
- MessageSegment.text(
771
- f"商品名:{fish.name} \n单份数量:{fish.amount}\n单价:{fish.buy_price} {fishing_coin_name}\n"
772
- f"单份总价:{total_price} {fishing_coin_name}\n描述:{fish.description}"
773
- )
774
- )
775
-
776
- return messages
1
+ import asyncio
2
+ import copy
3
+ import random
4
+ import time
5
+ import json
6
+
7
+ from collections.abc import Hashable
8
+ from sqlalchemy import select, update, delete
9
+ from sqlalchemy.sql.expression import func
10
+ from nonebot.adapters.onebot.v11 import MessageSegment
11
+ from nonebot_plugin_orm import get_session
12
+
13
+ from .config import config
14
+ from .model import FishingRecord, SpecialFishes
15
+ from .fish_helper import *
16
+
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
+
35
+ async def can_fishing(user_id: str) -> bool:
36
+ time_now = int(time.time())
37
+ session = get_session()
38
+ async with session.begin():
39
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
40
+ record = await session.scalar(select_user)
41
+ return True if not record else record.time < time_now
42
+
43
+
44
+ async def can_catch_special_fish(probability_add: int):
45
+ session = get_session()
46
+ async with session.begin():
47
+ records = await session.execute(select(SpecialFishes))
48
+ return (
49
+ len(records.all()) != 0
50
+ and random.random() <= config.special_fish_probability + probability_add
51
+ )
52
+
53
+
54
+ async def check_tools(
55
+ user_id: str, tools: list[str] = None, check_have: bool = True
56
+ ) -> str | None:
57
+ if not tools or tools == []:
58
+ return None
59
+
60
+ # 这是工具吗?
61
+ for tool in tools:
62
+ fish = get_fish_by_name(tool)
63
+ if not fish:
64
+ return f"你在用什么钓鱼……?{tool}?"
65
+
66
+ props = fish.props
67
+ if not props or props == []:
68
+ return f"搞啥嘞!{tool}既不是工具也不是鱼饵!"
69
+
70
+ # 如果有两个工具,是一个工具一个鱼饵吗?
71
+ if len(tools) == 2:
72
+ if get_fish_by_name(tools[0]).type == get_fish_by_name(tools[1]).type:
73
+ return "你为啥要用两个类型一样的东西?"
74
+
75
+ # 有吗?有吗?
76
+ if check_have:
77
+ session = get_session()
78
+ async with session.begin():
79
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
80
+ fishes_record = await session.scalar(select_user)
81
+ if fishes_record:
82
+ loads_fishes = json.loads(fishes_record.fishes)
83
+ for tool in tools:
84
+ if tool not in loads_fishes:
85
+ return f"你哪来的{tool}?"
86
+
87
+ return None
88
+
89
+
90
+ async def remove_tools(user_id: str, tools: list[str] = None) -> None:
91
+ if not tools or tools == []:
92
+ return None
93
+
94
+ session = get_session()
95
+ async with session.begin():
96
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
97
+ fishes_record = await session.scalar(select_user)
98
+ if fishes_record:
99
+ loads_fishes = json.loads(fishes_record.fishes)
100
+ for tool_name in tools:
101
+ loads_fishes[tool_name] -= 1
102
+ if loads_fishes[tool_name] == 0:
103
+ del loads_fishes[tool_name]
104
+ dump_fishes = json.dumps(loads_fishes)
105
+ user_update = (
106
+ update(FishingRecord)
107
+ .where(FishingRecord.user_id == user_id)
108
+ .values(fishes=dump_fishes)
109
+ )
110
+ await session.execute(user_update)
111
+ await session.commit()
112
+ else:
113
+ pass
114
+ # raise ValueError("?你的 Check 是怎么通过的?")
115
+
116
+
117
+ def get_adjusts_from_tools(tools: list = None) -> list:
118
+ no_add = 0
119
+ sp_add = 0
120
+ adjusts: list[Property] = []
121
+
122
+ if tools:
123
+ for tool in tools:
124
+ adjusts += get_fish_by_name(tool).props
125
+
126
+ for adjust in adjusts:
127
+ if adjust.type == "special_fish":
128
+ sp_add += adjust.value
129
+ if adjust.type == "no_fish":
130
+ no_add += adjust.value
131
+
132
+ return adjusts, no_add, sp_add
133
+
134
+
135
+ def adjusted(adjusts: list[Property] = None) -> tuple:
136
+ adjusted_fishes = copy.deepcopy(can_catch_fishes)
137
+
138
+ for adjust in adjusts:
139
+ if adjust.key and adjust.key not in adjusted_fishes:
140
+ continue
141
+ match adjust.type:
142
+ case "normal_fish":
143
+ for key, weight in can_catch_fishes.items():
144
+ if weight >= config.rare_fish_weight and key in adjusted_fishes:
145
+ adjusted_fishes[key] += adjust.value
146
+ case "rare_fish":
147
+ for key, weight in can_catch_fishes.items():
148
+ if weight < config.rare_fish_weight and key in adjusted_fishes:
149
+ adjusted_fishes[key] += adjust.value
150
+ case "fish":
151
+ adjusted_fishes[adjust.key] += adjust.value
152
+ case "rm_fish":
153
+ adjusted_fishes.pop(adjust.key)
154
+ case "special_fish" | "no_fish":
155
+ pass
156
+ case _:
157
+ pass
158
+
159
+ adjusted_fishes_list = list(adjusted_fishes.keys())
160
+ adjusted_weights = list(adjusted_fishes.values())
161
+
162
+ for i in range(len(adjusted_weights)):
163
+ if adjusted_weights[i] < 0:
164
+ adjusted_weights[i] = 0
165
+
166
+ return adjusted_fishes_list, adjusted_weights
167
+
168
+
169
+ def choice(adjusts: list[Property] = None) -> str:
170
+ adjusted_fishes_list, adjusted_weights = adjusted(adjusts)
171
+ choices = random.choices(
172
+ adjusted_fishes_list,
173
+ weights=adjusted_weights,
174
+ )
175
+ return choices[0]
176
+
177
+
178
+ async def get_fish(user_id: int, tools: list = None) -> str:
179
+ adjusts, no_add, sp_add = get_adjusts_from_tools(tools)
180
+
181
+ if random.random() < config.no_fish_probability + no_add:
182
+ await asyncio.sleep(random.randint(10, 20))
183
+ return "QAQ你空军了,什么都没钓到"
184
+
185
+ if await can_catch_special_fish(sp_add):
186
+ special_fish_name = await random_get_a_special_fish()
187
+ await asyncio.sleep(random.randint(10, 20))
188
+ await save_special_fish(user_id, special_fish_name)
189
+ result = f"你钓到了别人放生的 {special_fish_name}"
190
+ return result
191
+
192
+ fish = choice(adjusts)
193
+ sleep_time = get_fish_by_name(fish).sleep_time
194
+ result = f"钓到了一条{fish}, 你把它收进了背包里"
195
+ await asyncio.sleep(sleep_time)
196
+ await save_fish(user_id, fish)
197
+ return result
198
+
199
+
200
+ def predict(tools: list = None) -> str:
201
+ no = config.no_fish_probability
202
+ sp = config.special_fish_probability
203
+ sp_price = config.special_fish_price
204
+ result = ""
205
+
206
+ adjusts, no_add, sp_add = get_adjusts_from_tools(tools)
207
+ sp_t = min(max(sp + sp_add, 0), 1)
208
+ no_t = min(max(no + no_add, 0), 1)
209
+
210
+ # 拉取矫正权重
211
+ adjusted_fishes_list, adjusted_weights = adjusted(adjusts)
212
+
213
+ adjusted_fishes_value = []
214
+ for fish_name in adjusted_fishes_list:
215
+ fish = get_fish_by_name(fish_name)
216
+ adjusted_fishes_value.append(int(fish.price * fish.amount))
217
+
218
+ # 归一化
219
+ total_weight = sum(adjusted_weights)
220
+ probabilities = [w / total_weight for w in adjusted_weights]
221
+ expected_value = sum(v * p for v, p in zip(adjusted_fishes_value, probabilities))
222
+
223
+ result += f"鱼列表:[{', '.join(adjusted_fishes_list)}]\n"
224
+ result += f"概率列表: [{', '.join([str(round(w * 100, 2)) + "%" for w in probabilities])}]\n"
225
+ result += f"特殊鱼概率:{round(sp_t * (1 - no_t), 6)}\n"
226
+ result += f"空军概率:{round(no_t, 6)}\n"
227
+
228
+ # 无特殊鱼
229
+ expected_value = expected_value * (1 - no_t)
230
+ result += f"无特殊鱼时期望为:{expected_value:.3f}\n"
231
+
232
+ # 有特殊鱼
233
+ expected_value = expected_value * (1 - sp_t) + sp_price * sp_t * (1 - no_t)
234
+ result += f"有特殊鱼期望为:{expected_value:.3f}"
235
+
236
+ return result
237
+
238
+
239
+ async def random_get_a_special_fish() -> str:
240
+ session = get_session()
241
+ async with session.begin():
242
+ random_select = select(SpecialFishes).order_by(func.random())
243
+ data = await session.scalar(random_select)
244
+ return data.fish
245
+
246
+
247
+ async def check_achievement(user_id: str) -> str | None:
248
+ session = get_session()
249
+ async with session.begin():
250
+ record = await session.scalar(
251
+ select(FishingRecord).where(FishingRecord.user_id == user_id)
252
+ )
253
+ if not record:
254
+ return None
255
+ fishing_frequency = record.frequency
256
+ user_fishes = json.loads(record.fishes)
257
+ achievements = config_achievements
258
+ result_list = []
259
+ for achievement in achievements:
260
+ achievement_name = achievement.name
261
+ if await is_exists_achievement(user_id, achievement_name):
262
+ continue
263
+ if (
264
+ achievement.type == "fishing_frequency"
265
+ and achievement.data <= fishing_frequency
266
+ ) or (achievement.type == "fish_type" and achievement.data in user_fishes):
267
+ await save_achievement(user_id, achievement_name)
268
+ result_list.append(
269
+ f"""达成成就: {achievement_name}\n{achievement.description}"""
270
+ )
271
+ return result_list if result_list != [] else None
272
+
273
+
274
+ async def is_exists_achievement(user_id: str, achievement_name: str) -> bool:
275
+ session = get_session()
276
+ async with session.begin():
277
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
278
+ record = await session.scalar(select_user)
279
+ if record:
280
+ loads_achievements = json.loads(record.achievements)
281
+ return achievement_name in loads_achievements
282
+ return False
283
+
284
+
285
+ async def save_achievement(user_id: str, achievement_name: str):
286
+ time_now = int(time.time())
287
+ session = get_session()
288
+ async with session.begin():
289
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
290
+ record = await session.scalar(select_user)
291
+ if record:
292
+ loads_achievements = json.loads(record.achievements)
293
+ loads_achievements.append(achievement_name)
294
+ dump_achievements = json.dumps(loads_achievements)
295
+ user_update = (
296
+ update(FishingRecord)
297
+ .where(FishingRecord.user_id == user_id)
298
+ .values(achievements=dump_achievements)
299
+ )
300
+ await session.execute(user_update)
301
+ await session.commit()
302
+ return
303
+ data = []
304
+ dump_achievements = json.dumps(data)
305
+ new_record = FishingRecord(
306
+ user_id=user_id,
307
+ time=time_now,
308
+ frequency=0,
309
+ fishes="{}",
310
+ special_fishes="{}",
311
+ coin=0,
312
+ achievements=dump_achievements,
313
+ )
314
+ session.add(new_record)
315
+ await session.commit()
316
+
317
+
318
+ async def save_fish(user_id: str, fish_name: str) -> None:
319
+ time_now = int(time.time())
320
+ fishing_cooldown = random.randint(
321
+ config.fishing_cooldown_time_min, config.fishing_cooldown_time_max
322
+ )
323
+ amount = get_fish_by_name(fish_name).amount
324
+ session = get_session()
325
+ async with session.begin():
326
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
327
+ record = await session.scalar(select_user)
328
+ if record:
329
+ loads_fishes = json.loads(record.fishes)
330
+ try:
331
+ loads_fishes[fish_name] += amount
332
+ except KeyError:
333
+ loads_fishes[fish_name] = amount
334
+ dump_fishes = json.dumps(loads_fishes)
335
+ new_frequency = record.frequency + 1
336
+ user_update = (
337
+ update(FishingRecord)
338
+ .where(FishingRecord.user_id == user_id)
339
+ .values(
340
+ time=time_now + fishing_cooldown,
341
+ frequency=new_frequency,
342
+ fishes=dump_fishes,
343
+ )
344
+ )
345
+ await session.execute(user_update)
346
+ await session.commit()
347
+ return
348
+ data = {fish_name: amount}
349
+ dump_fishes = json.dumps(data)
350
+ new_record = FishingRecord(
351
+ user_id=user_id,
352
+ time=time_now + fishing_cooldown,
353
+ frequency=1,
354
+ fishes=dump_fishes,
355
+ special_fishes="{}",
356
+ coin=0,
357
+ achievements="[]",
358
+ )
359
+ session.add(new_record)
360
+ await session.commit()
361
+
362
+
363
+ async def save_special_fish(user_id: str, fish_name: str) -> None:
364
+ time_now = int(time.time())
365
+ fishing_cooldown = random.randint(
366
+ config.fishing_cooldown_time_min, config.fishing_cooldown_time_max
367
+ )
368
+ session = get_session()
369
+ async with session.begin():
370
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
371
+ record = await session.scalar(select_user)
372
+ if record:
373
+ loads_fishes = json.loads(record.special_fishes)
374
+ try:
375
+ loads_fishes[fish_name] += 1
376
+ except KeyError:
377
+ loads_fishes[fish_name] = 1
378
+ dump_fishes = json.dumps(loads_fishes)
379
+ user_update = (
380
+ update(FishingRecord)
381
+ .where(FishingRecord.user_id == user_id)
382
+ .values(
383
+ time=time_now + fishing_cooldown,
384
+ frequency=record.frequency + 1,
385
+ special_fishes=dump_fishes,
386
+ )
387
+ )
388
+ await session.execute(user_update)
389
+ else:
390
+ data = {fish_name: 1}
391
+ dump_fishes = json.dumps(data)
392
+ new_record = FishingRecord(
393
+ user_id=user_id,
394
+ time=time_now + fishing_cooldown,
395
+ frequency=1,
396
+ fishes="{}",
397
+ special_fishes=dump_fishes,
398
+ coin=0,
399
+ achievements=[],
400
+ )
401
+ session.add(new_record)
402
+ select_fish = (
403
+ select(SpecialFishes)
404
+ .where(SpecialFishes.fish == fish_name)
405
+ .order_by(SpecialFishes.id)
406
+ .limit(1)
407
+ )
408
+ record = await session.scalar(select_fish)
409
+ fish_id = record.id
410
+ delete_fishes = delete(SpecialFishes).where(SpecialFishes.id == fish_id)
411
+ await session.execute(delete_fishes)
412
+ await session.commit()
413
+
414
+
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:
422
+ if quantity <= 0:
423
+ return "你在卖什么 w(゚Д゚)w"
424
+
425
+ session = get_session()
426
+ async with session.begin():
427
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
428
+ fishes_record = await session.scalar(select_user)
429
+ if fishes_record := fishes_record:
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
+
435
+ spec_fishes = json.loads(fishes_record.special_fishes)
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
+ ):
453
+ if fish_name not in can_sell_fishes:
454
+ return f"这个 {fish_name} 不可以卖哦~"
455
+ if loads_fishes[fish_name] < quantity:
456
+ return f"你没有那么多 {fish_name}"
457
+ fish_price = get_fish_by_name(fish_name).price
458
+ loads_fishes[fish_name] -= quantity
459
+ if loads_fishes[fish_name] == 0:
460
+ del loads_fishes[fish_name]
461
+ dump_fishes = json.dumps(loads_fishes)
462
+ user_update = (
463
+ update(FishingRecord)
464
+ .where(FishingRecord.user_id == user_id)
465
+ .values(
466
+ coin=fishes_record.coin + fish_price * quantity,
467
+ fishes=dump_fishes,
468
+ )
469
+ )
470
+ await session.execute(user_update)
471
+ await session.commit()
472
+
473
+ return (
474
+ f"你以 {fish_price} {fishing_coin_name} / 条的价格卖出了 {quantity} 条 {fish_name}, "
475
+ f"你获得了 {fish_price * quantity} {fishing_coin_name}"
476
+ )
477
+ elif fish_name in spec_fishes and spec_fishes[fish_name] > 0:
478
+ fish_price = config.special_fish_price
479
+ if spec_fishes[fish_name] < quantity:
480
+ return f"你没有那么多 {fish_name}"
481
+ spec_fishes[fish_name] -= quantity
482
+ if spec_fishes[fish_name] == 0:
483
+ del spec_fishes[fish_name]
484
+ dump_fishes = json.dumps(spec_fishes)
485
+ user_update = (
486
+ update(FishingRecord)
487
+ .where(FishingRecord.user_id == user_id)
488
+ .values(
489
+ coin=fishes_record.coin + fish_price * quantity,
490
+ special_fishes=dump_fishes,
491
+ )
492
+ )
493
+ await session.execute(user_update)
494
+ await session.commit()
495
+ return (
496
+ f"你以 {fish_price} {fishing_coin_name} / 条的价格卖出了 {quantity} 条 {fish_name}, "
497
+ f"获得了 {fish_price * quantity} {fishing_coin_name}"
498
+ )
499
+ else:
500
+ return "查无此鱼"
501
+ else:
502
+ return "还没钓鱼就想卖鱼?"
503
+
504
+
505
+ async def buy_fish(user_id: str, fish_name: str, quantity: int = 1) -> str:
506
+ if quantity <= 0:
507
+ return "别在渔具店老板面前炫耀自己的鱼 (..-˘ ˘-.#)"
508
+ if fish_name not in can_buy_fishes:
509
+ return "商店不卖这个!"
510
+
511
+ fish = get_fish_by_name(fish_name)
512
+ total_price = int(fish.buy_price * fish.amount * quantity)
513
+
514
+ session = get_session()
515
+ async with session.begin():
516
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
517
+ fishes_record = await session.scalar(select_user)
518
+ if fishes_record := fishes_record:
519
+ loads_fishes = json.loads(fishes_record.fishes)
520
+ user_coin = fishes_record.coin
521
+ if user_coin < total_price:
522
+ coin_less = str(total_price - fishes_record.coin)
523
+ return f"你没有足够的 {fishing_coin_name}, 还需 {coin_less} {fishing_coin_name}"
524
+ user_coin -= total_price
525
+ try:
526
+ loads_fishes[fish_name] += fish.amount * quantity
527
+ except KeyError:
528
+ loads_fishes[fish_name] = fish.amount * quantity
529
+ dump_fishes = json.dumps(loads_fishes)
530
+ user_update = (
531
+ update(FishingRecord)
532
+ .where(FishingRecord.user_id == user_id)
533
+ .values(coin=user_coin, fishes=dump_fishes)
534
+ )
535
+ await session.execute(user_update)
536
+ await session.commit()
537
+ return f"你用 {total_price} {fishing_coin_name} 买入了 {quantity} 份 {fish_name}"
538
+ else:
539
+ return "不想钓鱼的人就别在渔具店逛了~"
540
+
541
+
542
+ async def free_fish(user_id: str, fish_name: str) -> str:
543
+ session = get_session()
544
+ async with session.begin():
545
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
546
+ fishes_record = await session.scalar(select_user)
547
+ if fishes_record:
548
+ user_coin = fishes_record.coin
549
+ spec_fishes = json.loads(fishes_record.special_fishes)
550
+ if fish_name in spec_fishes and spec_fishes[fish_name] > 0:
551
+ spec_fishes[fish_name] -= 1
552
+ if spec_fishes[fish_name] == 0:
553
+ del spec_fishes[fish_name]
554
+ new_record = SpecialFishes(user_id=user_id, fish=fish_name)
555
+ session.add(new_record)
556
+ dump_fishes = json.dumps(spec_fishes)
557
+ user_update = (
558
+ update(FishingRecord)
559
+ .where(FishingRecord.user_id == user_id)
560
+ .values(special_fishes=dump_fishes)
561
+ )
562
+ await session.execute(user_update)
563
+ await session.commit()
564
+ return f"你再次放生了 {fish_name}, 未来或许会被有缘人钓到呢"
565
+ else:
566
+ if fish_name in fish_list:
567
+ return "普通鱼不能放生哦~"
568
+
569
+ if user_coin < config.special_fish_free_price:
570
+ special_fish_coin_less = str(
571
+ config.special_fish_free_price - fishes_record.coin
572
+ )
573
+ return f"你没有足够的 {fishing_coin_name}, 还需 {special_fish_coin_less} {fishing_coin_name}"
574
+ user_coin -= config.special_fish_free_price
575
+ new_record = SpecialFishes(user_id=user_id, fish=fish_name)
576
+ session.add(new_record)
577
+ user_update = (
578
+ update(FishingRecord)
579
+ .where(FishingRecord.user_id == user_id)
580
+ .values(coin=user_coin)
581
+ )
582
+ await session.execute(user_update)
583
+ await session.commit()
584
+ return f"你花费 {config.special_fish_free_price} {fishing_coin_name} 放生了 {fish_name}, 未来或许会被有缘人钓到呢"
585
+ return "你甚至还没钓过鱼"
586
+
587
+
588
+ async def lottery(user_id: str) -> str:
589
+ """算法来自于 https://github.com/fossifer/minesweeperbot/blob/master/cards.py"""
590
+ session = get_session()
591
+ time_now = int(time.time())
592
+ fishing_cooldown = random.randint(
593
+ config.fishing_cooldown_time_min, config.fishing_cooldown_time_max
594
+ )
595
+ async with session.begin():
596
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
597
+ fishes_record = await session.scalar(select_user)
598
+ if fishes_record:
599
+ user_coin = fishes_record.coin
600
+ if user_coin < 0:
601
+ new_coin = random.randrange(1, 50)
602
+ user_update = (
603
+ update(FishingRecord)
604
+ .where(FishingRecord.user_id == user_id)
605
+ .values(
606
+ time=time_now + fishing_cooldown,
607
+ coin=0 + new_coin,
608
+ )
609
+ )
610
+ await session.execute(user_update)
611
+ await session.commit()
612
+ return f"你是不是被哪个坏心眼的神惩罚了……河神帮你还完了欠款"
613
+ if user_coin <= 30:
614
+ new_coin = random.randrange(1, 50)
615
+ user_update = (
616
+ update(FishingRecord)
617
+ .where(FishingRecord.user_id == user_id)
618
+ .values(
619
+ time=time_now + fishing_cooldown,
620
+ coin=fishes_record.coin + new_coin,
621
+ )
622
+ )
623
+ await session.execute(user_update)
624
+ await session.commit()
625
+ return f"你穷得连河神都看不下去了,给了你 {new_coin} {fishing_coin_name} w(゚Д゚)w"
626
+ new_coin = abs(user_coin) / 3
627
+ new_coin = random.randrange(5000, 15000) / 10000 * new_coin
628
+ new_coin = int(new_coin) if new_coin > 1 else 1
629
+ new_coin *= random.randrange(-1, 2, 2)
630
+ user_update = (
631
+ update(FishingRecord)
632
+ .where(FishingRecord.user_id == user_id)
633
+ .values(
634
+ time=time_now + fishing_cooldown,
635
+ coin=fishes_record.coin + new_coin,
636
+ )
637
+ )
638
+ await session.execute(user_update)
639
+ await session.commit()
640
+ return f'你{"获得" if new_coin >= 0 else "血亏"}了 {abs(new_coin)} {fishing_coin_name}'
641
+ else:
642
+ return "河神没有回应你……"
643
+
644
+
645
+ async def give(
646
+ user_id: str,
647
+ name_or_index: str,
648
+ quantity: int = 1,
649
+ as_index: bool = False,
650
+ as_special: bool = False,
651
+ ) -> str:
652
+ session = get_session()
653
+ async with session.begin():
654
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
655
+ record = await session.scalar(select_user)
656
+ if record:
657
+
658
+ if name_or_index == "coin" or name_or_index == fishing_coin_name:
659
+ user_update = (
660
+ update(FishingRecord)
661
+ .where(FishingRecord.user_id == user_id)
662
+ .values(
663
+ coin=record.coin + quantity,
664
+ )
665
+ )
666
+ await session.execute(user_update)
667
+ await session.commit()
668
+ return f"使用滥权之力成功为 {user_id} {"增加" if quantity >= 0 else "减少"} {abs(quantity)} {fishing_coin_name} ヾ(≧▽≦*)o"
669
+
670
+ loads_fishes = json.loads(record.fishes)
671
+ spec_fishes = json.loads(record.special_fishes)
672
+
673
+ if as_index:
674
+ if not name_or_index.isdigit():
675
+ return "你完全不看帮助是吗  ̄へ ̄"
676
+ load_dict = loads_fishes if not as_special else spec_fishes
677
+ fish_name = get_key_by_index(load_dict, int(name_or_index))
678
+ if not fish_name:
679
+ return "查无此鱼,你再看看这人背包呢?"
680
+ else:
681
+ fish_name = name_or_index
682
+
683
+ if not as_special and fish_name in fish_list:
684
+ try:
685
+ loads_fishes[fish_name] += quantity
686
+ except KeyError:
687
+ loads_fishes[fish_name] = quantity
688
+ if loads_fishes[fish_name] <= 0:
689
+ del loads_fishes[fish_name]
690
+ dump_fishes = json.dumps(loads_fishes)
691
+ user_update = (
692
+ update(FishingRecord)
693
+ .where(FishingRecord.user_id == user_id)
694
+ .values(fishes=dump_fishes)
695
+ )
696
+ await session.execute(user_update)
697
+ await session.commit()
698
+ else:
699
+ try:
700
+ spec_fishes[fish_name] += quantity
701
+ except KeyError:
702
+ spec_fishes[fish_name] = quantity
703
+ if spec_fishes[fish_name] <= 0:
704
+ del spec_fishes[fish_name]
705
+ dump_fishes = json.dumps(spec_fishes)
706
+ user_update = (
707
+ update(FishingRecord)
708
+ .where(FishingRecord.user_id == user_id)
709
+ .values(special_fishes=dump_fishes)
710
+ )
711
+ await session.execute(user_update)
712
+ await session.commit()
713
+
714
+ fish_name = (
715
+ fish_name[:20] + "..." + str(len(fish_name) - 20)
716
+ if len(fish_name) > 20
717
+ else fish_name
718
+ )
719
+ return f"使用滥权之力成功为 {user_id} {"增加" if quantity >= 0 else "减少"} {abs(quantity)} 条 {fish_name} ヾ(≧▽≦*)o"
720
+ return "未查找到用户信息, 无法执行滥权操作 w(゚Д゚)w"
721
+
722
+
723
+ async def get_all_special_fish() -> dict[str, int]:
724
+ session = get_session()
725
+ async with session.begin():
726
+ random_select = select(SpecialFishes.fish).order_by(SpecialFishes.fish.asc())
727
+ data = await session.scalars(random_select)
728
+ pool = data.all()
729
+
730
+ result = dict()
731
+ for fish in pool:
732
+ try:
733
+ result[fish] += 1
734
+ except KeyError:
735
+ result[fish] = 1
736
+
737
+ return result
738
+
739
+
740
+ async def remove_special_fish(name_or_index: str, as_index: bool = False) -> str | None:
741
+ pool = await get_all_special_fish()
742
+
743
+ if as_index:
744
+ if not name_or_index.isdigit():
745
+ return "你完全不看帮助是吗  ̄へ ̄"
746
+ fish_name = get_key_by_index(pool, int(name_or_index))
747
+ if not fish_name:
748
+ return "查无此鱼"
749
+ else:
750
+ fish_name = name_or_index
751
+ if fish_name not in pool:
752
+ return "查无此鱼"
753
+
754
+ session = get_session()
755
+ async with session.begin():
756
+ delete_fishes = delete(SpecialFishes).where(SpecialFishes.fish == fish_name)
757
+ await session.execute(delete_fishes)
758
+ await session.commit()
759
+
760
+ fish_name = (
761
+ fish_name[:20] + "..." + str(len(fish_name) - 20)
762
+ if len(fish_name) > 20
763
+ else fish_name
764
+ )
765
+
766
+ return f"已成功捞出 {fish_name}"
767
+
768
+
769
+ async def get_pool(name_limit: int = 30, page_limit: int = 200) -> list[MessageSegment]:
770
+ messages: list[MessageSegment] = []
771
+ pool = await get_all_special_fish()
772
+ messages.append(
773
+ MessageSegment.text(f"现在鱼池里面有 {sum(list(pool.values()))} 条鱼。")
774
+ )
775
+
776
+ msg = "鱼池列表:\n"
777
+ i = 0
778
+ j = 1
779
+ for fish, num in pool.items():
780
+ if len(msg) > page_limit:
781
+ fish = (
782
+ fish[:name_limit] + "..." + str(len(fish) - name_limit)
783
+ if len(fish) > name_limit
784
+ else fish
785
+ )
786
+ msg += f"{i}. {fish} x {num}\n"
787
+ msg += f"【第 {j} 页结束】"
788
+ messages.append(MessageSegment.text(msg))
789
+ msg = ""
790
+ i += 1
791
+ j += 1
792
+ else:
793
+ fish = (
794
+ fish[:name_limit] + "..." + str(len(fish) - name_limit)
795
+ if len(fish) > name_limit
796
+ else fish
797
+ )
798
+ msg += f"{i}. {fish} x {num}\n"
799
+ i += 1
800
+ else:
801
+ messages.append(MessageSegment.text(msg))
802
+
803
+ return messages
804
+
805
+
806
+ async def get_stats(user_id: str) -> str:
807
+ session = get_session()
808
+ async with session.begin():
809
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
810
+ fishing_record = await session.scalar(select_user)
811
+ if fishing_record:
812
+ return f"🐟你钓上了 {fishing_record.frequency} 条鱼"
813
+ return "🐟你还没有钓过鱼,快去钓鱼吧"
814
+
815
+
816
+ async def get_balance(user_id: str) -> str:
817
+ session = get_session()
818
+ async with session.begin():
819
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
820
+ fishes_record = await session.scalar(select_user)
821
+ if fishes_record:
822
+ return f"🪙你有 {fishes_record.coin} {fishing_coin_name}"
823
+ return "🪙你什么也没有 :)"
824
+
825
+
826
+ async def get_backpack(user_id: str, limit: int | None = None) -> list[str]:
827
+ session = get_session()
828
+ async with session.begin():
829
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
830
+ fishes_record = await session.scalar(select_user)
831
+ if fishes_record:
832
+ loads_fishes = json.loads(fishes_record.fishes)
833
+ loads_fishes = {
834
+ key: loads_fishes[key] for key in fish_list if key in loads_fishes
835
+ }
836
+ spec_fishes: dict = json.loads(fishes_record.special_fishes)
837
+ if spec_fishes:
838
+ spec_fishes = dict(sorted(spec_fishes.items()))
839
+ if limit:
840
+ return print_backpack(loads_fishes, spec_fishes, limit)
841
+ else:
842
+ return print_backpack(loads_fishes, spec_fishes)
843
+ return (
844
+ ["🎒你的背包里空无一物"]
845
+ if loads_fishes == {}
846
+ else print_backpack(loads_fishes)
847
+ )
848
+ return ["🎒你的背包里空无一物"]
849
+
850
+
851
+ def print_backpack(
852
+ backpack: dict, special_backpack: dict = None, limit: int | None = None
853
+ ) -> list[str]:
854
+ i = 0
855
+ result = []
856
+ for fish_name, quantity in backpack.items():
857
+ result.append(f"{i}. {fish_name}×{str(quantity)}")
858
+ i += 1
859
+
860
+ if special_backpack:
861
+ i = 0
862
+ special_result: list[str] = []
863
+ for fish_name, quantity in special_backpack.items():
864
+ if limit:
865
+ special_result.append(
866
+ f"{i}. {fish_name[:limit] + '...' + str(len(fish_name) - limit) if len(fish_name) > limit else fish_name}×{str(quantity)}"
867
+ )
868
+ else:
869
+ special_result.append(f"{i}. {fish_name}×{str(quantity)}")
870
+ i += 1
871
+ return [
872
+ "🎒普通鱼:\n" + "\n".join(result),
873
+ "🎒特殊鱼:\n" + "\n".join(special_result),
874
+ ]
875
+ return ["🎒普通鱼:\n" + "\n".join(result)]
876
+
877
+
878
+ async def get_achievements(user_id: str) -> str:
879
+ session = get_session()
880
+ async with session.begin():
881
+ select_user = select(FishingRecord).where(FishingRecord.user_id == user_id)
882
+ record = await session.scalar(select_user)
883
+ if record:
884
+ achievements = json.loads(record.achievements)
885
+ return "已完成成就:\n" + "\n".join(achievements)
886
+ return "你甚至还没钓过鱼 (╬▔皿▔)╯"
887
+
888
+
889
+ async def get_board() -> list[tuple]:
890
+ session = get_session()
891
+ async with session.begin():
892
+ select_users = (
893
+ select(FishingRecord).order_by(FishingRecord.coin.desc()).limit(10)
894
+ )
895
+ record = await session.scalars(select_users)
896
+ if record:
897
+ top_users_list = []
898
+ for user in record:
899
+ top_users_list.append((user.user_id, user.coin))
900
+ top_users_list.sort(key=lambda user: user[1], reverse=True)
901
+ return top_users_list
902
+ return []
903
+
904
+
905
+ def get_shop() -> list[MessageSegment]:
906
+ messages: list[MessageSegment] = []
907
+
908
+ messages.append(MessageSegment.text("===== 钓鱼用具店 ====="))
909
+
910
+ for fish in config_fishes:
911
+ if fish.can_buy:
912
+ total_price = int(fish.buy_price * fish.amount)
913
+ messages.append(
914
+ MessageSegment.text(
915
+ f"商品名:{fish.name} \n单份数量:{fish.amount}\n单价:{fish.buy_price} {fishing_coin_name}\n"
916
+ f"单份总价:{total_price} {fishing_coin_name}\n描述:{fish.description}"
917
+ )
918
+ )
919
+
920
+ return messages