nonebot-plugin-fishing2 0.1.1__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.
- nonebot_plugin_fishing2/__init__.py +601 -591
- nonebot_plugin_fishing2/config.py +301 -301
- nonebot_plugin_fishing2/data_source.py +920 -895
- nonebot_plugin_fishing2/fish_helper.py +157 -157
- nonebot_plugin_fishing2/migrations/7609e6d106dd_init_db.py +43 -43
- nonebot_plugin_fishing2/migrations/c5ab992c9af3_add_achievements.py +38 -38
- nonebot_plugin_fishing2/model.py +20 -20
- {nonebot_plugin_fishing2-0.1.1.dist-info → nonebot_plugin_fishing2-1.0.1.dist-info}/METADATA +8 -8
- nonebot_plugin_fishing2-1.0.1.dist-info/RECORD +14 -0
- {nonebot_plugin_fishing2-0.1.1.dist-info → nonebot_plugin_fishing2-1.0.1.dist-info}/WHEEL +1 -1
- {nonebot_plugin_fishing2-0.1.1.dist-info → nonebot_plugin_fishing2-1.0.1.dist-info/licenses}/LICENSE +21 -21
- nonebot_plugin_fishing2-0.1.1.dist-info/RECORD +0 -14
|
@@ -1,895 +1,920 @@
|
|
|
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
|
|
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=
|
|
608
|
-
)
|
|
609
|
-
)
|
|
610
|
-
await session.execute(user_update)
|
|
611
|
-
await session.commit()
|
|
612
|
-
return f"
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
)
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
)
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
)
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
if
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
fish_name
|
|
751
|
-
if
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
)
|
|
894
|
-
|
|
895
|
-
|
|
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
|