763 Commits

Author SHA1 Message Date
acd5408552 🍱 更新xx用什么的数据集 2023-04-15 01:43:10 +08:00
31b6bc7de4 🍱 更新收集的宝箱数据 2023-04-14 11:58:26 +08:00
4db59f2b1d 🍱 更新新圣遗物数据 2023-04-13 14:21:48 +08:00
99496abd40 添加查询琦良良换xx圣遗物的支持 2023-04-13 01:09:17 +08:00
d372757f72 🍱 更新原神3.6版本的metadata 2023-04-12 01:01:56 +08:00
689efe6595 🍱 更新血量表等杂图资源 2023-04-09 00:56:57 +08:00
7ec5618d56 🍱 更新原石预估素材 2023-04-02 00:28:07 +08:00
b4817ef539 🍱 新增新角色的参考面板,优化体验 2023-04-01 00:49:27 +08:00
739a14237c 增加获取抽卡记录链接功能 (#449) 2023-03-26 13:18:41 +08:00
c7f7130db3 🍱 更新参考面板版本深渊内容 2023-03-25 13:24:52 +08:00
15671c5204 🐛 修复材料 (#470) 2023-03-21 17:13:38 +08:00
a9644b6af2 🍱 更新原石预估 2023-03-14 00:23:24 +08:00
ca793d9b50 新增导出v3数据 2023-03-09 23:15:46 +08:00
b2564f3303 新增gsrc (#463) 2023-03-08 22:27:56 +08:00
bf530c7c49 🐛 修复查询白术的数据异常 2023-03-02 22:24:25 +08:00
d3214bd468 🍱 补充部分原神3.6的数据资料 2023-03-02 21:49:46 +08:00
04e05d708a ️ 支持查询白术查询卡维,修复几个BUG,优化体验 2023-03-02 21:17:33 +08:00
986dc750de 🎨 删除通用获取成功log (#461) 2023-03-02 02:32:42 +08:00
e0f6e68fb8 🐛 修补MetaData, 调整BUG(#461) 2023-03-02 00:04:08 +08:00
94aaa52fd6 🍱 更新原神3.5版本MetaData 2023-03-01 01:12:37 +08:00
f684f0e833 add Python 3.11 tests 2023-02-23 11:52:00 +08:00
772d54ef99 ⬆️ update nonebug 2023-02-23 11:38:01 +08:00
b6c855c1ae 🎨 更新切换api的API地址 2023-02-15 21:06:38 +08:00
558f280996 🐛 修复下载全部资源的问题 2023-02-14 23:24:16 +08:00
d75a023d10 下载全部资源将会检查版本差异 2023-02-14 22:28:47 +08:00
cd2eb1d217 🐛 修复部分情况下,扫码登陆无法获取正确UID 2023-02-11 15:34:11 +08:00
1a69c787b2 🎨 扫码登陆功能改为群聊触发以降低封号概率 (#443)
* 将扫码登陆功能改为群聊降低封号概率,并且增加uid绑定检验。

* 将扫码登陆功能改为群聊降低封号概率,并且增加uid绑定检验。

* 将扫码登陆功能改为群聊降低封号概率,并且增加uid绑定检验。

* 🚨 auto fix by pre-commit-ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-02-09 21:55:31 +08:00
e77b8b74b4 新增强制刷新抽卡记录 2023-02-09 01:55:55 +08:00
5da43afd78 📝 合并雷神和薙刀效果 2023-02-08 00:26:19 +08:00
fa3319a48d 🚑️ 修复删除配置项错误的问题 2023-02-07 00:08:16 +08:00
4f349cd253 🎨 移除失效配置、新增随机图配置 2023-02-06 23:47:27 +08:00
955ff47542 🐛 修复查询雷神的数值错误 2023-02-06 23:40:16 +08:00
ae38504e7e 修复test_adv 2023-02-05 21:55:45 +08:00
03e31d6416 🔧 修复pre-commit 2023-02-05 21:07:55 +08:00
4f0a3202ea 📝 更新查询收集的最大值 2023-02-05 21:02:40 +08:00
32e15df3cd 👽️ 更换随机图接口地址 (#441) 2023-02-05 20:25:07 +08:00
3a202afd19 📝 更新攻略、gs帮助、修复伤害参考bug 2023-02-04 19:11:21 +08:00
28227236da 🎨 微调强制刷新界面` 2023-02-03 00:29:40 +08:00
ed68e42385 🎨 修改强制刷新界面 2023-02-02 00:27:40 +08:00
b850f099d1 👽 更新ENKA_API 2023-01-29 22:52:15 +08:00
768619e0c1 ⬆️ update poetry-core(#433) 2023-01-28 08:05:35 +08:00
137c83471e 🍱 更新3.4血量表抗性表 2023-01-27 23:44:25 +08:00
20319c02ac 🐛 修复注册时间 2023-01-26 20:28:11 +08:00
79d90deae0 🚨 移除重复导入 2023-01-26 19:35:35 +08:00
9fee49e090 新增原神注册时间命令 (#431) 2023-01-26 19:11:19 +08:00
cc145d9a5c 🐛 修复查询心海的伤害计算和毕业度错误 2023-01-25 20:58:00 +08:00
1fbecaee53 🎨扫码登陆套聊天记录 (#430)
* 更改了一下刷新抽卡失败的提示

* 为扫码登陆套聊天记录,加入免责声明

* 🚨 auto fix by pre-commit-ci

* Update qrlogin.py

* 🚨 auto fix by pre-commit-ci

* 🎨 移动通用函数至`message`

* 🚨 auto fix by pre-commit-ci

* 🚨 修复一些警告

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: KimigaiiWuyi <444835641@qq.com>
2023-01-25 16:33:21 +08:00
f7ff22ad4c 新增chbg文件夹以供查询角色的自定义图 2023-01-24 00:02:59 +08:00
416cc371fc 新增查成就查委托 2023-01-23 15:54:46 +08:00
e73cd9e6eb 🍱 更新一部分成就资源 2023-01-23 15:21:08 +08:00
ec622d1388 🍱 更新艾尔海森瑶瑶的参考面板 2023-01-22 23:03:27 +08:00
bdfc63a6c7 🍱 增加查询米卡的治疗量计算,修复旅行者BUG 2023-01-20 19:11:57 +08:00
0c7d737ab7 🐛 修复新角色基础数值错误的问题 2023-01-20 00:10:08 +08:00
e0ae84ac89 🍱 更新3.5版本角色的别名和有效词条 2023-01-19 23:37:12 +08:00
b9519acf89 🍱 支持部分3.5版本的角色和武器的替换 2023-01-19 23:19:37 +08:00
6f22752b07 🐛 修复签到 (#428) 2023-01-18 21:54:52 +08:00
e13b3e5a52 🍱 更新原神3.4版本MetaData 2023-01-18 02:02:51 +08:00
8b3771a3a0 🐛 修复原神每日签到奖励物品名称获取错误的问题 (#428)
* 修复原神每日签到奖励物品名称获取错误的问题

* 🚨 auto fix by pre-commit-ci

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-01-17 22:22:24 +08:00
4ec467e154 📝 修改ck帮助的说明 (#421) 2023-01-17 00:21:52 +08:00
5b6384764a 🎨 补充_pass内容 2023-01-17 00:15:16 +08:00
7838611f14 新增刷新全部CK(需SU用户) 2023-01-16 23:31:52 +08:00
24257cdf90 🐛 修复xx在哪的一部分使用体验 (#427) 2023-01-15 17:42:48 +08:00
7692e9799a 新增刷新CK(需要用户绑定SK) 2023-01-15 00:48:22 +08:00
bdff2b31c1 🎨 增加几个安柏计划API 2023-01-14 23:59:14 +08:00
052d3c1c73 🐛 修正暴击率低于0%时期望伤害低于普通值的问题 (#422)
* 修正暴击率低于0%时期望伤害低于普通值的问题

* 🚨 auto fix by pre-commit-ci

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-01-10 22:53:21 +08:00
e5824e407e 🍱 更新原始预估3.4 2023-01-10 22:50:40 +08:00
5540fab06a 🎨 修改convert_img方法 2023-01-08 00:53:55 +08:00
6240d020eb 🐛 修复错误的sp_base 2023-01-06 23:17:56 +08:00
59c93fd6ef 🍱 同步查询艾尔海森的倍率,新增查询夜兰的蒸发伤害 2023-01-05 23:49:31 +08:00
668ad813c8 🐛 修复特殊情况下几种默认反应倍率 2023-01-03 23:59:02 +08:00
5eb4675628 🐛 修复原神公告的部分详情出现https错误 2023-01-02 23:49:24 +08:00
261437f466 🐛 修复清除原神公告红点 2023-01-01 01:31:17 +08:00
b24708f913 📝 更新gs帮助 2022-12-30 00:30:11 +08:00
3ff5b4f2fa 🐛 修复查询绫人等几个角色的伤害异常(#413) 2022-12-29 23:36:56 +08:00
698d310684 🎨 improve config
genshinuid_disabled_plugins: 禁用的插件(meta 无效)
genshinuid_priority: GenshinUID 的优先级

e.g.
```env
genshinuid_disabled_plugins=["enka", "help", "map"]
genshinuid_priority=5
```
2022-12-29 22:02:05 +08:00
18ed57b93a 🐛 修复导入子插件不完整的问题 2022-12-28 23:54:31 +08:00
ea486f7ff5 🐛 修复SQLModel导包问题 2022-12-28 23:49:15 +08:00
cd4ecb462c 🎨 separation of test dependencies into a new group
only test: poetry install --with test --without dev
2022-12-28 22:55:55 +08:00
3c3785cd48 🚨 fix lint warnings 2022-12-28 22:38:37 +08:00
37a6d2f7a8 新增原神公告 (#409) 2022-12-28 21:38:31 +08:00
29c46a93d6 🚑 fix bbs coin error 2022-12-28 10:22:08 +08:00
5ba1ba09e6 新增扫码登陆 2022-12-27 23:57:57 +08:00
21c7049fdd use pypi source default 2022-12-27 23:03:14 +08:00
76469c56a7 fix tests 2022-12-27 22:22:27 +08:00
b30bd4fa9c 🎨 update metadatas 2022-12-27 22:07:19 +08:00
eb6e822b6f 新增版本深渊,后可跟版本号 2022-12-22 00:16:22 +08:00
80f8a12789 增加hhw_api的相关方法 2022-12-21 23:01:43 +08:00
278cbcaa63 🎨 调整添加CK时候的判定顺序,修复几个BUG 2022-12-20 00:42:56 +08:00
ac98c9f896 新增数据文件夹内bg文件夹,用于存放自定义图片 2022-12-19 00:04:30 +08:00
c02d1f2f07 新增查询探索, 重绘的查询收集 2022-12-18 19:51:00 +08:00
0f1a0b02c2 🎨 添加draw_bar绘图方法,重绘收集样式 2022-12-18 19:48:18 +08:00
f4d1d47554 🐛 修复已知BUG、修改参考数值和角色BUFF错误 2022-12-17 19:17:17 +08:00
fb4c6b569c 🐛 修复已知BUG,优化报错提示(#405) 2022-12-16 23:19:53 +08:00
5e52c9abd4 🎨 为多条推送信息添加换行符 (#403) 2022-12-14 12:12:37 +08:00
c413e7d65c 🐛 修正国际服七圣召唤api (#402) 2022-12-14 12:00:45 +08:00
9e6cd2a2a8 🐛 下载全部资源时判断是否为空文件名 2022-12-14 09:45:03 +08:00
38910e9a2b 🐛 查询时额外输出问题 2022-12-14 00:07:15 +08:00
933e97ff97 攻略换用本地攻略源 2022-12-13 23:23:04 +08:00
09aa9af93a 🎨 更新深渊概览API,添加自动下载攻略 2022-12-13 23:15:37 +08:00
f1ff90c423 🍱 补充3.3新角色的参考面板毕业度 2022-12-12 22:52:40 +08:00
897399b77e 📝 限制绑定uid位数, 补充gs帮助 2022-12-11 17:16:48 +08:00
0099d16072 🎨 一些响应方式的修改 2022-12-11 15:25:18 +08:00
519aef0ca1 🎨 修改资源文件名 (#400)
* 修改资源文件名

统一命名,去除卡牌资源文件结尾的符号

* 🚨 auto fix by pre-commit-ci

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2022-12-11 14:07:54 +08:00
a6f66c5231 🎨 update dependencies 2022-12-11 14:01:01 +08:00
63488e7bbf 新增七圣召唤命令,后可跟UID 2022-12-11 13:54:13 +08:00
c7ceb7a14c 🎨 添加七圣召唤的API,修复一部分BUG 2022-12-11 13:50:06 +08:00
49612280fa 🍱 补充一些遗漏资源,修复几个BUG 2022-12-09 23:15:04 +08:00
e18e69aeed 🍱 补充一部分3.4的资源文件 2022-12-09 20:25:52 +08:00
1b402defbc 新增原牌功能, 例如原牌狼末 2022-12-08 23:29:54 +08:00
245446e329 🍱 增加一些资源文件 2022-12-08 23:20:55 +08:00
0832d9d79e 📝 提高原神版本至3.3 2022-12-07 01:08:32 +08:00
376f537701 🍱 新增原神3.3版本的元数据 2022-12-07 01:05:54 +08:00
a5933222c5 🐛 修复低星圣遗物的错误 2022-12-05 23:39:38 +08:00
455e9207ff 🐛 修复抽卡记录平均UP错误和提纳里的毕业度 2022-12-04 17:03:39 +08:00
fee7e8a936 🎨 优化一部分API访问 2022-12-04 13:55:06 +08:00
ba2b4aa86f 🐛 修复截获CK字段的错误 2022-12-03 00:04:32 +08:00
76f18d9c7c 🍱 补充版本规划3.3 2022-12-02 22:51:23 +08:00
95dbe36cf9 🐛 修复深渊概览刷新失败 2022-12-02 22:45:24 +08:00
d0d56f1a6d 🐛 修复未绑定UID时签到指令异常返回 2022-11-30 23:53:00 +08:00
b3a64c8aec 🐛 修复查询妮露的不正确毕业度(#397) 2022-11-29 22:01:36 +08:00
9d34e463ec 🎨 强制刷新支持使用@别人查询(#396) 2022-11-29 21:14:53 +08:00
0cb727784b 🎨 优化毕业度的计算值 2022-11-29 21:09:23 +08:00
1b743e9096 🎨 重做的毕业度计算 2022-11-29 01:48:01 +08:00
1ec87752a4 🚑️ 补充错误获取的CK 2022-11-26 23:31:42 +08:00
94050454e6 新增深渊统计(深渊概览) 2022-11-26 15:12:15 +08:00
2886cbfebf 🐛 修复缓存获取CK的BUG 2022-11-26 15:06:46 +08:00
fddc85c91e 🐛 修复仅修改命座的报错 2022-11-24 11:57:02 +08:00
63f5d0686b 🐛 修复查询六命散兵换xx无法生效的问题 2022-11-24 00:34:03 +08:00
21a6a3eafc 支持查询公子换香菱沙类似用法,并可以任意组合 2022-11-24 00:23:24 +08:00
a7eb2a33cb 💥 修改PROXY配置至config.json 2022-11-23 22:02:33 +08:00
aaf7431c92 🐛 兼容国际服的ID至UID的转换, 尝试从绑定UID读取 2022-11-12 17:00:29 +08:00
49a77f7fb9 👽️ 判断v2版本的米游社CK(#383) 2022-11-12 16:18:02 +08:00
ef923c5ba9 🐛 修复 Actions 错误 (#371)
* 🐛 修复 Actions 错误
 - PR 仓库无法执行 pre-commit
 - metadata 单元测试出错

* 🐛 修复 etc 单元测试出错

* 🐛 修复 pre-commit Actions 在 PR 中 checkout 错误

* 🚧 添加 pre-commit Actions 权限

* 🚧 调整 `pull_request_target` 触发类型

* 🚧 区分 pre-commit 提交步骤

* 🐛 remove `pull_request` trigger

* 🚨 auto fix by pre-commit-ci

* 🔥 delete pre-commit workflow

Co-authored-by: MingxuanGame <MingxuanGame@outlook.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2022-11-12 00:33:54 +08:00
68c42305e5 🎨 改进一部分错误提示 2022-11-12 00:28:55 +08:00
7fb4a4d572 👽️ 增加mr出现验证码的错误提示(#379) 2022-11-11 23:42:44 +08:00
ecdb232beb 🎨 修改部分角色BUFF,修改部分UI表现 2022-11-11 22:51:06 +08:00
8cd9570e2d 支持查询beta角色(数据从安柏计划获取) 2022-11-10 01:39:37 +08:00
e42ef039d1 📝 增加WeChat适配器的相关描述 2022-11-09 00:32:22 +08:00
28dce2f15c 为校验全部Cookies功能添加国际服支持(#377) 2022-11-08 21:36:21 +08:00
5ee22c89bf 🍱 增加一部分提示, 更新血量表等资源(#364) 2022-11-07 00:08:43 +08:00
9ddba001be 🐛 修复纳西妲业障除的伤害计算错误 2022-11-06 20:33:41 +08:00
58cabae6ee 🚑强制刷新检查绑定的UID 2022-11-06 19:13:12 +08:00
b59b406027 久岐忍,刻晴等角色添加更多的反应, 修复一些效果错误 2022-11-06 18:42:44 +08:00
e6d4d452a5 🍱 更新纳西妲的参考面板 2022-11-06 15:41:17 +08:00
8d82fba7af 🎨 添加判断刻晴是不是up (#376) 2022-11-06 14:45:25 +08:00
0a81e2b9fa 🐛 修复抽卡记录兜底值 2022-11-06 01:05:45 +08:00
98e0174348 重做的抽卡记录 2022-11-06 00:47:11 +08:00
9596199a3a 🐛 修复导入抽卡数据的ID错误 2022-11-05 01:49:57 +08:00
b9406eb634 🐛 修复低星圣遗物面板刷新的问题(#360) 2022-11-05 01:17:03 +08:00
30f164b2a1 添加几个角色的反应伤害, 修复*海量BUG 2022-11-04 23:35:01 +08:00
66224ece5b 🐛 修复防御力不正确加成, 优化使用体验 2022-11-03 05:11:50 +00:00
db9860531b 🐛 圣遗物四件套情况少计算两件套效果 2022-11-03 00:45:33 +08:00
d8d2ede988 支持查询六命莱依拉带精五月光换公子圣遗物类似用法 2022-11-03 00:00:00 +08:00
044701e730 🐛 修复一些效果和标记问题 2022-11-02 22:12:14 +08:00
2d1f766d7c 🐛 修正国际服ds生成规则 (#370) 2022-11-02 20:52:42 +08:00
b01117c224 🔧 兼容 Poetry (#368) 2022-11-02 16:04:22 +08:00
8ca7237075 🚑 向下兼容Python版本 2022-11-02 15:40:50 +08:00
41f047a96f 🐛 临时对随机获取cookie过程进行服务器隔离防止互相污染 (#367) 2022-11-02 13:25:45 +08:00
ad3859ed71 🍱 更新原神3.2版本伤害数据 2022-11-02 13:13:14 +08:00
e62f9ba574 🍱 新增原神3.2版本的元数据 2022-11-02 08:47:41 +08:00
93bcf9fbbc 🎨 统一角色面板处理文件 2022-11-01 22:50:56 +08:00
3ac2267cee 🐛 修复更新记录的绘图越界 2022-11-01 21:50:37 +08:00
c46f14e59f 为部分功能添加国际服支持 (#366)
Signed-off-by: Chino Kafuu <twfx1207@gmail.com>
2022-11-01 21:12:53 +08:00
99be740d11 ♻️ 重构部分伤害计算相关代码 2022-11-01 21:10:39 +08:00
21ddfa3cd6 补全对PicMenu的支持 (#361) 2022-10-31 15:10:10 +08:00
00bdc5fccb 🍱 更新参考面板妮露, 修复已知Bug 2022-10-24 21:16:20 +08:00
918632ad71 🐛 向下兼容网页控制台 2022-10-23 22:18:26 +08:00
b4f8371e5d 网页控制台为无管理员权限用户新增添加CK功能(#347) 2022-10-23 21:32:08 +08:00
59cc1e35c4 🐛 修复替换武器时因未正确判断类型导致伤害错误 2022-10-22 00:47:25 +08:00
798069565a 🎨 更新角色别名配置 (#359)
* 🎨 更新角色别名配置

* 🐛 修复角色别名识别

不再考虑输入为别名中字符串子串的情况
2022-10-22 00:13:43 +08:00
0b3dddb870 新增更新记录 2022-10-22 00:06:23 +08:00
58a0df17b8 新增gs清除缓存(如查询相关异常可尝试) 2022-10-21 00:40:34 +08:00
bdd4f26fe3 调整数据库缓存清除逻辑 2022-10-21 00:34:16 +08:00
c3ae3ed0db 查询妮露增加丰穰之核伤害计算(默认算上双水双草Buff) 2022-10-20 23:48:41 +08:00
ecd7a57ef3 🐛 查询甘雨伤害大招加成计算有误 2022-10-20 01:20:40 +08:00
c231cb4267 gs开启随机图的面板回复开启原图功能 2022-10-18 22:33:23 +08:00
26eb980e5b 🚚 为资源文件夹添加TEMP目录 2022-10-18 22:31:42 +08:00
ffb2558fec 🐛 修复一个面板抗性引发的问题; 更新伤害乘区 2022-10-18 21:00:47 +08:00
a9f26bb102 📝 补充gs帮助文件 2022-10-18 00:55:20 +08:00
2c1ad1466b 🎨 利用fastapi_genshin_map重写地图逻辑 2022-10-18 00:33:12 +08:00
25ffbfc4bc 🐛 修复一个导致CK死循环的错误(#354) 2022-10-17 22:49:38 +08:00
34eb5093d9 🐛 修复查询满命妮露的问题 2022-10-16 13:46:58 +08:00
9ac01864c5 重做的活动列表和新增卡池列表 2022-10-14 22:26:12 +08:00
db3ba78639 🎨 更高容纳度的get_qq_avatar方法 2022-10-14 01:28:13 +08:00
7617c29b6d 🔧 重命名依赖项 2022-10-14 01:10:42 +08:00
62d8ee5cd3 🐛 活动列表现在可以使用 2022-10-13 22:42:45 +08:00
bec03e8acc 重做的毕业度统计 2022-10-12 23:56:08 +08:00
396015763b 🎨 新增复用绘图方法, 更换默认背景图 2022-10-12 23:51:15 +08:00
4a1c402c38 ️ 增加gs帮助的内容 2022-10-10 23:53:06 +08:00
5fc6df94f6 现在查询展柜角色以图片返回 2022-10-10 23:29:17 +08:00
c39ddf30c2 🎨 优化绘图方法, 从中间裁切, 更新部分默认背景 2022-10-10 23:27:04 +08:00
124de5aff3 🐛 修复旅行者ID问题 2022-10-10 09:58:37 +08:00
3e61f3411a 🐛 修复强制刷新旅行者无法显示 2022-10-10 08:45:13 +08:00
1488e3eebb 🍱 更新3.1角色的参考面板 2022-10-10 00:41:21 +08:00
f32e40d362 现在强制刷新以图片返回结果 2022-10-10 00:25:54 +08:00
60af532185 🎨 新增一些绘图方法, 简化代码 2022-10-10 00:16:14 +08:00
ff317b8f7c 🐛 修复在高版本的依赖下插件报错 2022-10-07 22:28:33 +08:00
a703593836 新增清除无效用户(#206) 2022-10-07 21:28:45 +08:00
5f801276f5 🚑️ 缺漏符号 2022-10-07 13:39:13 +08:00
a2a6228b66 🎨 修改网页控制台主页 2022-10-07 13:35:11 +08:00
712380c24b 🎨 拉大签到间隔时长 2022-10-06 23:38:31 +08:00
27db2e14c4 新增gs开启跳过无感验证 2022-10-06 23:15:02 +08:00
3005b435d2 🐛 网页控制台的HTML修改 2022-10-06 19:29:05 +08:00
46a6e846e6 新增查询公子成长曲线类似用法 2022-10-05 18:24:19 +08:00
954e1dd965 新增各种缺失的曲线数据,修复大量面板Bug 2022-10-05 18:21:33 +08:00
f40730e510 improve downloading files 2022-10-05 15:46:30 +08:00
a60baf7975 add tests for etcimg and guide 2022-10-04 22:03:42 +08:00
7b9aec2761 🐛 fix creating map 2022-10-04 20:01:27 +08:00
a40a0ea74d 🙈 update .gitignore 2022-10-04 17:46:26 +08:00
711fe2ad1c 🎨 why not use Chinese? 2022-10-04 17:43:25 +08:00
391bf0aa0b 新增gs开启多彩面板 2022-10-04 00:09:50 +08:00
56a609226b support changing primary key 2022-10-03 23:02:27 +08:00
bc17763617 🐛 fix changing config error 2022-10-03 19:33:46 +08:00
a5a418f51c 🚀 support deploying by docker
docker build -t genshinuid:v3.1.0 .

nonebot 在 /nb2/nb2,GenshinUID 在 /plugin,需要的可自行挂载(用 docker volume)

默认不带有 go-cqhttp 及 nonebot-plugin-gocqhttp 插件,暴露端口 8080,需要自己连接 go-cqhttp

build 前修改 deploy 文件夹下的 .env.dev 修改镜像的 nonebot2 配置,或者可以运行后挂载 nb2 目录修改
2022-10-03 18:17:18 +08:00
aeec83f982 🐛 fix tests 2022-10-02 23:49:07 +08:00
85171c0172 ✏️ rename branch 2022-10-02 23:45:42 +08:00
1c363b7ff3 init tests 2022-10-02 23:43:40 +08:00
19dd446219 🎨 限制触发条件 2022-10-02 22:52:13 +08:00
6c778f1fcb 新增血量排行 2022-10-02 22:42:49 +08:00
7dad667064 🎨 更新收集数据,血量表,抗性表 2022-10-02 22:37:57 +08:00
c0532c06dd 🐛 面板查询的几个遗留问题 2022-10-02 22:15:14 +08:00
245121b318 🐛 remove logger for settings 2022-10-02 21:57:22 +08:00
501e8398b0 🐛 fix pydantic checking error 2022-10-02 21:40:46 +08:00
bac4d7061c mount WebConsole to nonebot ASGI server
path: /genshinuid
2022-10-02 18:47:27 +08:00
2cddf1c481 🎨 修改收集的数据和生成地图相关问题 2022-10-02 16:28:01 +08:00
973c64a2dc ⬆️ update genshinmap from MingxuanGame/GenshinMap 2022-10-02 14:11:50 +08:00
d4fd84da9b 🎨 更新gs帮助以及补漏其他功能 2022-10-02 01:53:28 +08:00
fd1f366db3 🐛 原石札记中分母为0的情况(#346) 2022-10-02 01:17:46 +08:00
86cc55cf78 🍱 角色成长曲线数据 2022-10-02 01:13:46 +08:00
70bc3b5143 新增御神签(#344) 2022-10-02 00:09:58 +08:00
6838ce7d5a 新增抽表情(#344) 2022-10-01 21:56:12 +08:00
75269479be 🐛 原石札记的一些UI问题 2022-10-01 20:41:20 +08:00
5d426aa4b4 新增当前信息(#337) 2022-10-01 19:49:01 +08:00
34af5a7c27 增加draw_note_img方法(#337) 2022-10-01 19:05:18 +08:00
dbd60d4ac4 🎨 原石预估现在将会输出当前原神版本的对应图片 2022-09-29 21:56:52 +08:00
ad4af70e21 新增赛诺E渡荒之雷伤害计算及超激化, 修复大量bug 2022-09-29 21:49:02 +08:00
06fa1a71fa 🎨 计算基础天赋时,如果没有则跳过 2022-09-29 08:40:59 +08:00
8cffc3f070 🐛 每日空值忽略世界等级(#342) 2022-09-28 22:32:58 +08:00
670cf730e7 🐛 每日如果收到空值则忽略签名处理(#342) 2022-09-28 21:15:26 +08:00
76a350a834 🐛 一部分武器的效果异常 2022-09-28 10:45:34 +08:00
830a246d96 🍱 新增原神3.1版本的角色和武器数据 2022-09-28 10:13:10 +08:00
5f7dfb93fc 🎨 修改mask.png的所在位置 2022-09-26 22:57:23 +08:00
113613bc94 🍱 新增原神3.1版本的元数据 2022-09-26 22:36:43 +08:00
bb6a2666ff 🐛 伤害值增加的错误计算 2022-09-26 21:35:45 +08:00
0e90dd9613 🐛 修复磐岩结绿攻击力转化效果 (#340) 2022-09-26 09:57:40 +08:00
2a5144b1d6 🎨 忽略空值 (#336) 2022-09-25 17:28:20 +08:00
1591cc6052 🐛 修复查询旅行者的问题 2022-09-24 22:49:58 +08:00
d8ec80bcd2 支持查询六命公子换精五飞雷类似用法 2022-09-24 18:59:31 +08:00
a50f26ecdc 支持查询雷神换精三弓藏类似用法 2022-09-22 23:44:22 +08:00
e59d42e168 🐛 现在可以更换低星武器 2022-09-22 23:29:08 +08:00
0941cd1196 🐛 修复抽卡记录中可能获取到空字典的情况 2022-09-22 23:17:36 +08:00
3e22dae35f 🐛 修复查询公子换月华时生命不正确以及部分角色天赋问题 2022-09-22 23:02:37 +08:00
ca40fad6d3 支持查询公子换冬极类似用法 2022-09-22 01:40:57 +08:00
11bee5a2fc 🎨 改进一些奇怪的问题 2022-09-22 01:39:19 +08:00
9cd5fbd0dc 🐛 解决远程链接用户无法发送本地图片 2022-09-22 01:12:21 +08:00
5443ef8ae2 使用计算替代读取面板, 也可使用gs开启旧面板返回 2022-09-22 01:08:16 +08:00
6e90802e30 🐛 修复琴位于探索中每日失效的问题 2022-09-21 01:58:41 +08:00
79f9aa9237 新增原石统计3.1 2022-09-20 21:33:15 +08:00
81da9e5735 🎨 gs重启将会杀死windows进程 2022-09-19 21:18:00 +08:00
fe439f7fb8 📝 Update requirements.txt 2022-09-19 21:16:56 +08:00
2608259a14 🐛 更新gs帮助 2022-09-18 18:32:58 +08:00
ca49ee0682 📝 更新gs帮助 2022-09-18 18:28:47 +08:00
c0ab255b32 📝 优化gs更新提示 2022-09-18 16:56:11 +08:00
99146c70ac 🐛 使用driver替换@get_driver() 2022-09-18 01:53:13 +08:00
8b7a1f5da7 🎨 优化的gs重启 2022-09-18 01:51:13 +08:00
d1312c5ecc gs重启 2022-09-17 21:32:20 +08:00
f2e3687f17 🎨 优化gs更新返回提醒 2022-09-17 11:18:50 +08:00
fbc76e5f8c 📝 导入新子插件包 2022-09-17 01:37:11 +08:00
4511f6c6c2 gs更新,gs强制更新,gs强行强制更新 2022-09-17 01:23:08 +08:00
7d98e374ee 🎨 分离添加时发送的消息类型 2022-09-17 00:17:33 +08:00
c917459e79 🐛 修复五郎位于探索中每日失效的问题(#334) 2022-09-17 00:14:16 +08:00
63710928f4 🔧 增加GitPython,fastapi_user_auth,fastapi_amis_admin依赖 2022-09-17 00:11:07 +08:00
5d21214a65 新增gs开启网页控制台 2022-09-16 23:58:18 +08:00
ab83a6689f 🎨 改进部分写法以避免type ignore (#332) 2022-09-14 23:04:31 +08:00
c8238e83cf 🐛 查询云堇时毕业度不正确显示 2022-09-12 16:04:40 +08:00
79bb8c2595 🍱 毕业度计算增加多莉,钟离E总护盾量 2022-09-12 15:02:18 +08:00
2ba6701304 🎨 修正新角色的有效词条 2022-09-12 12:10:21 +08:00
29a5a1a8b5 🐛 使用绝对路径导出抽卡记录 2022-09-12 00:45:35 +08:00
0faeef3544 抽卡记录中角色祈愿将新增up标识 2022-09-12 00:26:50 +08:00
efb31d55af 🐛 查询角色时因随机图API导致的错误 2022-09-11 23:11:12 +08:00
997e024681 🎨 调整并发任务超时时间 2022-09-11 20:50:24 +08:00
1445e0decb 📝 add requirements.txt 2022-09-11 19:11:19 +08:00
2a55819cd5 增加删除CK的数据库方法(#206) 2022-09-11 19:08:23 +08:00
cbf8d26005 使用sqlmodel替换base基类(#319) 2022-09-11 17:52:28 +08:00
4dc93cb7c2 🐛 修复消息段类型不匹配导致无法发送消息 (#329) 2022-09-11 17:50:29 +08:00
43e1202499 🐛 修复伤害计算因暴击率造成的数值错误(#328) 2022-09-11 14:49:46 +08:00
47fbf74e29 更换为下载速度更快的MINIGGICU 2022-09-11 14:35:55 +08:00
27b343a95e 🐛 auto move: delete utils 2022-09-10 18:00:01 +08:00
e8642ac7d8 add auto move files script 2022-09-10 17:49:01 +08:00
ffd27fe2db 🐛 gs帮助在部分情况下无法发送成功 2022-09-10 15:25:55 +08:00
b8395ab3fe 🐛 提高等待时间 2022-09-10 15:22:11 +08:00
e95f1ce4e3 🐛 并发下载漏剩余文件 2022-09-10 15:18:56 +08:00
cf67c7f1ea 并发下载资源包 2022-09-10 15:14:38 +08:00
5bd4890add 🚑 exist_ok=True 2022-09-10 15:02:03 +08:00
38471d4f11 🔀 merge nonebot2-beta1-git into nonebot2-beta1 (#325)
 支持使用 pip/nb-cli 安装
2022-09-10 14:49:16 +08:00
d3e1b24fdb 🔊 change warning to info 2022-09-10 00:25:48 +08:00
3cefc786ff 🔥 remove poetry.lock 2022-09-10 00:21:31 +08:00
d2f9c95e95 🐛 init dir 2022-09-10 00:20:37 +08:00
bdfd5714d2 🐛 遗漏的路径 2022-09-09 23:46:13 +08:00
244e4ae414 🚚 移动资源路径 2022-09-09 23:32:33 +08:00
0f225418be 🚚 change the player data path 2022-09-09 22:58:29 +08:00
82f7b05a69 🎨 change the warning colors 2022-09-09 22:30:11 +08:00
78daf6a934 support installing by pip 2022-09-09 20:58:48 +08:00
843166211b 📝 更新README.md 2022-09-09 11:34:42 +08:00
9fffc3be60 🐛 修复新匹配算法带来的问题 2022-09-09 00:27:48 +08:00
0643b7d888 添加CK和SK时转为图片回复(#320) 2022-09-09 00:13:17 +08:00
0dff2bf76a 🎨 增加添加CK的返回图片 2022-09-09 00:11:25 +08:00
ee88d072a1 🎨 降低精通带来的毕业度提升 2022-09-08 23:16:43 +08:00
89181be54a 🎨 增加gs帮助内容 2022-09-08 21:48:57 +08:00
bc522c2259 🐛 修复计算毕业度时香菱的攻击加成 2022-09-08 13:01:45 +08:00
6f8c5b60e0 gs帮助现在可用 2022-09-08 02:31:29 +08:00
b5992535c8 draw_help_card.py 2022-09-08 02:29:57 +08:00
1354400e27 👽️ 修复Enka的返回值增加 2022-09-07 10:50:51 +08:00
a96cb5b92f 🐛 角色伤害加成获取有误 2022-09-07 10:23:05 +08:00
2682b0c807 💬 增加制作帮助图所需资源 2022-09-07 00:52:09 +08:00
7788067def 🐛 小鹿的英文简称错误 2022-09-06 19:55:09 +08:00
7ba36afa97 🐛 神里绫华Q+3不生效 2022-09-06 15:05:15 +08:00
3c6f46bf7b 🐛 伤害计算减防不生效 2022-09-06 15:04:37 +08:00
3c8a706d2d Merge branch 'nonebot2-beta1' of github.com:KimigaiiWuyi/GenshinUID into nonebot2-beta1 2022-09-06 10:36:53 +08:00
fe1dad35ab 🚑 fix unknown parameterless 2022-09-06 10:34:33 +08:00
7c6d123bff 📝 更新须弥宝箱数量(#318) 2022-09-06 09:35:17 +08:00
45e3781020 use rule to simplify code 2022-09-05 23:40:25 +08:00
40af1c28db 🎨 补充遗漏内容 2022-09-05 21:44:03 +08:00
f325cc136b 新增gs开启催命模式 2022-09-05 21:41:36 +08:00
31d3f6f783 🍱 更新血量表,抗性表, 增加雷神E协同攻击超激化 2022-09-04 14:08:40 +08:00
e8ca7f7853 新增任务<任务名>,任务<地区名> 2022-09-04 13:58:17 +08:00
ff4ee1929d 🔥 删除无用代码 2022-09-04 01:39:16 +08:00
1b8e05d02b 改进的毕业度计算 2022-09-04 01:22:04 +08:00
5dbea107ab 🎨 修复空UID仍然输出log(#316) 2022-09-03 17:45:45 +08:00
09b47a5f2d 🎨 增加几个角色的反应伤害;移除雷神A的超激化反应 2022-09-03 17:30:55 +08:00
03cc73696a 新增gs配置,gs开启定时签到,gs开启定时米游币 2022-09-03 11:07:08 +08:00
6cbb92423b draw_config_card.py 2022-09-03 11:03:19 +08:00
79dff3fe7c 🐛 值错误 2022-09-02 01:25:02 +08:00
0c4719dc07 🍻 修复之前bug造成的影响 2022-09-02 01:23:50 +08:00
f9e1c3f7dd 🐛 uigf_gacha_type映射关系 2022-09-02 01:18:32 +08:00
b67eed8089 Merge branch 'nonebot2-beta1' of github.com:KimigaiiWuyi/GenshinUID into nonebot2-beta1 2022-09-02 00:04:34 +08:00
f604d7a007 支持导出抽卡记录和导入抽卡记录 2022-09-02 00:04:00 +08:00
d222368ba8 Merge branch 'nonebot2-beta1' of github.com:KimigaiiWuyi/GenshinUID into nonebot2-beta1 2022-09-02 00:03:14 +08:00
2e361247c8 🐛 返回字段错误 2022-09-02 00:02:38 +08:00
46f389e5eb Merge branch 'nonebot2-beta1' of github.com:KimigaiiWuyi/GenshinUID into nonebot2-beta1 2022-09-02 00:01:54 +08:00
cbb7947dd0 👷 auto run pre-commit in pull requests 2022-09-02 00:01:09 +08:00
c52c2192e7 改进的导入导出方法 2022-09-01 23:41:02 +08:00
5402f034fe export and import.py 2022-09-01 00:22:28 +08:00
7d50cc134b 📝 新增xx用什么的须弥角色信息 2022-08-31 21:00:07 +08:00
71bcb82082 🐛 修复每月统计(#315) 2022-08-31 20:47:21 +08:00
7061832664 🐛 修复一些问题 2022-08-31 20:40:31 +08:00
bb119bfd6f 🐛 首次刷新抽卡记录可能失败 2022-08-31 02:44:56 +00:00
ee987c11ed 🐛 查询柯莱的蔓激化 2022-08-31 02:19:10 +00:00
d80706beaf 新增gs开启随机图 2022-08-31 01:39:52 +00:00
09f1f39d62 🐛 修复刷新抽卡记录 2022-08-30 23:55:34 +08:00
d95c1a0c2d 📝 增加更多的角色别名 2022-08-30 23:30:11 +08:00
10a0199fdb 🐛 尝试修复刷新抽卡记录的数据错误 2022-08-30 22:46:01 +08:00
edc86d456d 📝 修改收集命令数据为3.0版本 2022-08-30 22:25:17 +08:00
445d190d34 增加切换api 2022-08-30 22:22:50 +08:00
b84c00c6a1 🐛 现在可以使用草主推荐等旅行者攻略 2022-08-30 22:15:51 +08:00
de78a3b13c 新增刻晴, 提纳里, 柯莱, 北斗的草系反应 2022-08-30 22:14:06 +08:00
68baa744b2 🍱 增加新角色参考面板 2022-08-30 21:39:42 +08:00
0aaf186615 🐛 猎人之径的效果错误问题 2022-08-30 10:31:46 +08:00
22febab01c 添加插件帮助 (#311) 2022-08-30 09:00:02 +08:00
47929f764c 🐛 fix req.json() error 2022-08-30 08:40:27 +08:00
72ebb26b12 🐛 fix miHoYo BBS api error 2022-08-29 21:38:48 +08:00
8333d61eae use req.json() instead of json.loads 2022-08-29 19:31:38 +08:00
9efaf75c0a recover changes
This reverts commit 9bd0085982.
2022-08-29 14:55:36 +08:00
9bd0085982 🐛 httpx.ReadTimeout 2022-08-29 14:08:59 +08:00
21150c7514 🎨 refactor by sourcery 2022-08-29 01:21:58 +08:00
2a337ce8e9 🚨 fix codestyle warnings 2022-08-29 00:46:56 +08:00
51866deb99 🚨 fix F841 and E722 warnings 2022-08-29 00:07:17 +08:00
331198fa5a 🚨 fix import warning 2022-08-28 23:57:14 +08:00
017fbf6683 remove requests 2022-08-28 23:08:16 +08:00
6c68ba3657 🐛 fix import error 2022-08-28 22:30:42 +08:00
a05fdfb9b8 🚨 fix F405 warning(#308) 2022-08-28 21:51:30 +08:00
4a211dd32f 🐛 修复久岐忍大招的伤害显示问题, 增加草系反应 2022-08-28 18:31:26 +08:00
96628af1c8 🎨 适用于多种情形的convert_img 2022-08-28 17:26:13 +08:00
d53f920bb3 🎨 抽卡记录现在计算平均时会排除掉首个出金 2022-08-28 14:14:55 +08:00
4c84a729d0 🐛 直接添加Stoken无法添加成功的问题 2022-08-28 13:30:09 +08:00
3548477289 Merge branch 'nonebot2-beta1' of github.com:KimigaiiWuyi/GenshinUID into nonebot2-beta1 2022-08-28 13:04:26 +08:00
b836263039 🐛 修复一处提示文案错误 2022-08-28 00:28:01 +08:00
7ddf72ea17 🐛 修复刷新抽卡记录 2022-08-27 19:00:46 +08:00
e960a19060 增加部分草系反应的计算 2022-08-27 18:53:11 +08:00
44934543ea 🐛 修复地图黑色区域,重新生成地图即可 2022-08-27 02:42:26 +08:00
f9fc8539eb 🚨 meta中的错误格式 2022-08-26 22:54:12 +08:00
4002f8597a 🐛 解决合并冲突 2022-08-26 22:48:22 +08:00
fa490d744a 适配PicMenu插件(nonebot2版本需求上升至2.0.0b4 2022-08-26 22:41:45 +08:00
a6dfb9489c 新增刷新抽卡记录,抽卡记录 2022-08-26 22:33:59 +08:00
5f074c645c edit
edit

edit

edittttt
2022-08-26 22:33:50 +08:00
3b1e03a8ac 增加3.0新角色的伤害计算 2022-08-26 22:33:49 +08:00
10fb6c23f8 更换minigg.icu为资源自动下载站 2022-08-26 22:33:49 +08:00
6071903db4 edit 2022-08-26 01:13:46 +08:00
97eafe0c4f feat: 适配PicMenu插件(nonebot2版本需求上升至2.0.0b4 2022-08-25 02:36:39 +08:00
4f7ee1b8fc 🐛 尝试解决文件冲突问题 2022-08-24 23:33:31 +08:00
790c6c363a 🍱 增加部分3.0图片资源 2022-08-24 22:46:06 +08:00
a680fd40c0 🍱 新增部分3.0 map原始数据* 2022-08-24 01:06:18 +08:00
e7d6b90950 🎨 新增, 修复EnkaAPI 2022-08-22 05:15:30 +00:00
8dc4bf8b38 🚸 增加部分错误提示 2022-08-22 01:07:27 +08:00
372a03baaa 🐛 修复大部分武器常驻效果错误的问题 2022-08-21 20:36:22 +08:00
9a22c2f0a0 🐛 武器常驻被动不参与计算 2022-08-20 23:51:29 +08:00
e7f934342e 🐛 倍率和常量互相转换 2022-08-20 19:16:51 +08:00
b385d78655 🐛 修复伤害计算中可能的逻辑错误 2022-08-20 12:21:07 +08:00
d853a3bffe 🐛 查询神里绫华进行附魔 2022-08-19 22:42:44 +08:00
2331e54519 🐛 修复查询甘雨查询夜兰中特殊箭矢的重击计算 2022-08-19 22:31:01 +08:00
84111f11b9 🐛 修复添加CK字段中如果存在cookie_token会忽略login_ticket的bug 2022-08-19 21:15:51 +08:00
2120c5387c 🔨 update requirements.txt 2022-08-19 19:36:55 +08:00
0c1d0c8dd3 🐛 查询雷神梦想一刀伤害错误 2022-08-19 19:03:58 +08:00
ca81bbf131 Merge branch 'nonebot2-beta1' of github.com:KimigaiiWuyi/GenshinUID into nonebot2-beta1 2022-08-19 19:02:07 +08:00
418399abf2 🔨 add requirements.txt 2022-08-19 19:01:51 +08:00
1fca111eef 🐛 技能等级也应缩小一位 2022-08-19 13:19:26 +08:00
02627e9743 🐛 转换等级时应缩小一位 2022-08-19 09:18:15 +08:00
e0f19e144f 🐛 修复salt的问题导致的其他任务无法完成 2022-08-19 01:41:54 +08:00
2f88ca9f96 👽️ 修复因为米游社API变动导致的开始获取米游币失败 2022-08-19 01:35:14 +08:00
55296b8ca7 查询风系角色时,将会计算扩散伤害 2022-08-19 01:01:28 +08:00
a1ad2a2ab5 🐛 雷神满愿力的计算方式,角色偏移等 2022-08-18 20:37:30 +08:00
d7cd6b0955 查询胡桃等增加蒸发反应计算,查询雷神增加满愿力计算 2022-08-18 01:52:37 +08:00
5e706cc04d 新增血量表, 抗性表 2022-08-16 22:04:42 +08:00
18ae78863c 🐛 启动会下载多余的圣遗物图片 2022-08-16 22:00:51 +08:00
ab8cfe3290 优化 (#296)
* 优化资源下载

* 优化资源点查询
优化地图名称提示
优化查询语句匹配
2022-08-16 20:42:14 +08:00
91c4224b01 👽️ 再次增大重试间隔, 尝试修复全部重签 2022-08-16 01:00:32 +08:00
f60716f3fe 新增版本规划(版本规划2.8), 伤害乘区 2022-08-16 00:14:29 +08:00
8e4c3aa3e7 数据库会在凌晨0点进行备份,备份留存最近五天 2022-08-16 00:12:25 +08:00
0aa94deaae 查询面板现支持自定义图片;支持查询旅行者 2022-08-15 23:20:46 +08:00
2eafb87fe5 每日现在可以显示体力回满还需要多久 2022-08-15 21:56:18 +08:00
3205499096 🐛 genshinuid_map支持python3.8 2022-08-15 20:36:45 +08:00
9e13b43d8d 🐛 全部重签 2022-08-15 15:37:08 +08:00
efbfea22e1 👽 尝试通过重试修复签到全部重签 2022-08-15 13:32:21 +08:00
3f55b031b2 🐛 修复毕业度统计,修复查询魈伤害计算 2022-08-15 00:10:24 +08:00
df7245d9c7 🐛 ST to St 2022-08-14 23:02:55 +08:00
3191714394 🐛 genshinuid_enka伤害计算附魔问题 2022-08-14 22:51:08 +08:00
1bf87585cf Merge branch 'nonebot2-beta1' of github.com:KimigaiiWuyi/GenshinUID into nonebot2-beta1 2022-08-14 22:48:04 +08:00
e6be183259 🐛 修复mode引发的问题 2022-08-14 22:46:57 +08:00
ba1da7f328 🐛 兼容不使用米游币的数据库问题 2022-08-14 20:36:36 +08:00
32fd9c66e1 🐛 每日信息的存在性校验 2022-08-14 19:21:50 +08:00
e42fe4d745 🐛 handle_exc 2022-08-14 18:50:10 +08:00
88395108dc 🐛 List 2022-08-14 18:44:28 +08:00
6b01b98f1f 🐛 生成地图的链接错误 2022-08-14 18:42:34 +08:00
300f907985 🐛 生成地图的错误提示 2022-08-14 18:34:17 +08:00
9c196a7341 🐛 type hints 2022-08-14 18:22:57 +08:00
8dc2494bed 🐛 extend_existing 2022-08-14 16:55:23 +08:00
0da4c273e7 🐛 extend_existing 2022-08-14 16:37:10 +08:00
c371f64449 添加依赖sklearn和shapely 2022-08-14 16:08:38 +08:00
0f4f02c687 🎉 GenshinUID 3.0 beta 2022-08-14 14:34:32 +08:00
9bf5c26b22 Merge pull request #291 from lgc2333/patch-1
修复文本错误
2022-08-09 14:11:02 +08:00
641d4a5ad9 修复文本错误 2022-08-09 14:01:36 +08:00
816feb22e6 🐛 Enka UA 2022-08-08 12:08:50 +08:00
64c145c68d 👽️ 修复原神签到 2022-08-05 08:42:49 +08:00
a8b2ad5fbc ��️ 修复开始获取米游币 2022-08-05 00:40:34 +08:00
8a57b016cd 🐛 修复伤害计算 2022-07-20 21:08:57 +08:00
e76eff24fe 更新:查询收集的max_data 2022-07-20 16:59:46 +08:00
1105ff1ac7 Merge branch 'nonebot2-beta1' of github.com:KimigaiiWuyi/GenshinUID into nonebot2-beta1 2022-07-16 19:23:16 +08:00
cf6ea4bc6a 优化:伤害计算 2022-07-16 19:23:00 +08:00
a70061b158 修复:EnkaAPI 2022-07-16 14:11:44 +08:00
5fa9ef4b84 更新:用什么, 给谁用 2022-07-15 00:25:44 +08:00
bc02c23cee 修复:活动列表 2022-07-15 00:13:35 +08:00
beb9a566a3 修改:version 2022-07-14 22:24:56 +08:00
3480677c52 修复:鹿野院平藏资源问题 2022-07-14 08:54:54 +08:00
ea86619795 更新:2.8相关资源 2022-07-13 23:23:58 +08:00
e2d75b3752 修改:avatarCardOffsetMap.json 2022-07-11 10:37:48 +08:00
6269277b96 修复:毕业度统计 2022-07-11 10:35:23 +08:00
31941d31b2 优化:伤害计算区域对齐 2022-07-10 01:57:25 +08:00
55bfd25f64 新增:毕业度统计 2022-07-09 20:55:11 +08:00
6706fd1312 修改:UI贴图 2022-07-09 20:53:21 +08:00
35d0596f17 新增:查询展柜角色的伤害计算 2022-07-09 20:47:27 +08:00
5ab0693f7b 修复:命座影响天赋的map引入 2022-07-03 00:23:30 +08:00
4277a40450 修复:遗漏的图片 2022-07-03 00:09:17 +08:00
cfa3f91379 修复:班尼特的元素充能效率计算为有效词条 2022-07-02 23:16:18 +08:00
4b1ad04662 修改:查询角色面板的背景上色方式 2022-07-02 22:26:53 +08:00
c854194fcc 修复:因为地脉活动导致的活动列表错误问题 2022-07-02 17:12:40 +08:00
451e871d1b 新增:每日自动米游币任务结束后向SUPERUSER发送报告 2022-07-02 01:13:40 +08:00
4bc1533063 新增:校验全部Stoken 2022-07-02 00:51:08 +08:00
62649caa31 优化:命座显示天赋+3 2022-07-01 22:37:11 +08:00
0c9b291ee9 修复:特殊情况下查询深渊角色显示头像异常 2022-07-01 13:07:21 +08:00
29df398de6 新增:谁能用可以模糊查询圣遗物匹配信息 2022-06-30 23:47:28 +08:00
0694443bca 修复:推荐表内的换行问题 2022-06-30 23:43:57 +08:00
75b078810a 修复:能用啥的三星武器丢失问题 2022-06-30 23:18:31 +08:00
7aa07579db 修复:查询展柜角色中旅行者无法正常显示 2022-06-30 23:09:30 +08:00
a50a6167e2 优化:查询失败返回语句优化 2022-06-27 00:05:32 +08:00
382068070e 优化:全新的活动列表界面 2022-06-26 21:35:55 +08:00
782307e4bb chore(deps): Bump nonebot2 from 2.0.0b2 to 2.0.0b4 2022-06-25 20:16:58 +08:00
94f3c3a7cb 修复:天赋的tag问题 2022-06-25 11:45:54 +08:00
d441c25c51 优化:天赋的数字类型判断 2022-06-25 01:27:40 +08:00
675e8e4f65 更新:gs帮助 2022-06-25 01:00:32 +08:00
3a02a8f496 删除:无用的测试代码 2022-06-25 00:50:24 +08:00
387f618c59 修复:查询词云 2022-06-25 00:47:09 +08:00
0bacc8c674 修复:天赋中存在数字错乱的问题 2022-06-25 00:18:07 +08:00
ee74e054d8 修复:查询展柜角色 元素充能效率 -> 充能效率 2022-06-24 19:36:43 +08:00
83681c8e15 修复:久岐忍的探索派遣状态问题 2022-06-24 00:33:38 +08:00
27572a3af4 更新:gs帮助内容 2022-06-24 00:31:23 +08:00
2ad9b6242e 修复:烟绯的毕业度计算问题 2022-06-23 19:35:28 +08:00
01de70c1af 新增:完善dmgMap.json的制作方式 2022-06-22 21:54:58 +08:00
00c5280ec6 新增:久岐忍有效词条的计算 2022-06-22 01:11:58 +08:00
cca8c34bba 优化:圣遗物评分将变为有效词条计数 2022-06-22 01:00:23 +08:00
bf259f805d 修改:强制刷新返回字段,减少风控 2022-06-21 13:02:54 +08:00
ebdbec5fcd 修复:抗性区的计算问题 2022-06-21 12:53:49 +08:00
d96c7b0e06 修复:伤害计算错误 2022-06-19 21:05:02 +08:00
a6130424d5 优化:查询展柜角色优化整体UI 2022-06-19 15:50:51 +08:00
b8ce462636 修复:部分文案重叠 2022-06-19 14:48:45 +08:00
7c1508fd23 修复:完善全角色查询展柜角色毕业度的计算 2022-06-18 20:29:33 +08:00
5581b85332 查询展柜角色中完善角色立绘偏移 2022-06-17 00:28:47 +08:00
5dc5110ee3 '新增:引入avatarOffsetMap.json' 2022-06-14 00:24:17 +08:00
fe31910a09 修改:开始获取米游币的回复描述 2022-06-13 19:44:50 +08:00
04a486a256 '修复:计算毕业度时,绫人,绫华,迪奥娜,霄宫,九条的异常问题' 2022-06-13 00:05:26 +08:00
d1ca4da918 '新增:查询xx页面新增角色毕业度' 2022-06-12 22:56:55 +08:00
75d6083419 修复:强制刷新造成的安柏数据错误;新增:equipSets字段 2022-06-11 17:29:39 +08:00
c2e87458a1 更新:参考面板水新增夜兰 2022-06-07 19:22:42 +08:00
202e86ee77 Update README.md 2022-06-07 12:57:31 +08:00
27eef2e13e 优化:武器命令(防止两个Bot互刷) 2022-06-06 13:06:44 +08:00
9c9bae7cc6 新增:数据库将保留五天备份 2022-06-05 22:24:21 +08:00
6c41b75e42 修复:查询收集小数问题 & 更新数据 2022-06-05 20:26:14 +08:00
bfbf3140ac 优化:查询攻略图片前校验URL是否存在 2022-06-05 18:26:36 +08:00
a2305773a9 支持通过uid方式查询其他玩家的展柜信息 2022-06-05 16:42:49 +08:00
ec250a3cbb 修复若水和落霞的武器map 2022-06-05 16:30:04 +08:00
f7d62129cb 完善查询展柜信息的错误提示 2022-06-05 13:58:06 +08:00
d24a3109f0 更新xx能用啥命令的推荐表 & 备注 2022-06-04 21:57:43 +08:00
e2b52b0987 完善Map制作方式 2022-06-04 14:45:04 +08:00
8fb71cb0be fix 2022-06-03 19:19:17 +08:00
a974b7b1b7 去除UI线框,换用默认大图 2022-06-03 19:08:25 +08:00
a475fd8811 修复:命座数据问题 2022-06-02 11:37:07 +08:00
74e471380a 添加:夜兰 2022-06-02 09:50:10 +08:00
6f9d251fd1 添加:夜兰 2022-06-02 09:49:29 +08:00
8e87716175 Merge pull request #249 from lgc2333/nonebot2-beta1
fix
2022-06-02 01:41:51 +08:00
daffc0e39f Merge remote-tracking branch 'origin/nonebot2-beta1' into nonebot2-beta1 2022-06-02 01:40:05 +08:00
ac2346def6 ~~fuck~~ fix 2022-06-02 01:39:50 +08:00
e7c9071a2a Merge branch 'KimigaiiWuyi:nonebot2-beta1' into nonebot2-beta1 2022-06-02 01:19:02 +08:00
07ac6fc212 requirements 2022-06-02 01:18:00 +08:00
6bb12944b8 fix 2022-06-02 01:17:02 +08:00
46d94cebe3 Merge pull request #248 from lgc2333/nonebot2-beta1
fix & format
2022-06-02 00:12:12 +08:00
94838c0a0a fix 2022-06-01 23:52:37 +08:00
4e2f6d8ee0 fix 2022-06-01 23:40:26 +08:00
47bc645b68 format 2022-06-01 23:34:57 +08:00
60d1c59f2c matcher.**finsih** 2022-06-01 23:33:48 +08:00
96d4ba3211 Merge branch 'nonebot2-beta1' of https://github.com/lgc2333/GenshinUID into nonebot2-beta1 2022-06-01 23:16:33 +08:00
26fbb1b38c 补充文件 2022-06-01 23:13:59 +08:00
d201c33278 Merge branch 'nonebot2-beta1' of https://github.com/lgc2333/GenshinUID into nonebot2-beta1 2022-06-01 22:57:46 +08:00
97fee4c824 新增:查询展柜角色 2022-06-01 22:14:57 +08:00
12bd7ba921 chore(deps): pin nonebot2 to 2.0.0b2 2022-06-01 15:04:19 +08:00
29a98bab97 fix: import ActionFailed from nonebot.adapters.onebot.v11 2022-06-01 15:03:09 +08:00
e4c4e66e58 新增:查询收集 2022-06-01 00:02:24 +08:00
f74d04f53a Merge branch 'KimigaiiWuyi:nonebot2-beta1' into nonebot2-beta1 2022-05-31 01:52:42 +08:00
ead44f46f6 新增:gs关闭米游币推送 2022-05-28 21:41:34 +08:00
894da9c2a6 整理依赖 (#240) 2022-05-25 21:36:23 +08:00
ae25d5c6b1 修复:新api接口(-record) 2022-05-18 19:44:01 +08:00
4f605e8654 Merge #229 into nonebot2-beta1 (by @lgc2333) 2022-05-11 08:37:38 +08:00
ca8ecb677b Merge branch 'nonebot2-beta1' of https://github.com/lgc2333/GenshinUID into nonebot2-beta1 2022-05-11 02:25:26 +08:00
89db8d35ca reformat README 2022-05-11 02:21:54 +08:00
65c3496e37 Merge #222 into nonebot2-beta1 (by @lgc2333)
gen char_adv_list.json from xlsx that weapon_adv and char_adv use
2022-05-02 22:32:43 +08:00
eccfe329a3 rename 2022-05-02 22:30:20 +08:00
86e22f7374 modify regex match param 2022-05-02 22:27:12 +08:00
62fccbedef move 2022-05-02 22:23:48 +08:00
4ef0be08e8 fix 2022-05-02 22:19:11 +08:00
1fd5b6c564 gen char_adv_list.json from xlsx that weapon_adv and char_adv use 2022-05-02 22:11:58 +08:00
1a88b93efd 同步查询 -> uid & mys 2022-05-01 23:00:54 +08:00
1b3706a46b 颜色转换 2022-05-01 22:58:59 +08:00
ecad374c03 Merge #220 into nonebot2-beta1
fix: use depends
2022-04-30 21:57:42 +08:00
fa4ca0be51 fix: use depends(fix #207, fix #219) 2022-04-30 21:49:51 +08:00
240a01fb18 Merge pull request #216 from yen-qian/nonebot2-beta1
修复安装时httpx版本冲突问题
2022-04-28 17:49:19 +08:00
yen
7103e7d8ca Update requirements.txt 2022-04-28 17:46:24 +08:00
728ea9abc2 yapf 2022-04-27 23:44:56 +08:00
2f90e0ee3b 新增:参考面板(eg.参考面板火) 2022-04-27 23:11:12 +08:00
42d28f2fed 当ck数量大于9条时,[校验全部Cookies]命令输出精简 2022-04-26 22:12:05 +08:00
1893edf8a7 fix: send error message(fix #207, fix #208) 2022-04-25 21:29:15 +08:00
92b9e1737f fix:send error message 2022-04-20 09:23:57 +08:00
d4c5d515c8 fix #205 2022-04-18 22:27:07 +08:00
1198c71160 fix #205 2022-04-18 22:23:16 +08:00
6d4704da56 test: wiki 2022-04-18 17:08:56 +08:00
4234cc2d2e fix:audio error&style: use finish 2022-04-18 16:53:54 +08:00
c07e864aa0 Merge #204 into nonebot2-beta1 (by @shirokurakana)
减少重复代码
2022-04-17 22:52:37 +08:00
de97644fd0 fix: finish can't raise FinishedException 2022-04-17 22:50:02 +08:00
3b862cb54f 减少重复代码 2022-04-17 22:24:54 +08:00
192682ea2a Merge pull request #202 from shirokurakana/nonebot2-beta1
重做消息响应器&参数获取
2022-04-17 11:03:48 +08:00
3593c2d163 防止一律响应开头满足条件的消息 2022-04-16 15:03:11 +08:00
9ae88a11d5 使用更好的方式实现指令参数的获取 2022-04-16 15:01:41 +08:00
7efc532f3e 合并 #199
Revert 197 nonebot2-beta1
2022-04-15 20:23:13 +08:00
c2e62045fd feat: use one scheduler 2022-04-15 15:14:59 +08:00
5de79b499f Revert "小修复" 2022-04-15 14:56:00 +08:00
dffdbcc4c6 Merge pull request #197 from shirokurakana/nonebot2-beta1
小修复
2022-04-14 18:13:40 +08:00
90e5b9d3e7 scheduler只需要require一次 2022-04-14 16:20:54 +08:00
6b6d9ee479 修复未配置优先级时引发的问题 2022-04-14 16:19:11 +08:00
3ae3611d36 fix: the error message send error by record type 2022-04-11 20:51:14 +08:00
7c75145a50 fix: the error message send error by record type 2022-04-11 20:47:13 +08:00
ad88bc5011 fix: key-value error 2022-04-08 17:34:50 +08:00
18a16db8db 合并 #192 (closed #191)
补上一个空格 & 修复给谁用
2022-04-08 17:28:36 +08:00
bb385e3f9f fix: key and value error 2022-04-08 17:27:21 +08:00
d600d4ff9a fix 2022-04-08 17:23:06 +08:00
71620ce015 fix text 2022-04-08 17:16:09 +08:00
19d9781107 modify 2022-04-08 17:13:09 +08:00
f42788c008 修复给谁用 2022-04-08 16:04:28 +08:00
6c95472351 补上一个空格 2022-04-08 15:58:58 +08:00
1a92f35fcc 适应米游社数据 2022-04-08 00:17:11 +08:00
f800581446 修复:未探索地下造成的查询错误 & gs帮助错别字 2022-04-06 23:14:17 +08:00
b63c5b9ba3 修复:米游社新命名造成的查询错误 & 优化:更深的颜色遮罩 2022-04-06 21:06:52 +08:00
22204b115d 修改错误 2022-04-06 00:21:12 +08:00
35b884a2d3 新增:gs帮助 & xx推荐|攻略 2022-04-06 00:15:07 +08:00
7440ef2805 Merge pull request #179 from lgc2333/nonebot2-beta1
规范引号
2022-04-03 22:36:27 +08:00
c54facc919 规范引号 2022-04-03 21:40:47 +08:00
4390193184 向下兼容Python 3.8 2022-04-02 23:51:38 +08:00
23ec1dce8d 合并lgc2333/nonebot2-beta1(#176)
修复全部重签
2022-04-02 21:00:27 +08:00
d3853a6eb4 修复全部重签 2022-04-02 20:47:49 +08:00
dfe71c99f0 Merge pull request #166 from chenchenriver/nonebot2-beta1
Update get_mihoyo_bbs_data.py
2022-04-01 14:22:10 +08:00
6ef6005112 Update get_mihoyo_bbs_data.py 2022-04-01 14:18:00 +08:00
e39094f54a 更新:推荐表格信息 2022-04-01 00:33:17 +08:00
435e4a2d9a fix 2022-04-01 00:23:48 +08:00
746cb89bf3 新增:当前状态 & 当前信息添加参量质变仪信息 2022-04-01 00:22:04 +08:00
83a8c53449 Merge branch 'nonebot2-beta1' of github.com:KimigaiiWuyi/GenshinUID into nonebot2-beta1 2022-04-01 00:21:55 +08:00
0907e10271 新增:当前状态 & 当前信息添加参量质变仪信息 2022-04-01 00:21:24 +08:00
e07183beae 修复活动列表未进行正则提取的错误以及当前信息图片全部恢复的重合问题(fix #130) 2022-03-31 14:34:48 +08:00
8daec54d15 更新依赖 2022-03-31 13:44:23 +08:00
0fc4d899b6 修复:八角色UI重叠问题 2022-03-31 09:40:16 +08:00
53b9026d0a 新增:层岩巨渊的适配 2022-03-31 01:20:21 +08:00
0ec2685d37 同步:beta1 & main分支 2022-03-31 00:06:46 +08:00
656fbb4749 Merge pull request #156 from lgc2333/nonebot2-beta1
修复词云
2022-03-30 09:27:03 +08:00
2a4da7699d 删除测试代码 2022-03-29 23:49:06 +08:00
b5ff2b3613 尝试修复词云 2022-03-29 23:37:29 +08:00
c121c95a4c Merge branch 'KimigaiiWuyi:nonebot2-beta1' into nonebot2-beta1 2022-03-29 23:24:36 +08:00
cbcaa41640 修复:御神签偶发性输出空字符串 & 其他 2022-03-29 23:18:08 +08:00
2e37a0ff9a 修复:御神签偶发性输出空字符串 & 其他 2022-03-29 23:17:08 +08:00
4389d23bcc Merge remote-tracking branch 'origin/nonebot2-beta1' into nonebot2-beta1 2022-03-29 23:15:34 +08:00
a2b2f2f3d3 尝试修复词云 2022-03-29 23:14:44 +08:00
0ddad55580 尝试修复词云 2022-03-29 22:49:17 +08:00
1cc1d4e765 Merge pull request #153 from lgc2333/nonebot2-beta1
修复满树脂仍然显示剩余时间的问题 & Fix
2022-03-29 15:00:44 +08:00
72bd7be66e fix 2022-03-29 04:03:37 +08:00
b1ff73ef0d 修复满树脂仍然显示剩余时间的问题 2022-03-29 03:59:07 +08:00
72d9fa0828 尝试修复 2022-03-29 03:50:31 +08:00
82e33b153b 建议无疑早日使用jb 2022-03-29 03:42:19 +08:00
06c67c85f8 建议无疑早日使用jb 2022-03-29 03:38:41 +08:00
fdeafed874 修改:开启/关闭为gs开启/gs关闭 2022-03-29 00:32:47 +08:00
e3fb49c791 re: 2022-03-29 00:31:18 +08:00
71db7d8f0f 同步 2022-03-28 00:10:03 +08:00
223f519ee1 新增:开启自动米游币 & 当前信息(当前状态图片版)& 全部重获取;优化:新的查询样式 2022-03-26 18:58:26 +08:00
8d6b3c5c77 Merge pull request #143 from lgc2333/nonebot2-beta1
fixes
2022-03-18 09:35:42 +08:00
a60b64181c fix 2022-03-18 09:29:59 +08:00
5260abac14 fix 2022-03-18 09:04:50 +08:00
7838150f35 fix tip 2022-03-18 08:39:10 +08:00
cd0c38700c Merge pull request #142 from lgc2333/nonebot2-beta1
兼容
2022-03-17 23:29:03 +08:00
70c23164c5 修复失误 2022-03-17 22:15:56 +08:00
f3c5cb80a1 兼容 2022-03-17 21:33:19 +08:00
f28d7ae0a0 nb a16分支同步(pr #141 by @Igc2333)
与nb a16分支同步
2022-03-17 20:29:37 +08:00
017c561008 与nb a16分支同步 2022-03-17 20:18:08 +08:00
35dcd29d74 Update the setting of priority(Fix #137) 2022-03-13 20:19:00 +08:00
3c4c7a83c8 修复:全部重签 2022-03-11 10:13:55 +08:00
5f20fbd347 新增:开始获取米游币 & 添加Stokne;修复:活动列表 2022-03-10 23:58:39 +08:00
d0f334c9aa 米游币自动获取前提:Stoken获取指南 2022-03-09 00:24:09 +08:00
0333757b92 fix 2022-03-09 00:18:22 +08:00
89fe126579 准备:当前状态图片版 & 自动米游币获取 2022-03-09 00:01:16 +08:00
b9991ac7d2 修改结构 2022-03-06 23:36:19 +08:00
ef0913e6dd 补充:新增文件 2022-03-06 00:04:57 +08:00
564f3b2783 新增:xxx用什么|能用啥|怎么养&xxx能给谁|给谁用|要给谁|谁能用 2022-03-05 23:57:24 +08:00
d49c3297ed 优化:统一深渊生成图 & 统一返回 (添加大量冗余代码 2022-03-05 22:01:45 +08:00
3df56c1249 ReadMe 2022-02-22 23:58:50 +08:00
e43392253c 更新接口 2022-02-22 23:52:41 +08:00
2d1339f8c1 优化:天赋wiki的显示(合并转发) 2022-02-22 23:49:57 +08:00
9597a6d1ba Merge pull request #118 from shirokurakana/nonebot2-beta1
nonebot2-beta1 分支的一些修复工作
2022-02-16 19:20:40 +08:00
8f3bc1f9ee 修复发不出消息 2022-02-16 17:17:54 +08:00
b8279048c1 使用MessageSegment代替CQ码 2022-02-16 16:44:53 +08:00
d2a8c048a1 修复:深渊查询问题 2022-02-16 16:16:28 +08:00
b785adf105 修复:活动列表时间 2022-02-15 00:14:01 +08:00
414e384f1c Merge pull request #115 from MingxuanGame/nonebot2-beta1
Nonebot2 beta1
2022-02-12 19:04:04 +08:00
0ca23df74f 格式化提交(事件响应部分) 2022-02-12 18:49:19 +08:00
e6b629d9e1 格式化提交(数据部分) 2022-02-12 18:48:52 +08:00
c37e008261 Merge pull request #109 from MingxuanGame/nonebot2
nonebot2 2.0.0b1更新
2022-02-08 13:50:29 +08:00
f3eb0b0aa1 填无疑复制错的坑 2022-02-07 23:49:49 +08:00
563933f78f nonebot2 2.0.0b1更新 2022-02-07 23:40:35 +08:00
89a8883f07 requirements 2022-02-06 23:26:47 +08:00
adc0a86ce0 修复 2022-02-04 19:26:28 +08:00
0fb37e41ab 优化:报错 2022-02-04 19:23:18 +08:00
ce110cba99 Merge branch 'nonebot2' of github.com:KimigaiiWuyi/GenshinUID into nonebot2 2022-02-03 20:08:05 +08:00
bf51b8a2a6 Readme 2022-02-03 20:07:48 +08:00
a3e9a00568 Merge pull request #104 from lgc2333/patch-1
fix
2022-02-03 17:57:29 +08:00
5adf659ac5 fix 2022-02-03 17:49:28 +08:00
7500be4078 优化:定时任务log&活动列表图片发送 2022-02-03 00:05:39 +08:00
c933d5d9ef requirements.txt 2022-02-02 13:00:06 +08:00
157ad92eda 优化:校验全部Cookies现在会私聊已失效CK的QQ账号提醒ck过期 2022-02-02 10:59:00 +08:00
82d2fbcda1 README! 2022-02-01 19:07:04 +08:00
2afaa437b7 优化:八角色UI信息内容 2022-02-01 18:39:07 +08:00
b7c896e18a 补充代码 2022-02-01 00:16:20 +08:00
16dc1fe974 优化:自动签到报告&新增:开启简洁签到报告 2022-02-01 00:05:57 +08:00
586481062c 删除:无效代码 2022-01-27 00:02:27 +08:00
fd0e60796e 修复:同步新的WikiAPI接口;优化:错误提示. 2022-01-26 23:47:11 +08:00
e91564ac08 添加依赖 2022-01-25 14:15:51 +08:00
e9042d42fd 临时修改 2022-01-25 14:12:42 +08:00
b92ff01ddb Update getMes.py 2022-01-25 13:40:59 +08:00
5d736dbda1 修改获取Cookies 2022-01-25 13:39:36 +08:00
a5006183ae 优化:每日签到 2022-01-24 00:39:28 +08:00
3b919f54fb 同步语音重试:PR #81 2022-01-23 01:54:40 +08:00
9c3e260d1a 移除:数据库优化命令 2022-01-23 01:13:55 +08:00
0054148196 新增:食物/圣遗物命令,支持模糊查询;修复&优化:签到/添加Ck指令 2022-01-23 00:52:45 +08:00
0be58c1f43 Create LICENSE 2022-01-11 19:39:37 +08:00
02d4809d2c Merge pull request #86 from lgc2333/nonebot2
edit
2022-01-08 20:48:50 +08:00
cea56eb3ea edit 2022-01-08 20:47:39 +08:00
e53a1d2299 Merge pull request #85 from lgc2333/nonebot2
加入洞天宝钱大概积攒速度和全恢复时间
2022-01-08 20:47:24 +08:00
2f0f8ccbd6 add features 2022-01-08 20:13:45 +08:00
c120bf65a3 Merge pull request #82 from lgc2333/nonebot2
修正文本
2022-01-07 12:30:54 +08:00
dd0720a32c edit 2022-01-07 11:51:54 +08:00
ed8d169134 edit 2022-01-07 11:49:17 +08:00
e59d4ed1e5 edit 2022-01-07 11:09:50 +08:00
7955f52ba9 Update getImg.py 2022-01-07 10:46:02 +08:00
fc9e35ed05 edit 2022-01-07 10:40:50 +08:00
c7cc86ca2d Merge pull request #81 from lgc2333/nonebot2
fix
2022-01-06 10:28:12 +08:00
199c2f3a78 fix record 2022-01-06 04:17:44 +08:00
5c9960b5af Merge pull request #80 from lgc2333/nonebot2
fix
2022-01-06 03:01:08 +08:00
81d5e52528 fix 2022-01-06 02:47:21 +08:00
8f70742528 fix 2022-01-06 02:41:27 +08:00
d00b7bcbd9 Merge pull request #78 from lgc2333/nonebot2
optimize
2022-01-06 02:31:57 +08:00
c47d091c40 fix 2022-01-06 02:24:45 +08:00
7ff2609f2d optimize 2022-01-06 02:17:37 +08:00
1e2f605776 readme 2022-01-06 00:35:21 +08:00
05f53275f6 新增:语音命令;修复:渊下宫带来的查询错误问题;新增:当前状态命令查询洞天宝钱数量 2022-01-06 00:17:11 +08:00
5728d4ecad Merge pull request #77 from lgc2333/nonebot2
修复活动列表发图失败
2022-01-06 00:11:03 +08:00
91758947ac update event list when load plugin 2022-01-05 21:45:17 +08:00
a6e06dce57 fix send pic 2022-01-05 21:03:37 +08:00
bc49efa759 修复:角色命令可能出错的问题 2022-01-01 15:42:23 +08:00
ad88859ca6 新增:开启&关闭自动签到/推送服务,可由超级管理员操作 2021-12-30 23:03:35 +08:00
3dce0539c6 新增:命座查询的模糊匹配;优化:代码结构 2021-12-30 22:29:29 +08:00
fcc038abc1 新增:武器已支持查询某个固定等级属性 & 支持模糊查询;修复:角色查等级时元素精通数值不正确显示。 2021-12-30 00:38:21 +08:00
247709b06a 修复:角色命令现已支持模糊查询(修复之前直接输出Json) 2021-12-30 00:02:12 +08:00
a4fbaccee8 修复&优化:数据获取方式 & 推送树脂可能造成的Bug;新增:原魔、天赋指令。 2021-12-29 23:51:45 +08:00
0fce1cbe92 Merge branch 'nonebot2' of github.com:KimigaiiWuyi/GenshinUID into nonebot2 2021-12-26 22:18:38 +08:00
823e998114 修复:活动列表可能导致的bug 2021-12-26 22:18:06 +08:00
66e76c71ba Merge pull request #64 from lgc2333/nonebot2
fix
2021-12-25 16:15:42 +08:00
926b48a890 fix 2021-12-25 16:06:02 +08:00
22b7a53e58 Merge pull request #62 from wudifeixue/patch-2
修复米哈游更改api造成的插件损坏
2021-12-24 14:06:11 +08:00
f09547ba04 重新再次修复 2021-12-23 23:04:26 -07:00
6f54c0c99a 补充意外删除的debug信息 2021-12-23 22:53:03 -07:00
5bc89880fe 修复米哈游更改api造成的插件损坏
顺便更新了更好的后台错误反馈信息方便debug
2021-12-23 22:48:20 -07:00
aab3d148c4 修复:Readme 2021-12-20 01:04:50 +08:00
c23e577c45 新增:若干功能 2021-12-20 00:33:38 +08:00
69250a8700 Merge pull request #56 from ZhouYingSASA/nonebot2
Nonebot2:完善错误处理
2021-12-16 01:39:02 +08:00
5a9e63c54a fix: 完善错误处理 2021-12-16 01:27:56 +08:00
336c3f2aaf fix: 完善错误处理 2021-12-16 01:25:54 +08:00
9ba855fa17 修复:原神wiki相关功能 2021-12-11 00:28:47 +08:00
bd47c1dce8 fix 2021-12-10 00:51:34 +08:00
d04dd57aef !!fix!! 2021-12-04 19:17:37 +08:00
18a054ae66 !!fix!! 2021-12-04 19:13:08 +08:00
1b6dc2a194 !!fix!! 2021-12-04 19:03:19 +08:00
421291929d Merge pull request #35 from lgc2333/nonebot2
fix&feature
2021-11-26 10:09:32 +08:00
ecf9419186 fix 2021-11-26 04:30:46 +08:00
b5362fe575 feature 2021-11-26 04:03:23 +08:00
ac223d02b3 edit 2021-11-26 03:27:08 +08:00
babac2d270 fix 2021-11-26 02:51:42 +08:00
7ea57c069e fix 2021-11-25 22:09:07 +08:00
68a0fc6073 Merge branch 'nonebot2' of github.com:KimigaiiWuyi/GenshinUID into nonebot2 2021-11-25 22:03:27 +08:00
cedd47a453 fix 2021-11-25 22:02:56 +08:00
b72594f20e Merge pull request #31 from lgc2333/nonebot2
fixxxxxxxxxxxxxxxxxxx custom background of wordcloud
2021-11-21 03:08:25 +08:00
61cf1ce79e fixxxxxxxxxxxxxxxxxxx 2021-11-21 02:30:15 +08:00
997688fa67 Merge pull request #30 from lgc2333/nonebot2
fix wordcloud & add requirements
2021-11-21 02:16:04 +08:00
6aa62f2451 fix 2021-11-21 02:04:05 +08:00
96a2bf6a46 Update requirements.txt 2021-11-21 02:03:23 +08:00
53a58d458c Merge pull request #29 from lgc2333/nonebot2
紧急修复bug
2021-11-21 01:30:18 +08:00
4452e35f6a 紧急修复bug 2021-11-21 01:21:08 +08:00
608c505d7a 紧急修复bug 2021-11-21 01:13:40 +08:00
da36b1ae0d readme 2021-11-21 00:29:16 +08:00
d72bdf87ad fix and feat 2021-11-21 00:18:23 +08:00
dd19fc6bd2 Merge pull request #26 from lgc2333/nonebot2
尝试解决签到限制问题 添加通过.env.*配置文件设置消息处理优先级
2021-11-20 22:25:40 +08:00
a51d03c6ee 尝试解决签到限制问题 添加通过.env.*配置文件设置消息处理优先级 2021-11-20 03:55:21 +08:00
d73a6d57e4 尝试解决签到限制问题 添加通过.env.*配置文件设置消息处理优先级 2021-11-20 03:15:28 +08:00
84b46699ba Merge pull request #24 from lgc2333/nonebot2
改回readme 在requirements.txt添加nonebot-plugin-apscheduler>=0.1.2
2021-11-19 12:18:10 +08:00
9bdb8dfc3f Update README.md 2021-11-19 12:15:08 +08:00
286a74d004 Update requirements.txt 2021-11-19 12:14:16 +08:00
3cd332d8f5 Merge pull request #23 from lgc2333/patch-1
edit
2021-11-19 00:29:37 +08:00
2a3db3784f edit 2021-11-19 00:19:21 +08:00
1cea32424d fix 2021-11-18 00:43:11 +08:00
207c82dfab 合并Hoshino提交,修复Bug 2021-11-16 21:45:46 +08:00
dff8992adc fix 2021-11-15 00:51:16 +08:00
8a7fdb1709 fix 2021-11-15 00:14:43 +08:00
94682d43fe readme 2021-11-14 23:59:05 +08:00
2e34937700 NoneBot2 support 2021-11-14 23:48:04 +08:00
865 changed files with 218643 additions and 2128 deletions

16
.dockerignore Normal file
View File

@ -0,0 +1,16 @@
# .git
.vscode
.env
.venv
env
venv
.pytest_cache
*.pyc
*.pyo
*.pyd
.Python
tests
GenshinUID.egg-info
build
__pycache__
.pytest_cache

42
.github/workflows/unittest.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: Unittest
on:
push:
branches:
- nonebot2-beta1
pull_request:
jobs:
test:
name: Test
strategy:
matrix:
version: ["3.8", "3.9", "3.10", "3.11"]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
OS: ${{ matrix.os }}
PYTHON_VERSION: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v3
- name: Install poetry
run: pipx install poetry
shell: bash
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.version }}
architecture: "x64"
cache: "poetry"
- name: Install dependencies
run: poetry install --with test --without dev
shell: bash
- name: Run Pytest
run: |
cd tests
poetry run pytest

673
.gitignore vendored Normal file
View File

@ -0,0 +1,673 @@
# Created by https://www.toptal.com/developers/gitignore/api/visualstudio,visualstudiocode,jetbrains+all,python
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio,visualstudiocode,jetbrains+all,python
### JetBrains+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### JetBrains+all Patch ###
# Ignore everything but code style settings and run configurations
# that are supposed to be shared within teams.
.idea/*
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env/
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### VisualStudioCode ###
!.vscode/*
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# Support for Project snippet scope
.vscode/*.code-snippets
# Ignore code-workspaces
*.code-workspace
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
# Local History for Visual Studio Code
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
### VisualStudio Patch ###
# Additional files built by Visual Studio
# End of https://www.toptal.com/developers/gitignore/api/visualstudio,visualstudiocode,jetbrains+all,python,data
### CI ###
result.txt
### GenshinUID ###
GenshinUID/genshinuid_help/help.png
GenshinUID/genshinuid_map/map_data
### Debug ###
testnb2/

37
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,37 @@
ci:
autofix_commit_msg: ":rotating_light: auto fix by pre-commit-ci"
skip:
- "poetry-lock"
autofix_prs: true
autoupdate_branch: master
autoupdate_schedule: monthly
autoupdate_commit_msg: ":arrow_up: auto update by pre-commit-ci"
repos:
- repo: https://github.com/pycqa/isort
rev: 5.11.5
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: 22.6.0
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
rev: 5.0.4
hooks:
- id: flake8
- repo: https://github.com/hadialqattan/pycln
rev: v2.1.2
hooks:
- id: pycln
- repo: https://github.com/python-poetry/poetry
rev: 1.3.1
hooks:
- id: poetry-check
- id: poetry-lock
- id: poetry-export
args: ["-f", "requirements.txt", "--without-hashes", "-o", "requirements.txt"]
verbose: true

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["ms-python.python", "ms-python.vscode-pylance"]
}

19
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"python.languageServer": "Pylance",
"python.analysis.typeCheckingMode": "basic",
"cSpell.words": [
"audioid",
"enka",
"genshin",
"genshinuid",
"minigg",
"nonebot",
"nonebug",
"weapontype"
],
"[python]": {
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
}
}

43
Dockerfile Normal file
View File

@ -0,0 +1,43 @@
FROM python:3.9
# 1. 环境设置
# 使用镜像源
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
RUN apt-get update && apt-get install -y tzdata
ENV TZ Asia/Shanghai
# 2. 安装 GenshinUID
WORKDIR /plugin
COPY ./pyproject.toml ./LICENSE ./README.md /plugin/
COPY ./GenshinUID /plugin/GenshinUID/
RUN pip install --editable "."
COPY ./.git /plugin/.git
# 3. 生成 nb2 项目
WORKDIR /nb2
RUN pip install tomlkit "cookiecutter>=2.1.1"
COPY ./deploy/cookiecutter.yml ./deploy/update_pyproject.py /nb2/
# RUN cookiecutter --config-file ./cookiecutter.yml https://github.com/nonebot/nb-cli.git --directory="nb_cli/project" --no-input
# 使用镜像源
RUN cookiecutter --config-file ./cookiecutter.yml https://ghproxy.com/https://github.com/nonebot/nb-cli.git --directory="nb_cli/project" --no-input
RUN python update_pyproject.py
COPY ./deploy/.env.dev /nb2/nb2/
WORKDIR /nb2/nb2
EXPOSE 8080
CMD python bot.py

25
GenshinUID/__init__.py Normal file
View File

@ -0,0 +1,25 @@
from pathlib import Path
from pkgutil import iter_modules
from nonebot.log import logger
from nonebot import require, load_all_plugins, get_plugin_by_module_name
from .config import config as _config
require('nonebot_plugin_apscheduler')
if get_plugin_by_module_name("GenshinUID"):
logger.info("推荐直接加载 GenshinUID 仓库文件夹")
load_all_plugins(
[
f"GenshinUID.{module.name}"
for module in iter_modules([str(Path(__file__).parent)])
if module.ispkg
and (
(name := module.name[11:]) == "meta"
or name not in _config.disabled_plugins
)
# module.name[:11] == genshinuid_
],
[],
)

15
GenshinUID/config.py Normal file
View File

@ -0,0 +1,15 @@
from typing import Set
from nonebot import get_driver
from pydantic import Field, BaseModel
class Config(BaseModel):
disabled_plugins: Set[str] = Field(
default_factory=set, alias="genshinuid_disabled_plugins"
)
priority: int = Field(2, alias="genshinuid_priority")
config = Config.parse_obj(get_driver().config)
priority = config.priority

View File

@ -0,0 +1,102 @@
from typing import Any, Tuple, Union
from nonebot import on_regex
from nonebot.log import logger
from nonebot.matcher import Matcher
from nonebot.params import Depends, RegexGroup
from nonebot.adapters.onebot.v11 import (
MessageSegment,
GroupMessageEvent,
PrivateMessageEvent,
)
from ..genshinuid_meta import register_menu
from .draw_abyss_card import draw_abyss_img
from ..utils.message.error_reply import UID_HINT
from ..utils.db_operation.db_operation import select_db
from ..utils.message.get_image_and_at import ImageAndAt
from ..utils.mhy_api.convert_mysid_to_uid import convert_mysid
from ..utils.exception.handle_exception import handle_exception
get_abyss_info = on_regex(
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
r'(uid|查询|mys)?([0-9]+)?(上期)?(深渊|sy)'
r'(9|10|11|12|九|十|十一|十二)?(层)?'
r'(\[CQ:at,qq=[0-9]+\])?( )?$',
block=True,
)
@get_abyss_info.handle()
@handle_exception('查询深渊信息')
@register_menu(
'查询深渊信息',
'查询(@某人)(上期)深渊(xx层)',
'查询你的或者指定人的深渊战绩',
detail_des=(
'介绍:\n'
'可以用来查看你的或者指定人的深渊战绩,可以指定层数,默认为最高层数\n'
'可以在命令文本后带一张图以自定义背景图\n'
' \n' # 如果想要空行,请在换行符前面打个空格,不然会忽略换行符
'指令:\n'
'- <ft color=(238,120,0)>{查询</ft>'
'<ft color=(125,125,125)>(@某人)</ft>'
'<ft color=(238,120,0)>|uid</ft><ft color=(0,148,200)>xx</ft>'
'<ft color=(238,120,0)>|mys</ft><ft color=(0,148,200)>xx</ft>'
'<ft color=(238,120,0)>}</ft>'
'<ft color=(125,125,125)>(上期)</ft>'
'<ft color=(238,120,0)>深渊</ft>'
'<ft color=(125,125,125)>(xx层)</ft>\n'
' \n'
'示例:\n'
'- <ft color=(238,120,0)>查询深渊</ft>\n'
'- <ft color=(238,120,0)>uid123456789上期深渊</ft>\n'
'- <ft color=(238,120,0)>查询</ft><ft color=(0,123,67)>@无疑Wuyi</ft> '
'<ft color=(238,120,0)>上期深渊12层</ft>'
),
)
async def send_abyss_info(
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
args: Tuple[Any, ...] = RegexGroup(),
custom: ImageAndAt = Depends(),
):
logger.info('开始执行[查询深渊信息]')
logger.info(f'[查询深渊信息]参数: {args}')
at = custom.get_first_at()
qid = at or event.user_id
if args[2] == 'mys':
uid = await convert_mysid(args[3])
elif args[3] is None:
uid = await select_db(qid, mode='uid')
uid = str(uid)
elif len(args[3]) != 9:
return
else:
uid = args[3]
logger.info(f'[查询深渊信息]uid: {uid}')
if '未找到绑定的UID' in uid:
await matcher.finish(UID_HINT)
schedule_type = '1' if args[4] is None else '2'
logger.info(f'[查询深渊信息]深渊期数: {schedule_type}')
if args[6] in ['', '', '十一', '十二']:
floor = (
args[6]
.replace('', '9')
.replace('十一', '11')
.replace('十二', '12')
.replace('', '10')
)
else:
floor = args[6]
if floor is not None:
floor = int(floor)
logger.info(f'[查询深渊信息]深渊层数: {floor}')
im = await draw_abyss_img(uid, floor, schedule_type)
if isinstance(im, str):
await matcher.finish(im)
elif isinstance(im, bytes):
await matcher.finish(MessageSegment.image(im))
else:
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')

View File

@ -0,0 +1,316 @@
import time
import asyncio
from pathlib import Path
from typing import Union, Optional
from nonebot.log import logger
from PIL import Image, ImageDraw
from ..utils.get_cookies.get_cookies import GetCookies
from ..utils.download_resource.download_url import download_file
from ..utils.draw_image_tools.send_image_tool import convert_img
from ..utils.draw_image_tools.draw_image_tool import get_simple_bg
from ..utils.genshin_fonts.genshin_fonts import genshin_font_origin
from ..utils.download_resource.RESOURCE_PATH import (
CHAR_PATH,
TEXT2D_PATH,
CHAR_SIDE_PATH,
CHAR_STAND_PATH,
)
TEXT_PATH = Path(__file__).parent / 'texture2D'
TALENT_PATH = TEXT2D_PATH / 'talent'
abyss_title_pic = Image.open(TEXT_PATH / 'abyss_title.png')
char_mask = Image.open(TEXT_PATH / 'char_mask.png')
char_frame = Image.open(TEXT_PATH / 'char_frame.png')
text_title_color = (29, 29, 29)
text_floor_color = (30, 31, 25)
genshin_font_70 = genshin_font_origin(70)
genshin_font_32 = genshin_font_origin(32)
genshin_font_27 = genshin_font_origin(27)
async def get_abyss_star_pic(star: int) -> Image.Image:
star_pic = Image.open(TEXT_PATH / f'star{star}.png')
return star_pic
async def get_rarity_pic(rarity: int) -> Image.Image:
rarity_pic = Image.open(TEXT_PATH / f'rarity{rarity}.png')
return rarity_pic
async def get_talent_pic(talent: int) -> Image.Image:
return Image.open(TALENT_PATH / f'talent_{talent}.png')
async def get_rank_data(data: dict, path: Path):
char_id = data[0]['avatar_id']
# 只下载侧视图
if path == CHAR_SIDE_PATH:
# 确认角色头像路径
char_side_path = CHAR_PATH / f'{char_id}.png'
# 不存在自动下载
if not char_side_path.exists():
await download_file(data[0]['avatar_icon'], 3, f'{char_id}.png')
char_pic = Image.open(path / f'{char_id}.png').convert('RGBA')
if path == CHAR_STAND_PATH:
char_pic = char_pic.resize((862, 528), Image.Resampling.BICUBIC)
elif path == CHAR_SIDE_PATH:
char_pic = char_pic.resize((60, 60), Image.Resampling.BICUBIC)
rank_value = str(data[0]['value'])
return char_pic, rank_value
async def _draw_abyss_card(
char: dict,
talent_num: str,
floor_pic: Image.Image,
index_char: int,
index_part: int,
):
char_card = Image.new('RGBA', (150, 190), (0, 0, 0, 0))
# 根据稀有度获取背景
char_bg = await get_rarity_pic(char['rarity'])
# 确认角色头像路径
char_pic_path = CHAR_PATH / f'{char["id"]}.png'
# 不存在自动下载
if not char_pic_path.exists():
await download_file(char['icon'], 1, f'{char["id"]}.png')
char_pic = (
Image.open(char_pic_path)
.convert('RGBA')
.resize((150, 150), Image.Resampling.LANCZOS) # type: ignore
)
char_img = Image.new('RGBA', (150, 190), (0, 0, 0, 0))
char_img.paste(char_pic, (0, 3), char_pic)
char_bg = Image.alpha_composite(char_bg, char_img)
char_card.paste(char_bg, (0, 0), char_mask)
char_card = Image.alpha_composite(char_card, char_frame)
talent_pic = await get_talent_pic(int(talent_num))
char_card.paste(talent_pic, (83, 156), talent_pic)
char_card_draw = ImageDraw.Draw(char_card)
char_card_draw.text(
(9, 172),
f'Lv.{char["level"]}',
font=genshin_font_27,
fill=text_floor_color,
anchor='lm',
)
floor_pic.paste(
char_card,
(0 + 155 * index_char, 50 + index_part * 195),
char_card,
)
async def _draw_floor_card(
level_star: int,
floor_pic: Image.Image,
bg_img: Image.Image,
time_str: str,
index_floor: int,
):
star_pic = await get_abyss_star_pic(level_star)
floor_pic.paste(star_pic, (420, -5), star_pic)
floor_pic_draw = ImageDraw.Draw(floor_pic)
floor_pic_draw.text(
(31, 25),
time_str,
font=genshin_font_27,
fill=text_floor_color,
anchor='lm',
)
bg_img.paste(floor_pic, (5, 415 + index_floor * 440), floor_pic)
async def draw_abyss_img(
uid: str,
floor: Optional[int] = None,
schedule_type: str = '1',
) -> Union[bytes, str]:
# 获取Cookies
data_def = GetCookies()
retcode = await data_def.get_useable_cookies(uid)
if retcode:
return retcode
raw_data = data_def.raw_data
raw_abyss_data = await data_def.get_spiral_abyss_data(schedule_type)
# 获取数据
if raw_abyss_data:
raw_abyss_data = raw_abyss_data['data']
else:
return '没有获取到深渊数据'
if raw_data:
char_data = raw_data['data']['avatars']
else:
return '没有获取到角色数据'
char_temp = {}
# 获取查询者数据
is_unfull = False
if floor:
floor = floor - 9
if floor < 0:
return '楼层不能小于9层!'
if len(raw_abyss_data['floors']) >= floor + 1:
floors_data = raw_abyss_data['floors'][floor]
else:
return '你还没有挑战该层!'
else:
if len(raw_abyss_data['floors']) == 0:
return '你还没有挑战本期深渊!\n可以使用[上期深渊]命令查询上期~'
floors_data = raw_abyss_data['floors'][-1]
levels_num = len(floors_data['levels'])
if floors_data['levels'][0]['battles']:
floors_title = str(floors_data['index']) + ''
else:
floors_title = '统计'
is_unfull = True
# 获取背景图片各项参数
based_w = 625
based_h = 415 if is_unfull else 415 + levels_num * 440
white_overlay = Image.new('RGBA', (based_w, based_h), (255, 255, 255, 188))
bg_img = await get_simple_bg(based_w, based_h)
bg_img.paste(white_overlay, (0, 0), white_overlay)
abyss_title = Image.new('RGBA', (625, 415), (0, 0, 0, 0))
damage_rank = raw_abyss_data['damage_rank']
defeat_rank = raw_abyss_data['defeat_rank']
take_damage_rank = raw_abyss_data['take_damage_rank']
normal_skill_rank = raw_abyss_data['normal_skill_rank']
energy_skill_rank = raw_abyss_data['energy_skill_rank']
dmg_pic, dmg_val = await get_rank_data(damage_rank, CHAR_STAND_PATH)
defeat_pic, defeat_val = await get_rank_data(defeat_rank, CHAR_SIDE_PATH)
(
take_damage_pic,
take_damage_val,
) = await get_rank_data(take_damage_rank, CHAR_SIDE_PATH)
(
normal_skill_pic,
normal_skill_val,
) = await get_rank_data(normal_skill_rank, CHAR_SIDE_PATH)
(
energy_skill_pic,
energy_skill_val,
) = await get_rank_data(energy_skill_rank, CHAR_SIDE_PATH)
abyss_title.paste(dmg_pic, (13, -42), dmg_pic)
abyss_title = Image.alpha_composite(abyss_title, abyss_title_pic)
abyss_title.paste(defeat_pic, (5, 171), defeat_pic)
abyss_title.paste(take_damage_pic, (5, 171 + 54), take_damage_pic)
abyss_title.paste(normal_skill_pic, (5, 171 + 54 * 2), normal_skill_pic)
abyss_title.paste(energy_skill_pic, (5, 171 + 54 * 3), energy_skill_pic)
abyss_title_draw = ImageDraw.Draw(abyss_title)
abyss_title_draw.text(
(41, 95),
f'深渊{floors_title}',
font=genshin_font_70,
fill=text_title_color,
anchor='lm',
)
abyss_title_draw.text(
(41, 139),
f'UID{uid}',
font=genshin_font_27,
fill=text_title_color,
anchor='lm',
)
abyss_title_draw.text(
(610, 282),
dmg_val,
font=genshin_font_32,
fill=text_title_color,
anchor='rm',
)
abyss_title_draw.text(
(610, 357),
str(raw_abyss_data['total_battle_times']),
font=genshin_font_32,
fill=text_title_color,
anchor='rm',
)
abyss_title_draw.text(
(64, 217),
defeat_val,
font=genshin_font_27,
fill=text_title_color,
anchor='lm',
)
abyss_title_draw.text(
(64, 217 + 54),
take_damage_val,
font=genshin_font_27,
fill=text_title_color,
anchor='lm',
)
abyss_title_draw.text(
(64, 217 + 54 * 2),
normal_skill_val,
font=genshin_font_27,
fill=text_title_color,
anchor='lm',
)
abyss_title_draw.text(
(64, 217 + 54 * 3),
energy_skill_val,
font=genshin_font_27,
fill=text_title_color,
anchor='lm',
)
bg_img.paste(abyss_title, (0, 0), abyss_title)
if is_unfull:
pass
else:
task = []
for index_floor, level in enumerate(floors_data['levels']):
floor_pic = Image.new('RGBA', (615, 440), (0, 0, 0, 0))
level_star = level['star']
timestamp = int(level['battles'][0]['timestamp'])
time_array = time.localtime(timestamp)
time_str = time.strftime('%Y-%m-%d %H:%M:%S', time_array)
for index_part, battle in enumerate(level['battles']):
for index_char, char in enumerate(battle['avatars']):
# 获取命座
if char["id"] in char_temp:
talent_num = char_temp[char["id"]]
else:
for i in char_data:
if i["id"] == char["id"]:
talent_num = str(
i["actived_constellation_num"]
)
char_temp[char["id"]] = talent_num
break
task.append(
_draw_abyss_card(
char,
talent_num, # type: ignore
floor_pic,
index_char,
index_part,
)
)
await asyncio.gather(*task)
task.clear()
task.append(
_draw_floor_card(
level_star, floor_pic, bg_img, time_str, index_floor
)
)
await asyncio.gather(*task)
res = await convert_img(bg_img)
logger.info('[查询深渊信息]绘图已完成,等待发送!')
return res

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,34 @@
from nonebot import on_command
from nonebot.log import logger
from nonebot.matcher import Matcher
from nonebot.params import CommandArg
from nonebot.adapters.onebot.v11 import Message
from ..config import priority
from .get_achi_desc import get_achi, get_daily_achi
from ..utils.exception.handle_exception import handle_exception
get_task_info = on_command('查委托', aliases={'委托'}, priority=priority)
get_achi_info = on_command('查成就', aliases={'成就'}, priority=priority)
@get_task_info.handle()
@handle_exception('查委托')
async def send_task_info(matcher: Matcher, args: Message = CommandArg()):
if not args:
return
name = str(args[0])
logger.info(f'[查委托] 参数:{name}')
im = await get_daily_achi(name)
await matcher.finish(im)
@get_achi_info.handle()
@handle_exception('查成就')
async def send_achi_info(matcher: Matcher, args: Message = CommandArg()):
if not args:
return
name = str(args[0])
logger.info(f'[查成就] 参数:{name}')
im = await get_achi(name)
await matcher.finish(im)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,542 @@
{
"语言交流": {
"achievement": "…Odomu",
"desc": "在「语言交流」中与丘丘人交流成功。",
"guide": "《语言交流》:注意 1、不要攻击附近的丘丘人2、注意雷雨天小心落雷击中丘丘人导致任务失败",
"link": ""
},
"诗歌交流": {
"achievement": "Yo dala",
"desc": "在「诗歌交流」中与丘丘人交流成功。",
"guide": "《诗歌交流》:选择这 3 项即可【Celi dada,mimi nunu!】、【Ye dada!】、【Muhe ye!】其余同上",
"link": ""
},
"来自冬天的故事": {
"achievement": "有一说一",
"desc": "在「来自冬天的故事」中探听到所有关于至冬国的情报。",
"guide": "《来自冬天的故事》:愚人众、邪眼、女皇陛下,三个选项各选 1 次,也就是至少要做 3 次\n*2.4新增后续维克托回至冬(向冬日回归)\n*视频地址",
"link": "https://www.bilibili.com/video/BV1Xt4y1z7qw?spm_id_from=333.999.0.0"
},
"说到做到": {
"achievement": "追求极致",
"desc": "在「说到做到!」中完美完成查耶维奇的所有委托。",
"guide": "《说到做到!》至少 3 次“完美”且不重复地完成委托才能拿到成就。\n山顶按照顺序击杀火斧、木盾、丘丘人萨满山腰不能损坏货物可以拉怪出来\n山底需要 1 分钟内完成,跑图时间也算,可以提前放个口袋锚点,打怪前保留角色大招)\n*详解地址",
"link": "https://www.bilibili.com/video/BV1m64y1y7rk?"
},
"岩游记": {
"achievement": "帝君故事",
"desc": "搜集到「岩游记」中所有有关岩王帝君的故事。",
"guide": "《岩游记》需要做 4 次,给 4 次不同的道具:财神(必须是琉璃百合);开拓之神(野外采集物:琉璃袋 清心 绝云辣椒 霓裳花等);炉灶之神(各类矿石:夜泊石 铁矿 石珀 等等);历史之神(璃月菜品:翡翠什锦袋 水煮黑背鲈 等等)。\n*当“财神”和“历史之神”共同存在任务道具会被回收,当“炉灶之神”和“开拓之神”共同存在任务道具会被回收,注意记录。\n*视频地址及道具回收演示",
"link": "https://www.bilibili.com/video/BV1s64y1m718?p=1"
},
"且听下回分解": {
"achievement": "且听我一言。",
"desc": "在「且听下回分解」中听完《海山履云记》。",
"guide": null,
"link": ""
},
"璃月港,有海盗!": {
"achievement": "哎呀!海盗!",
"desc": "陪璐璐、阿飞与小蒙各玩一次海盗游戏。",
"guide": "《璃月港有海盗1.5 版本更新后在这三人附近挂机很容易刷到2.4后又新增后续\n*视频地址",
"link": "https://www.bilibili.com/video/BV1q44y1N7Dn?spm_id_from=333.999.0.0"
},
"好兆头": {
"achievement": "「…而尽人事。」",
"desc": "破坏了四种爱情运来临的征兆。",
"guide": "在《好兆头》中捕鱼、风吹或者火烧落叶、杀鸽子、看到狗要赶走。人为干涉所有的征兆。\n*视频地址",
"link": "https://www.bilibili.com/video/BV11r4y127Rw?spm_id_from=333.999.0.0"
},
"愿风带走思念": {
"achievement": "过量的思念",
"desc": "完成五次「愿风带走思念」。",
"guide": "《愿风带走思念》做 5 次。1.0版本2020年11月11日之前有BUG会做1次=5次的情况拿到成就后不会重置。如果进度不为5次会重置为0。从1.1后后重新计算。\n*视频地址",
"link": "https://www.bilibili.com/video/BV1xu41167hS?spm_id_from=333.999.0.0"
},
"勿言勿笑": {
"achievement": "厨子与渔夫",
"desc": "完成「独钓江雪」与「勿言勿笑」。",
"guide": "正常完成 2 个任务即可",
"link": ""
},
"独钓江雪": {
"achievement": "厨子与渔夫",
"desc": "完成「独钓江雪」与「勿言勿笑」。",
"guide": "正常完成 2 个任务即可",
"link": ""
},
"望舒须筑阶": {
"achievement": "更上一层楼",
"desc": "帮助淮安修复望舒客栈的断桥。",
"guide": "正常完成《望舒须筑阶》2次任务即可",
"link": ""
},
"鸽子、鸭子、小孩子": {
"achievement": "略表歉意",
"desc": "向提米道歉。",
"guide": "《鸽子、鸭子、小孩子》里投食鸭子后故意杀掉鸭子,第二天刷《提米,对不起》",
"link": ""
},
"提米,对不起!": {
"achievement": "略表歉意",
"desc": "向提米道歉。",
"guide": "《鸽子、鸭子、小孩子》里投食鸭子后故意杀掉鸭子,第二天刷《提米,对不起》",
"link": ""
},
"鸽子习惯一去不回": {
"achievement": "「您好,亲爱的爸爸…」",
"desc": "了解提米的故事。",
"guide": "水银的讲解视频点此;\n每日委托《鸽子习惯一去不回》有三个支线第一种正常赶走鸽子做完没有后续\n第二种赶鸽子的时候玩家杀了鸽子被杜拉夫要求让旅行者亲自去送信做完后也没有后续\n第三种赶鸽子的时候发现任务提示点的地上一团金光跑过去发现丘丘人把鸽子抓走烧了吃了打死丘丘人完成任务没有后续\n第三种丘丘人支线又分成两种情况一是地上有一封信捡到信的话解锁后续每日委托《一个男孩的去信》做完这个委托后可以拿到成就\n建议在另外一个每日委托《鸽子、鸭子、小孩子》里不要杀死提米要你喂的鸽子这样更有可能进入掉信的支线\n至于提米那个略表歉意的成就可以在另外一次刷到鸽子鸭子小孩子以后再做",
"link": "https://www.bilibili.com/video/BV1xR4y1E7PR"
},
"一个男孩的去信": {
"achievement": "「您好,亲爱的爸爸…」",
"desc": "了解提米的故事。",
"guide": "水银的讲解视频点此;\n每日委托《鸽子习惯一去不回》有三个支线第一种正常赶走鸽子做完没有后续\n第二种赶鸽子的时候玩家杀了鸽子被杜拉夫要求让旅行者亲自去送信做完后也没有后续\n第三种赶鸽子的时候发现任务提示点的地上一团金光跑过去发现丘丘人把鸽子抓走烧了吃了打死丘丘人完成任务没有后续\n第三种丘丘人支线又分成两种情况一是地上有一封信捡到信的话解锁后续每日委托《一个男孩的去信》做完这个委托后可以拿到成就\n建议在另外一个每日委托《鸽子、鸭子、小孩子》里不要杀死提米要你喂的鸽子这样更有可能进入掉信的支线\n至于提米那个略表歉意的成就可以在另外一次刷到鸽子鸭子小孩子以后再做",
"link": "https://www.bilibili.com/video/BV1xR4y1E7PR"
},
"奇药庐中来": {
"achievement": "妙手怪医",
"desc": "治好安娜的病。",
"guide": "《奇药庐中来》要做 3 次,之后解锁《大病初愈》后续任务;第一次做完《大病初愈》后给成就。\n成就拿完后《大病初愈》可能还会反复刷安娜会出现在三个位置风车顶上、教堂顶上、风神像手上\n*视频地址",
"link": "https://www.bilibili.com/video/BV1Hw411Z7zp?spm_id_from=333.999.0.0"
},
"大病初愈": {
"achievement": "妙手怪医",
"desc": "治好安娜的病。",
"guide": "《奇药庐中来》要做 3 次,之后解锁《大病初愈》后续任务;第一次做完《大病初愈》后给成就。\n成就拿完后《大病初愈》可能还会反复刷安娜会出现在三个位置风车顶上、教堂顶上、风神像手上\n*视频地址",
"link": "https://www.bilibili.com/video/BV1Hw411Z7zp?spm_id_from=333.999.0.0"
},
"餐品订单": {
"achievement": "这不是应急食品",
"desc": "在「餐品订单」任务中吃掉了餐品…?",
"guide": "成就是刷到任务以后吃掉任务菜品就可以拿,但是蟹黄火腿焗时蔬的食谱是不一定给的(送餐给活跃的欧琳的支线才会给,途中要打史莱姆)(触发哪条支线是随机的)",
"link": ""
},
"惊喜大礼": {
"achievement": "西风佑我",
"desc": "见证吉丽安娜的故事。",
"guide": "《惊喜大礼》要做 4 次不同路线(莎拉店、纪念品店、坤恩水果摊、芙萝拉花店)\n最后触发最终剧情此任务还有后续盗宝团来复仇触发“那位先生的委托”\n*视频地址",
"link": "https://www.bilibili.com/video/BV1Ew411f74K?spm_id_from=333.999.0.0"
},
"「冒险家」的能力极限": {
"achievement": "凑合…也能用",
"desc": "只带给赫尔曼木桩的材料。",
"guide": "《「冒险家」的能力极限》木桩一定要打坏带回",
"link": ""
},
"冒险家测验·作战方式": {
"achievement": "安娜冒险记",
"desc": "帮助安娜成为一名冒险家。",
"guide": "《冒险家,安娜!》\n拿到成就的过程和给安娜治病差不多且需要先给安娜治好病也就是完成每日委托成就《妙手怪医》之后完成前置任务《冒险家测验·作战方式》、《冒险家测验·冒险诀窍》、《冒险家测验·起飞方式》最后接到后续《冒险家安娜第一次完成任务后拿到成就\n做完成就后还有后续支线其中一条支线有“彩蛋”级内容但没成就\n*前置很阴间主要是情商选项后续这4个也很阴间不按套路出牌\n*视频地址",
"link": "https://www.bilibili.com/video/BV1Bu411r7Kb?spm_id_from=333.999.0.0"
},
"冒险家测验·冒险诀窍": {
"achievement": "安娜冒险记",
"desc": "帮助安娜成为一名冒险家。",
"guide": "《冒险家,安娜!》\n拿到成就的过程和给安娜治病差不多且需要先给安娜治好病也就是完成每日委托成就《妙手怪医》之后完成前置任务《冒险家测验·作战方式》、《冒险家测验·冒险诀窍》、《冒险家测验·起飞方式》最后接到后续《冒险家安娜第一次完成任务后拿到成就\n做完成就后还有后续支线其中一条支线有“彩蛋”级内容但没成就\n*前置很阴间主要是情商选项后续这4个也很阴间不按套路出牌\n*视频地址",
"link": "https://www.bilibili.com/video/BV1Bu411r7Kb?spm_id_from=333.999.0.0"
},
"冒险家测验·起飞方式": {
"achievement": "安娜冒险记",
"desc": "帮助安娜成为一名冒险家。",
"guide": "《冒险家,安娜!》\n拿到成就的过程和给安娜治病差不多且需要先给安娜治好病也就是完成每日委托成就《妙手怪医》之后完成前置任务《冒险家测验·作战方式》、《冒险家测验·冒险诀窍》、《冒险家测验·起飞方式》最后接到后续《冒险家安娜第一次完成任务后拿到成就\n做完成就后还有后续支线其中一条支线有“彩蛋”级内容但没成就\n*前置很阴间主要是情商选项后续这4个也很阴间不按套路出牌\n*视频地址",
"link": "https://www.bilibili.com/video/BV1Bu411r7Kb?spm_id_from=333.999.0.0"
},
"冒险家,安娜!": {
"achievement": "安娜冒险记",
"desc": "帮助安娜成为一名冒险家。",
"guide": "《冒险家,安娜!》\n拿到成就的过程和给安娜治病差不多且需要先给安娜治好病也就是完成每日委托成就《妙手怪医》之后完成前置任务《冒险家测验·作战方式》、《冒险家测验·冒险诀窍》、《冒险家测验·起飞方式》最后接到后续《冒险家安娜第一次完成任务后拿到成就\n做完成就后还有后续支线其中一条支线有“彩蛋”级内容但没成就\n*前置很阴间主要是情商选项后续这4个也很阴间不按套路出牌\n*视频地址",
"link": "https://www.bilibili.com/video/BV1Bu411r7Kb?spm_id_from=333.999.0.0"
},
"『遗落』的文物": {
"achievement": "学者与「学者」",
"desc": "完成「『遗落』的文物」与「『夺宝』小行动」。",
"guide": "《遗落的文物》至少要做 3 次,剧情进展到解救学者索拉雅以后有才有几率刷出《夺宝小行动》",
"link": ""
},
"『夺宝』小行动": {
"achievement": "学者与「学者」",
"desc": "完成「『遗落』的文物」与「『夺宝』小行动」。",
"guide": "《遗落的文物》至少要做 3 次,剧情进展到解救学者索拉雅以后有才有几率刷出《夺宝小行动》",
"link": ""
},
"港口驶过几艘船,二四六七八": {
"achievement": "梦想与工作,诗与面包",
"desc": "完成「所谓『工作』」,并获得霖铃的诗集。",
"guide": "完成《港口驶过几艘船,二四六七八》时故意告诉霖铃错误的数量(注意船有驶入和驶出的区别),大概率第二天刷《所谓工作》;如果第二天没刷,可能过一阵子才会刷",
"link": ""
},
"所谓「工作」": {
"achievement": "梦想与工作,诗与面包",
"desc": "完成「所谓『工作』」,并获得霖铃的诗集。",
"guide": "完成《港口驶过几艘船,二四六七八》时故意告诉霖铃错误的数量(注意船有驶入和驶出的区别),大概率第二天刷《所谓工作》;如果第二天没刷,可能过一阵子才会刷",
"link": ""
},
"点石成…什么": {
"achievement": "时也运也",
"desc": "一次就选中了最高价值的璞石。",
"guide": "《点石成…什么》:正确方法是选最亮的石头。\n不放心的话可以卡视角来透视璞石内部有完整的石珀就可以选。\n注意并不是 100% 有石珀,纯随机,同理“餐品订单”任务\n外观最亮的通过透视可以看到里面发光、纹路有完整条纹的即可。\n",
"link": ""
},
"这本小说真厉害": {
"achievement": "这本小说真厉害!",
"desc": "偷看常九爷的书稿。",
"guide": "《这本小说真厉害!》,交书稿前派蒙会问你是否偷看,选择偷看即可",
"link": ""
},
"久久望故人": {
"achievement": "故人久未归",
"desc": "完成「久久望故人」任务。",
"guide": "《久久望故人》:一定要先做过世界任务的小九九,否则可能做完没成就。\n*视频地址",
"link": "https://www.bilibili.com/video/BV11U4y137Tr?spm_id_from=333.999.0.0"
},
"哎呀!海盗想长大!": {
"achievement": "远大前程",
"desc": "一位少年即将启程远行…",
"guide": "《小海盗,要出海!》\n前置《哎呀海盗想长大》、《随水而来的烦恼》\n后续《小小的远行》系列 3 个(没成就)\n*视频地址",
"link": "https://www.bilibili.com/video/BV1q44y1N7Dn?spm_id_from=333.999.0.0"
},
"随水而来的烦恼": {
"achievement": "远大前程",
"desc": "一位少年即将启程远行…",
"guide": "《小海盗,要出海!》\n前置《哎呀海盗想长大》、《随水而来的烦恼》\n后续《小小的远行》系列 3 个(没成就)\n*视频地址",
"link": "https://www.bilibili.com/video/BV1q44y1N7Dn?spm_id_from=333.999.0.0"
},
"小海盗,要出海!": {
"achievement": "远大前程",
"desc": "一位少年即将启程远行…",
"guide": "《小海盗,要出海!》\n前置《哎呀海盗想长大》、《随水而来的烦恼》\n后续《小小的远行》系列 3 个(没成就)\n*视频地址",
"link": "https://www.bilibili.com/video/BV1q44y1N7Dn?spm_id_from=333.999.0.0"
},
"试问,藏锋何处?": {
"achievement": "四方求剑",
"desc": "见证岚姐与「藏锋」的故事。",
"guide": null,
"link": ""
},
"剑去之日": {
"achievement": "行万里路…?",
"desc": "见证孙宇的故事。",
"guide": null,
"link": ""
},
"万端珊瑚事件簿": {
"achievement": "瞳孔中的伪装者",
"desc": "帮助珊瑚和龙二破获案件。",
"guide": "完成《万端珊瑚事件簿·结案时刻》后解锁成就,需要先完成前置任务,推测的顺序是:\n万端珊瑚事件簿 → 搜索工作x3次 → 合适的身份 → 迷惑行动x3次 → 结案时刻→收尾工作\n第二和四环节有 3 个分支地点(随机给其中 1 个):稻妻城附近、甘金岛附近、神里屋敷附近\n*视频地址",
"link": "https://www.bilibili.com/video/BV1i3411K7YD?spm_id_from=333.999.0.0"
},
"万端珊瑚事件簿·搜索工作": {
"achievement": "瞳孔中的伪装者",
"desc": "帮助珊瑚和龙二破获案件。",
"guide": "完成《万端珊瑚事件簿·结案时刻》后解锁成就,需要先完成前置任务,推测的顺序是:\n万端珊瑚事件簿 → 搜索工作x3次 → 合适的身份 → 迷惑行动x3次 → 结案时刻→收尾工作\n第二和四环节有 3 个分支地点(随机给其中 1 个):稻妻城附近、甘金岛附近、神里屋敷附近\n*视频地址",
"link": "https://www.bilibili.com/video/BV1i3411K7YD?spm_id_from=333.999.0.0"
},
"万端珊瑚事件簿·迷惑行动": {
"achievement": "瞳孔中的伪装者",
"desc": "帮助珊瑚和龙二破获案件。",
"guide": "完成《万端珊瑚事件簿·结案时刻》后解锁成就,需要先完成前置任务,推测的顺序是:\n万端珊瑚事件簿 → 搜索工作x3次 → 合适的身份 → 迷惑行动x3次 → 结案时刻→收尾工作\n第二和四环节有 3 个分支地点(随机给其中 1 个):稻妻城附近、甘金岛附近、神里屋敷附近\n*视频地址",
"link": "https://www.bilibili.com/video/BV1i3411K7YD?spm_id_from=333.999.0.0"
},
"万端珊瑚事件簿·合适的身份": {
"achievement": "瞳孔中的伪装者",
"desc": "帮助珊瑚和龙二破获案件。",
"guide": "完成《万端珊瑚事件簿·结案时刻》后解锁成就,需要先完成前置任务,推测的顺序是:\n万端珊瑚事件簿 → 搜索工作x3次 → 合适的身份 → 迷惑行动x3次 → 结案时刻→收尾工作\n第二和四环节有 3 个分支地点(随机给其中 1 个):稻妻城附近、甘金岛附近、神里屋敷附近\n*视频地址",
"link": "https://www.bilibili.com/video/BV1i3411K7YD?spm_id_from=333.999.0.0"
},
"万端珊瑚事件簿·结案时刻": {
"achievement": "瞳孔中的伪装者",
"desc": "帮助珊瑚和龙二破获案件。",
"guide": "完成《万端珊瑚事件簿·结案时刻》后解锁成就,需要先完成前置任务,推测的顺序是:\n万端珊瑚事件簿 → 搜索工作x3次 → 合适的身份 → 迷惑行动x3次 → 结案时刻→收尾工作\n第二和四环节有 3 个分支地点(随机给其中 1 个):稻妻城附近、甘金岛附近、神里屋敷附近\n*视频地址",
"link": "https://www.bilibili.com/video/BV1i3411K7YD?spm_id_from=333.999.0.0"
},
"万端珊瑚事件簿·收尾工作": {
"achievement": "真相只有一个…?",
"desc": "见证龙二的故事。",
"guide": "做完《万端珊瑚事件簿·结案时刻》后解锁《万端珊瑚事件簿·收尾工作》,新登场大和田剧情。\n*视频地址",
"link": "https://www.bilibili.com/video/BV1i3411K7YD?spm_id_from=333.999.0.0"
},
"家乡之味": {
"achievement": "璃月一番",
"desc": "用美味的料理治愈汤雯。",
"guide": "前置任务每日委托《家乡之味》交付奇怪的料理(无论哪种料理的奇怪的版本都行)给汤雯,汤雯拿到以后会说味道很微妙。\n正确完成前置任务后再接到后续每日委托《绝对独特的美味》 (非强制触发最快第二天可以接到最慢1个月后),三个选项 (绝云锅巴、腌笃鲜、烤吃虎鱼) 选哪种都可以,交付美味的料理即可解锁成就\n*.2.5版本后在再做一次该任务,汤雯会回璃月\n*视频地址",
"link": "https://www.bilibili.com/video/BV12f4y157fC?spm_id_from=333.999.0.0"
},
"绝对独特的美味": {
"achievement": "璃月一番",
"desc": "用美味的料理治愈汤雯。",
"guide": "前置任务每日委托《家乡之味》交付奇怪的料理(无论哪种料理的奇怪的版本都行)给汤雯,汤雯拿到以后会说味道很微妙。\n正确完成前置任务后再接到后续每日委托《绝对独特的美味》 (非强制触发最快第二天可以接到最慢1个月后),三个选项 (绝云锅巴、腌笃鲜、烤吃虎鱼) 选哪种都可以,交付美味的料理即可解锁成就\n*.2.5版本后在再做一次该任务,汤雯会回璃月\n*视频地址",
"link": "https://www.bilibili.com/video/BV12f4y157fC?spm_id_from=333.999.0.0"
},
"全能美食队·突破性思维": {
"achievement": "噼咔,为什么又是噼咔",
"desc": "向香菱请教到特别的烹饪手法。",
"guide": "《全能美食队·突破性思维》\n剧情里旭东会让旅行者去璃月的万民堂找卯师傅卯师傅会给你 2 个选项,选择“也许香菱知道怎么解决他的问题…”这个选项,卯师傅说香菱去轻策庄了,让你找点绝云椒椒和禽肉。这时候你可以不管卯师傅要的东西,自己传送到轻策庄去找香菱对话,最后回去找旭东\n香菱在轻策庄西南的传送点刚传送过去就会被野猪撞的那个附近\n此外只要自己去找香菱对话最后交付道具时交付香菱给的就行了对话选哪个选项其实无所谓\n*视频地址",
"link": "https://www.bilibili.com/video/BV1zv411g7VE?spm_id_from=333.999.0.0"
},
"全能美食队·烹饪对决": {
"achievement": "双人餐行",
"desc": "帮助旭东和龟井宗久各完成一次烹饪。",
"guide": "《全能美食队·烹饪对决》:双方各胜利 1 次即可。\n灭火BUG已经修护如实正常做任务即可\n*视频地址",
"link": "https://www.bilibili.com/video/BV1zv411g7VE?spm_id_from=333.999.0.0"
},
"全能美食队·美食小问答": {
"achievement": "饮食问题",
"desc": "帮助芭尔瓦涅校对全部食谱。",
"guide": "《全能美食队·美食小问答》正确答案如下:\n北地苹果焖肉——胡椒 ;天枢肉———清心\n腌笃鲜—————竹笋 ;串串三味——鸟蛋 ;水煮黑背鲈——盐\n*视频地址",
"link": "https://www.bilibili.com/video/BV1zv411g7VE?spm_id_from=333.999.0.0"
},
"全能美食队·厨道的极意": {
"achievement": "武士饭",
"desc": "帮助龟井宗久搜集过全部两侧营地的食材。",
"guide": "《全能美食队·厨道的极意》:左右两边各要做 1 次\n*视频地址",
"link": "https://www.bilibili.com/video/BV1zv411g7VE?spm_id_from=333.999.0.0"
},
"稻妻销售员": {
"achievement": "「给您添蘑菇了!」",
"desc": "在「售后服务」中收到顾客绀田传助的抱怨。",
"guide": "前置任务《稻妻销售员》中,告诉绀田传助错误的化肥使用方法\n任务里有三个选项选择错误的选项\n每次刷到这个任务时瓦希德告诉你的方法的顺序可能是不一样的没有固定答案需要你自己判断哪个选项是错误的类似璃月港数船\n教错了的话绀田传助会说感觉不对劲\n之后解锁每日委托《售后服务》解锁代表有机会刷到但不是第二天一定就刷为绀田传助摘除田地里的蘑菇时注意要把全部的蘑菇都摘除、摘了一部分时派蒙会说“这下应该差不多了”同时系统提示可以找绀田传助交任务了此时不要理会继续摘蘑菇全部摘完以后派蒙会说“这下就全部摘干净了”这时再去找绀田传助交任务任务完成后解锁成就",
"link": ""
},
"售后服务": {
"achievement": "「给您添蘑菇了!」",
"desc": "在「售后服务」中收到顾客绀田传助的抱怨。",
"guide": "前置任务《稻妻销售员》中,告诉绀田传助错误的化肥使用方法\n任务里有三个选项选择错误的选项\n每次刷到这个任务时瓦希德告诉你的方法的顺序可能是不一样的没有固定答案需要你自己判断哪个选项是错误的类似璃月港数船\n教错了的话绀田传助会说感觉不对劲\n之后解锁每日委托《售后服务》解锁代表有机会刷到但不是第二天一定就刷为绀田传助摘除田地里的蘑菇时注意要把全部的蘑菇都摘除、摘了一部分时派蒙会说“这下应该差不多了”同时系统提示可以找绀田传助交任务了此时不要理会继续摘蘑菇全部摘完以后派蒙会说“这下就全部摘干净了”这时再去找绀田传助交任务任务完成后解锁成就",
"link": ""
},
"这本小说…厉害吗?": {
"achievement": "编辑部的一己之见",
"desc": "帮助阿茂和顺吉回到正确的创作轨道。",
"guide": "一阶段:《这本小说…厉害吗?》(支线:天目锻冶屋、九十九物、观察同心们的工作)\n二阶段支线 A《这本小说…有问题》\n二阶段支线 B《这本小说…好像看过按顺序123依次交书即可\n从剧情逻辑上来看在一阶段支持编辑阿茂解锁刷到《这本小说…好像看过》的可能性支持作家顺吉解锁刷到《这本小说…有问题》的可能性\n需要这三个每日都做完且在 B 支线交付\n*视频成就",
"link": "https://www.bilibili.com/video/BV1tu411C7jN?spm_id_from=333.999.0.0"
},
"这本小说…有问题?": {
"achievement": "编辑部的一己之见",
"desc": "帮助阿茂和顺吉回到正确的创作轨道。",
"guide": "一阶段:《这本小说…厉害吗?》(支线:天目锻冶屋、九十九物、观察同心们的工作)\n二阶段支线 A《这本小说…有问题》\n二阶段支线 B《这本小说…好像看过按顺序123依次交书即可\n从剧情逻辑上来看在一阶段支持编辑阿茂解锁刷到《这本小说…好像看过》的可能性支持作家顺吉解锁刷到《这本小说…有问题》的可能性\n需要这三个每日都做完且在 B 支线交付\n*视频成就",
"link": "https://www.bilibili.com/video/BV1tu411C7jN?spm_id_from=333.999.0.0"
},
"这本小说…好像看过?": {
"achievement": "编辑部的一己之见",
"desc": "帮助阿茂和顺吉回到正确的创作轨道。",
"guide": "一阶段:《这本小说…厉害吗?》(支线:天目锻冶屋、九十九物、观察同心们的工作)\n二阶段支线 A《这本小说…有问题》\n二阶段支线 B《这本小说…好像看过按顺序123依次交书即可\n从剧情逻辑上来看在一阶段支持编辑阿茂解锁刷到《这本小说…好像看过》的可能性支持作家顺吉解锁刷到《这本小说…有问题》的可能性\n需要这三个每日都做完且在 B 支线交付\n*视频成就",
"link": "https://www.bilibili.com/video/BV1tu411C7jN?spm_id_from=333.999.0.0"
},
"必须精进的武艺": {
"achievement": "同心训练家?",
"desc": "协助朝仓进行5次训练。",
"guide": "做 4 次每日委托《必须精进的武艺》后解锁世界任务《洗刷耻辱的一战》,完成世界任务后有机会刷到每日委托《永不停歇的修炼》,《必须精进的武艺》+《永不停歇的修炼》合计 5 次即可",
"link": ""
},
"永不停歇的修炼": {
"achievement": "同心训练家?",
"desc": "协助朝仓进行5次训练。",
"guide": "做 4 次每日委托《必须精进的武艺》后解锁世界任务《洗刷耻辱的一战》,完成世界任务后有机会刷到每日委托《永不停歇的修炼》,《必须精进的武艺》+《永不停歇的修炼》合计 5 次即可",
"link": ""
},
"每日委托《这本小说…有问题?》": {
"achievement": "至少有了个结局",
"desc": "听顺吉讲述完他所构思的故事。",
"guide": "需要在 2.1 版本后2.0 版本做过的不算)重做《这本小说…有问题?》和《这本小说…好像看过?》才能解锁世界任务《故事构思法》 ,做完世界任务后得到成\n*视频成就",
"link": "https://www.bilibili.com/video/BV1tu411C7jN?spm_id_from=333.999.0.0"
},
"每日委托《这本小说…好像看过?》": {
"achievement": "至少有了个结局",
"desc": "听顺吉讲述完他所构思的故事。",
"guide": "需要在 2.1 版本后2.0 版本做过的不算)重做《这本小说…有问题?》和《这本小说…好像看过?》才能解锁世界任务《故事构思法》 ,做完世界任务后得到成\n*视频成就",
"link": "https://www.bilibili.com/video/BV1tu411C7jN?spm_id_from=333.999.0.0"
},
"世界任务《故事构思法》": {
"achievement": "至少有了个结局",
"desc": "听顺吉讲述完他所构思的故事。",
"guide": "需要在 2.1 版本后2.0 版本做过的不算)重做《这本小说…有问题?》和《这本小说…好像看过?》才能解锁世界任务《故事构思法》 ,做完世界任务后得到成\n*视频成就",
"link": "https://www.bilibili.com/video/BV1tu411C7jN?spm_id_from=333.999.0.0"
},
"每日委托《神社大扫除》": {
"achievement": "她和她的猫",
"desc": "陪寝子前往影向山,寻找「阿响」的痕迹。",
"guide": "做完寝子系列的世界任务后,累积做 4 个寝子相关每日委托(指《神社大扫除》、《鱼之味》、《猫之迹》,大岛纯平那三个不算)后解锁世界任务《鸣神寻踪》,完成世界任务后解锁成就\n*视频地址",
"link": "https://www.bilibili.com/video/BV1T3411m7kJ"
},
"每日委托《鱼之味》": {
"achievement": "她和她的猫",
"desc": "陪寝子前往影向山,寻找「阿响」的痕迹。",
"guide": "做完寝子系列的世界任务后,累积做 4 个寝子相关每日委托(指《神社大扫除》、《鱼之味》、《猫之迹》,大岛纯平那三个不算)后解锁世界任务《鸣神寻踪》,完成世界任务后解锁成就\n*视频地址",
"link": "https://www.bilibili.com/video/BV1T3411m7kJ"
},
"每日委托《猫之迹》": {
"achievement": "她和她的猫",
"desc": "陪寝子前往影向山,寻找「阿响」的痕迹。",
"guide": "做完寝子系列的世界任务后,累积做 4 个寝子相关每日委托(指《神社大扫除》、《鱼之味》、《猫之迹》,大岛纯平那三个不算)后解锁世界任务《鸣神寻踪》,完成世界任务后解锁成就\n*视频地址",
"link": "https://www.bilibili.com/video/BV1T3411m7kJ"
},
"世界任务《鸣神寻踪》": {
"achievement": "她和她的猫",
"desc": "陪寝子前往影向山,寻找「阿响」的痕迹。",
"guide": "做完寝子系列的世界任务后,累积做 4 个寝子相关每日委托(指《神社大扫除》、《鱼之味》、《猫之迹》,大岛纯平那三个不算)后解锁世界任务《鸣神寻踪》,完成世界任务后解锁成就\n*视频地址",
"link": "https://www.bilibili.com/video/BV1T3411m7kJ"
},
"每日委托《鱼钩上的绝景?》": {
"achievement": "啊哈…什么上钩了?",
"desc": "与凯万一起钓起奇怪的东西…",
"guide": "累积做 3 次前置每日委托《鱼钩上的绝景有墩墩桃、鸟蛋、蘑菇三种支线注意是累积3次第二天4点后解锁世界任务《鱼钩的物尽其用》做完世界任务拿到成就。\n任务还有后续但是无成就可能未来版本会加后续成就。\n做完世界任务以后有机会接到每日委托《鱼钩的奇异时光和前边的也差不多有帕蒂沙兰、香辛果、甜甜花三种支线",
"link": ""
},
"世界任务《鱼钩的物尽其用》": {
"achievement": "啊哈…什么上钩了?",
"desc": "与凯万一起钓起奇怪的东西…",
"guide": "累积做 3 次前置每日委托《鱼钩上的绝景有墩墩桃、鸟蛋、蘑菇三种支线注意是累积3次第二天4点后解锁世界任务《鱼钩的物尽其用》做完世界任务拿到成就。\n任务还有后续但是无成就可能未来版本会加后续成就。\n做完世界任务以后有机会接到每日委托《鱼钩的奇异时光和前边的也差不多有帕蒂沙兰、香辛果、甜甜花三种支线",
"link": ""
},
"每日委托《鱼钩的奇异时光?》": {
"achievement": "啊哈…什么上钩了?",
"desc": "与凯万一起钓起奇怪的东西…",
"guide": "累积做 3 次前置每日委托《鱼钩上的绝景有墩墩桃、鸟蛋、蘑菇三种支线注意是累积3次第二天4点后解锁世界任务《鱼钩的物尽其用》做完世界任务拿到成就。\n任务还有后续但是无成就可能未来版本会加后续成就。\n做完世界任务以后有机会接到每日委托《鱼钩的奇异时光和前边的也差不多有帕蒂沙兰、香辛果、甜甜花三种支线",
"link": ""
},
"吞金和蓄财": {
"achievement": "卡里米之蕈兽",
"desc": "见证哈特姆在「期货交易」大赚一笔!",
"guide": "全随机后续正常需要做5次拿到2成就最速欧皇可以3次拿2成就。\n2022/9/5更新\n「吞金料理」中有3种料理摩拉肉黄油鸡和「堆高高」。\n建议选择美味的堆高高。\n2022/9/16更新\n现在发现变成了随机后续给任何料理都会触发任意成就原本应该给2次料理2个成就的也可以1次料理2成就。",
"link": ""
},
"喵…喵喵?喵!喵。": {
"achievement": "捉猫记",
"desc": "帮莎莉寻找过所有小猫。",
"guide": "至少要做 3 次,正确完成寻找 3 只不同小猫的支线\n「黑白色」的猫「拉勒」【喵喵喵喵喵——】\n「深灰色」的猫「纳尔吉斯」【喵喵喵喵】\n「灰黑条纹」的猫「萝赞」【喵喵喵喵喵喵】",
"link": ""
},
"世界任务《加尔恰的赞歌》": {
"achievement": "推分算数原理",
"desc": "帮助加尔恰完善他的机器。",
"guide": "推测需要先完后璃月望舒客栈的世界任务《加尔恰的赞歌》后才能在须弥接到这系列每日委托。\n《举手之劳》里正确选项【二次入炉的时候燃料记得加多点。】【从内向外敲打。】\n做完《某人的回响》后应该可以拿到成就同时解锁后续世界任务",
"link": ""
},
"每日委托《加尔恰的赞歌·关键物品》": {
"achievement": "推分算数原理",
"desc": "帮助加尔恰完善他的机器。",
"guide": "推测需要先完后璃月望舒客栈的世界任务《加尔恰的赞歌》后才能在须弥接到这系列每日委托。\n《举手之劳》里正确选项【二次入炉的时候燃料记得加多点。】【从内向外敲打。】\n做完《某人的回响》后应该可以拿到成就同时解锁后续世界任务",
"link": ""
},
"每日委托《加尔恰的赞歌·替代物》": {
"achievement": "推分算数原理",
"desc": "帮助加尔恰完善他的机器。",
"guide": "推测需要先完后璃月望舒客栈的世界任务《加尔恰的赞歌》后才能在须弥接到这系列每日委托。\n《举手之劳》里正确选项【二次入炉的时候燃料记得加多点。】【从内向外敲打。】\n做完《某人的回响》后应该可以拿到成就同时解锁后续世界任务",
"link": ""
},
"每日委托《加尔恰的赞歌·轴承在上》": {
"achievement": "推分算数原理",
"desc": "帮助加尔恰完善他的机器。",
"guide": "推测需要先完后璃月望舒客栈的世界任务《加尔恰的赞歌》后才能在须弥接到这系列每日委托。\n《举手之劳》里正确选项【二次入炉的时候燃料记得加多点。】【从内向外敲打。】\n做完《某人的回响》后应该可以拿到成就同时解锁后续世界任务",
"link": ""
},
"每日委托《加尔恰的赞歌·举手之劳》": {
"achievement": "推分算数原理",
"desc": "帮助加尔恰完善他的机器。",
"guide": "推测需要先完后璃月望舒客栈的世界任务《加尔恰的赞歌》后才能在须弥接到这系列每日委托。\n《举手之劳》里正确选项【二次入炉的时候燃料记得加多点。】【从内向外敲打。】\n做完《某人的回响》后应该可以拿到成就同时解锁后续世界任务",
"link": ""
},
"每日委托《加尔恰的赞歌·某人的回响》": {
"achievement": "推分算数原理",
"desc": "帮助加尔恰完善他的机器。",
"guide": "推测需要先完后璃月望舒客栈的世界任务《加尔恰的赞歌》后才能在须弥接到这系列每日委托。\n《举手之劳》里正确选项【二次入炉的时候燃料记得加多点。】【从内向外敲打。】\n做完《某人的回响》后应该可以拿到成就同时解锁后续世界任务",
"link": ""
},
"世界任务《加尔恰的赞歌·适配性赠礼》": {
"achievement": "推分算数原理",
"desc": "帮助加尔恰完善他的机器。",
"guide": "推测需要先完后璃月望舒客栈的世界任务《加尔恰的赞歌》后才能在须弥接到这系列每日委托。\n《举手之劳》里正确选项【二次入炉的时候燃料记得加多点。】【从内向外敲打。】\n做完《某人的回响》后应该可以拿到成就同时解锁后续世界任务",
"link": ""
},
"御用在他乡": {
"achievement": "「为了工作。」",
"desc": "为范兵卫采到更多的蘑菇。",
"guide": "每日委托《御用在他乡》\n√完结\n可以一次性拿到成就 要求采5个蘑菇但可以采7个给成就\n推测需要先做完稻妻的世界任务《踏鞴物语》系列才能在须弥接到这个委托。\n做完第一次以后他以后还会让你摘蘑菇对话内容会有些变化",
"link": ""
},
"谨遵医嘱": {
"achievement": "放松疗法",
"desc": "满足三个病人的愿望。",
"guide": "《洁净与健康》不是前置任务,可以直接刷到了《谨遵医嘱》\n《谨遵医嘱》这个任务是你和病人对话完成就可以回去交差了的但这样拿不到成就。你需要\n细节① 主动为古尔根清理田里的杂草,清理完以后再次与古尔根对话;② 阿兹拉说药太苦,和她对话,送给她【糖】;③ 阿夫塔想吃肉,给他【美味的烤肉排】。\n满足病人的愿望以后再回去交差。其中阿兹拉和阿夫塔不会主动问你要东西需要你听完他们的话以后再次与他们对话来交付道具",
"link": ""
},
"生不出的花": {
"achievement": "斩花除根",
"desc": "找到并打倒逃走的骗骗花。",
"guide": "前置累积3次《生不出的花》后后续出《花开之时》\n随机后续1有骗骗花的支线才有成就追击并干掉骗骗花后获得成就。\n随机后续2无骗骗花寄了再来3次……\n细节前置有 2 个支线,一个是提供肥料,另一个是浇水。",
"link": ""
},
"花开之时": {
"achievement": "斩花除根",
"desc": "找到并打倒逃走的骗骗花。",
"guide": "前置累积3次《生不出的花》后后续出《花开之时》\n随机后续1有骗骗花的支线才有成就追击并干掉骗骗花后获得成就。\n随机后续2无骗骗花寄了再来3次……\n细节前置有 2 个支线,一个是提供肥料,另一个是浇水。",
"link": ""
},
"衡量世界之人!": {
"achievement": "天有多高,地有多…",
"desc": "协助法伽尼进行测量工作。",
"guide": "1和2分支都是随机给的其中分支1还有3种怪丘丘人、蕈兽、遗迹蛇\n至少做 3 次,分别是:① 打怪;② 设置信标;③ 回收信标+打怪。",
"link": ""
},
"宝贝计划": {
"achievement": "非必要需求",
"desc": "找到古拉布吉尔给小蛇制作的所有道具。",
"guide": "帮古拉布吉尔找宠物蛇口粮,有 5 个支线。任务是你找到【古拉布吉尔的特制宠物蛇口粮】交给 NPC 就可以完成,但是做成就需要你额外找到 3 个东西:【奇怪的珠子】、【奇怪的小型帽子】、【破旧的架子】。\n每次随机给1个隐藏道具但是也可能没有。",
"link": ""
},
"问题的转化": {
"achievement": "船说了算",
"desc": "与拉菲克成功地测试了船体强度。",
"guide": "目前第三段就可以拿到成就,但是还有后续,可能未来版本还有成就。\n类似稻妻八重堂作家和编辑《小说有问题》在后续版本上线新成就。\n细节在《问题的转化·理论强度》中拿5块木头这样在《问题的转化·负载问题》中可以成功拿到成就失败的支线可能会退回到第二阶段。",
"link": ""
},
"问题的转化·理论强度": {
"achievement": "船说了算",
"desc": "与拉菲克成功地测试了船体强度。",
"guide": "目前第三段就可以拿到成就,但是还有后续,可能未来版本还有成就。\n类似稻妻八重堂作家和编辑《小说有问题》在后续版本上线新成就。\n细节在《问题的转化·理论强度》中拿5块木头这样在《问题的转化·负载问题》中可以成功拿到成就失败的支线可能会退回到第二阶段。",
"link": ""
},
"问题的转化·负载问题": {
"achievement": "船说了算",
"desc": "与拉菲克成功地测试了船体强度。",
"guide": "目前第三段就可以拿到成就,但是还有后续,可能未来版本还有成就。\n类似稻妻八重堂作家和编辑《小说有问题》在后续版本上线新成就。\n细节在《问题的转化·理论强度》中拿5块木头这样在《问题的转化·负载问题》中可以成功拿到成就失败的支线可能会退回到第二阶段。",
"link": ""
},
"问题的转化·关键在何?": {
"achievement": "船说了算",
"desc": "与拉菲克成功地测试了船体强度。",
"guide": "目前第三段就可以拿到成就,但是还有后续,可能未来版本还有成就。\n类似稻妻八重堂作家和编辑《小说有问题》在后续版本上线新成就。\n细节在《问题的转化·理论强度》中拿5块木头这样在《问题的转化·负载问题》中可以成功拿到成就失败的支线可能会退回到第二阶段。",
"link": ""
},
"食与学": {
"achievement": "问题何在?",
"desc": "享受三道贾法尔制作的料理。",
"guide": "每次随机给一个。\n完成 3 个支线:薄荷豆汤、绿汁脆球、烤肉卷",
"link": ""
},
"教令院,小问题": {
"achievement": "须弥博学者",
"desc": "答对六道不同的问题。",
"guide": "总共 6 道题,每次抽 3 道正确答案分别是1、阿弥利多学院2、悉般多摩学院3、圣树4、防沙壁5、驮兽6、蕈兽",
"link": ""
},
"跑,希尔米,跑": {
"achievement": "一步之遥",
"desc": "在与希尔米的赛跑中大意落败…",
"guide": null,
"link": ""
},
"良药难求": {
"achievement": "医用笔迹",
"desc": "帮助马鲁夫正确地解析药方。",
"guide": null,
"link": ""
},
"沙上花·余香": {
"achievement": "手有余香",
"desc": "见证内尔敏的故事。",
"guide": null,
"link": ""
}
}

View File

@ -0,0 +1,62 @@
import re
from .template import all_achi, daily_achi, achi_template, daily_template
async def get_daily_achi(task: str) -> str:
_similarity = 0
detail = {}
if task in daily_achi:
detail = daily_achi[task]
else:
for _task in daily_achi:
__task = ''.join(re.findall('[\u4e00-\u9fa5]', _task))
__task = __task.replace('每日委托', '').replace('世界任务', '')
similarity = len(set(__task) & set(task))
if similarity >= len(__task) / 2:
if similarity > _similarity:
_similarity = similarity
detail = daily_achi[_task]
task = _task
else:
if detail == {}:
return '该委托暂无成就...'
achi = detail['achievement']
desc = detail['desc']
guide = detail['guide']
link = detail['link']
im = daily_template.format(task, achi, desc, guide)
im = f'{im}\n{link}' if link else im
return im
async def get_achi(achi: str) -> str:
_similarity = 0
detail = {}
if achi in all_achi:
detail = all_achi[achi]
else:
for _achi in all_achi:
__achi = ''.join(re.findall('[\u4e00-\u9fa5]', _achi))
__achi = __achi.replace('每日委托', '').replace('世界任务', '')
similarity = len(set(__achi) & set(achi))
if similarity >= len(__achi) / 2:
if similarity > _similarity:
_similarity = similarity
detail = all_achi[_achi]
achi = _achi
else:
if detail == {}:
return '暂无该成就...'
book = detail['book']
desc = detail['desc']
guide = detail['guide']
link = detail['link']
im = achi_template.format(book, achi, desc)
im = f'{im}\n{guide}' if guide else im
im = f'{im}\n{link}' if link else im
return im

View File

@ -0,0 +1,20 @@
import json
from pathlib import Path
path = Path(__file__).parent
with open(path / 'all_achi.json', "r", encoding='UTF-8') as f:
all_achi = json.load(f)
with open(path / 'daily_achi.json', "r", encoding='UTF-8') as f:
daily_achi = json.load(f)
daily_template = '''任务:【{}
成就:【{}
描述:【{}
攻略:【{}
'''
achi_template = '''合辑:【{}
成就:【{}
描述:【{}
'''

Binary file not shown.

View File

@ -0,0 +1,72 @@
from typing import Any, Tuple
from nonebot import on_regex
from nonebot.matcher import Matcher
from nonebot.params import RegexGroup
from ..config import priority
from .get_adv import char_adv, weapon_adv
from ..genshinuid_meta import register_menu
from ..utils.alias.alias_to_char_name import alias_to_char_name
from ..utils.exception.handle_exception import handle_exception
get_char_adv = on_regex('([\u4e00-\u9fa5]+)(用什么|能用啥|怎么养)', priority=priority)
get_weapon_adv = on_regex(
'([\u4e00-\u9fa5]+)(能给谁|给谁用|要给谁|谁能用)', priority=priority
)
@get_char_adv.handle()
@handle_exception('建议')
@register_menu(
'角色配置推荐',
'xx用什么',
'查询角色武器/圣遗物推荐配置',
detail_des=(
'介绍:\n'
'可以查询某角色的武器/圣遗物推荐配置\n'
'支持部分角色别名\n'
' \n'
'指令:\n'
'- <ft color=(0,148,200)>[角色名]</ft>'
'<ft color=(238,120,0)>{用什么|能用啥|怎么养}</ft>\n'
' \n'
'示例:\n'
'- <ft color=(238,120,0)>钟离用什么</ft>\n'
'- <ft color=(238,120,0)>公子怎么养</ft>'
),
)
async def send_char_adv(
matcher: Matcher, args: Tuple[Any, ...] = RegexGroup()
):
name = await alias_to_char_name(str(args[0]))
im = await char_adv(name)
await matcher.finish(im)
@get_weapon_adv.handle()
@handle_exception('建议')
@register_menu(
'装备适用角色',
'xx能给谁',
'查询某武器/圣遗物能给谁用',
detail_des=(
'介绍:\n'
'可以通过武器/圣遗物名反查适用的角色\n'
'支持部分别名\n'
' \n'
'指令:\n'
'- <ft color=(0,148,200)>[武器名]</ft>'
'<ft color=(238,120,0)>{能给谁|给谁用|要给谁|谁能用}</ft>\n'
' \n'
'示例:\n'
'- <ft color=(238,120,0)>四风原典能给谁</ft>\n'
'- <ft color=(238,120,0)>千岩给谁用</ft>'
),
)
async def send_weapon_adv(
matcher: Matcher, args: Tuple[Any, ...] = RegexGroup()
):
name = await alias_to_char_name(str(args[0]))
im = await weapon_adv(name)
await matcher.finish(im)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
import json
from pathlib import Path
from ..utils.alias.alias_to_char_name import alias_to_char_name
with open(
Path(__file__).parent / 'char_adv_list.json', "r", encoding='UTF-8'
) as f:
adv_lst = json.load(f)
async def weapon_adv(name):
weapons = {}
artifacts = {}
for char, info in adv_lst.items():
char_weapons = []
char_artifacts = []
for i in info['weapon'].values(): # 3 stars, 4 stars, 5 stars
char_weapons.extend(i)
for i in info['artifact']:
char_artifacts.extend(i)
# char_artifacts = list(set(char_artifacts))
for weapon_name in char_weapons:
if name in weapon_name: # fuzzy search
char_weapon = weapons.get(weapon_name, [])
char_weapon.append(char)
weapons[weapon_name] = char_weapon
for artifact_name in char_artifacts:
if name in artifact_name: # fuzzy search
char_artifact = artifacts.get(artifact_name, [])
char_artifact.append(char)
char_artifact = list(set(char_artifact))
artifacts[artifact_name] = char_artifact
im = []
if weapons:
im.append('✨武器:')
for k, v in weapons.items():
im.append(f'{"".join(v)} 可能会用到【{k}')
if artifacts:
im.append('✨圣遗物:')
for k, v in artifacts.items():
im.append(f'{"".join(v)} 可能会用到【{k}')
if im == []:
im = '没有角色能使用【{}'.format(name)
else:
im = '\n'.join(im)
return im
async def char_adv(name: str):
name = await alias_to_char_name(name)
for char, info in adv_lst.items():
if name in char:
im = [f'{char}', '-=-=-=-=-=-=-=-=-=-']
if weapon_5 := info['weapon']['5']:
im.append(f'推荐5★武器{"".join(weapon_5)}')
if weapon_4 := info['weapon']['4']:
im.append(f'推荐4★武器{"".join(weapon_4)}')
if weapon_3 := info['weapon']['3']:
im.append(f'推荐3★武器{"".join(weapon_3)}')
if artifacts := info['artifact']:
im.append('推荐圣遗物搭配:')
for arti in artifacts:
if len(arti) > 1:
im.append(f'[{arti[0]}]两件套 + [{arti[1]}]两件套')
else:
im.append(f'[{arti[0]}]四件套')
if remark := info['remark']:
im.append('-=-=-=-=-=-=-=-=-=-')
im.append('备注:')
mark = "\n".join(remark)
im.append(f'{mark}')
return '\n'.join(im)
return '没有找到角色信息'

View File

@ -0,0 +1,142 @@
import random
import asyncio
from nonebot.log import logger
from nonebot.matcher import Matcher
from nonebot.params import CommandArg
from nonebot import get_bot, on_command
from nonebot.permission import SUPERUSER
from nonebot_plugin_apscheduler import scheduler
from nonebot.adapters.onebot.v11 import (
Message,
MessageEvent,
MessageSegment,
GroupMessageEvent,
)
from .util import black_ids
from ..config import priority
from .main import ann, consume_remind
from ..utils.nonebot2.rule import FullCommand
from ..utils.message.error_reply import UID_HINT
from ..utils.db_operation.db_operation import select_db
from ..genshinuid_config.default_config import string_config
from ..utils.exception.handle_exception import handle_exception
from .ann_card import sub_ann, unsub_ann, ann_list_card, ann_detail_card
update_ann_scheduler = scheduler
get_ann_info = on_command('原神公告', priority=priority)
reg_ann = on_command(
'订阅原神公告', priority=priority, rule=FullCommand(), permission=SUPERUSER
)
unreg_ann = on_command(
'取消订阅原神公告',
aliases={'取消原神公告', '退订原神公告'},
priority=priority,
rule=FullCommand(),
permission=SUPERUSER,
)
consume_ann = on_command('清除原神公告红点', priority=priority, rule=FullCommand())
@get_ann_info.handle()
@handle_exception('原神公告', '获取/发送原神公告失败')
async def send_ann_pic(
matcher: Matcher,
args: Message = CommandArg(),
):
ann_id = str(args).replace(' ', '').replace('#', '')
if not ann_id:
img = await ann_list_card()
await matcher.finish(MessageSegment.image(img))
if not ann_id.isdigit():
raise Exception("公告ID不正确")
img = await ann_detail_card(int(ann_id))
await matcher.finish(MessageSegment.image(img))
@reg_ann.handle()
@handle_exception('设置原神公告', '设置原神公告失败')
async def send_reg_ann(
event: GroupMessageEvent,
matcher: Matcher,
):
await matcher.finish(sub_ann(event.group_id))
@unreg_ann.handle()
@handle_exception('取消原神公告', '取消设置原神公告失败')
async def send_unreg_ann(
event: GroupMessageEvent,
matcher: Matcher,
):
await matcher.finish(unsub_ann(event.group_id))
@consume_ann.handle()
@handle_exception('取消原神公告红点', '取消红点失败')
async def send_consume_ann(
event: MessageEvent,
matcher: Matcher,
):
qid = event.user_id
uid = await select_db(qid, mode='uid')
uid = str(uid)
if '未找到绑定的UID' in uid:
await matcher.finish(UID_HINT)
await matcher.finish(await consume_remind(uid))
@update_ann_scheduler.scheduled_job('cron', minute=10)
async def check_ann():
await check_ann_state()
async def check_ann_state():
logger.info('[原神公告] 定时任务: 原神公告查询..')
ids = string_config.get_config('Ann_Ids')
sub_list = string_config.get_config('Ann_Groups')
if not sub_list:
logger.info('没有群订阅, 取消获取数据')
return
if not ids:
ids = await ann().get_ann_ids()
if not ids:
raise Exception('获取原神公告ID列表错误,请检查接口')
string_config.set_config('Ann_Ids', ids)
logger.info('初始成功, 将在下个轮询中更新.')
return
new_ids = await ann().get_ann_ids()
new_ann = set(ids) ^ set(new_ids)
if not new_ann:
logger.info('[原神公告] 没有最新公告')
return
for ann_id in new_ann:
if ann_id in black_ids:
continue
try:
img = await ann_detail_card(ann_id) # 防止抛出异常报错
bot = get_bot()
for group in sub_list:
try:
await bot.call_api(
api='send_group_msg',
group_id=group,
message=MessageSegment.image(img),
)
await asyncio.sleep(random.uniform(1, 3))
except Exception as e:
logger.exception(e)
except Exception as e:
logger.exception(str(e))
logger.info('[原神公告] 推送完毕, 更新数据库')
string_config.set_config('Ann_Ids', new_ids)

View File

@ -0,0 +1,216 @@
import re
from pathlib import Path
from bs4 import BeautifulSoup
from PIL import Image, ImageOps, ImageDraw
from .main import ann
from .util import filter_list
from ..genshinuid_config.default_config import string_config
from ..utils.draw_image_tools.send_image_tool import convert_img
from ..utils.genshin_fonts.genshin_fonts import gs_font_18, gs_font_26
from ..utils.draw_image_tools.draw_image_tool import (
get_pic,
easy_paste,
draw_text_by_line,
easy_alpha_composite,
)
assets_dir = Path(__file__).parent / 'assets'
list_head = Image.open(assets_dir / 'list.png')
list_item = (
Image.open(assets_dir / 'item.png').resize((384, 96)).convert('RGBA')
)
async def ann_list_card() -> bytes:
ann_list = await ann().get_ann_list()
if not ann_list:
raise Exception('获取游戏公告失败,请检查接口是否正常')
height_len = max(len(ann_list[0]['list']), len(ann_list[1]['list']))
bg = Image.new(
'RGBA',
(
list_head.width,
list_head.height + list_item.height * height_len + 20 + 30,
),
'#f9f6f2',
)
easy_paste(bg, list_head, (0, 0))
for data in ann_list:
x = 45
if data['type_id'] == 1:
x = 472
for index, ann_info in enumerate(data['list']):
new_item = list_item.copy()
subtitle = ann_info['subtitle']
draw_text_by_line(
new_item,
(0, 30 - (len(subtitle) > 10 and 10 or 0)),
subtitle,
gs_font_26,
'#3b4354',
250,
True,
)
draw_text_by_line(
new_item,
(new_item.width - 80, 10),
str(ann_info['ann_id']),
gs_font_18,
'#3b4354',
100,
)
bg = easy_alpha_composite(
bg, new_item, (x, list_head.height + (index * new_item.height))
)
tip = '*可以使用 原神公告#0000(右上角ID) 来查看详细内容, 例子: 原神公告#2434'
draw_text_by_line(
bg, (0, bg.height - 35), tip, gs_font_18, '#767779', 1000, True
)
return await convert_img(bg)
async def ann_detail_card(ann_id):
ann_list = await ann().get_ann_content()
if not ann_list:
raise Exception('获取游戏公告失败,请检查接口是否正常')
content = filter_list(ann_list, lambda x: x['ann_id'] == ann_id)
if not content:
raise Exception('没有找到对应的公告ID :%s' % ann_id)
soup = BeautifulSoup(content[0]['content'], 'lxml')
banner = content[0]['banner']
ann_img = banner if banner else ''
for a in soup.find_all('a'):
a.string = ''
for img in soup.find_all('img'):
img.string = img.get('src')
msg_list = [ann_img]
msg_list += [
BeautifulSoup(x.get_text('').replace('<<', ''), 'lxml').get_text()
+ '\n'
for x in soup.find_all('p')
]
drow_height = 0
for msg in msg_list:
if msg.strip().endswith(('jpg', 'png')):
_msg = re.search(r'(https://.*[png|jpg])', msg)
if _msg:
msg = _msg.group(0)
img = await get_pic(msg.strip())
img_height = img.size[1]
if img.width > 1080:
img_height = int(img.height * 0.6)
drow_height += img_height + 40
else:
(
x_drow_duanluo,
x_drow_note_height,
x_drow_line_height,
x_drow_height,
) = split_text(msg)
drow_height += x_drow_height
im = Image.new('RGB', (1080, drow_height), '#f9f6f2')
draw = ImageDraw.Draw(im)
# 左上角开始
x, y = 0, 0
for msg in msg_list:
if msg.strip().endswith(('jpg', 'png')):
_msg = re.search(r'(https://.*[png|jpg])', msg)
if _msg:
msg = _msg.group(0)
img = await get_pic(msg.strip())
if img.width > im.width:
img = img.resize((int(img.width * 0.6), int(img.height * 0.6)))
easy_paste(im, img, (0, y))
y += img.size[1] + 40
else:
(
drow_duanluo,
drow_note_height,
drow_line_height,
drow_height,
) = split_text(msg)
for duanluo, line_count in drow_duanluo:
draw.text((x, y), duanluo, fill=(0, 0, 0), font=gs_font_26)
y += drow_line_height * line_count
_x, _y = gs_font_26.getsize('')
padding = (_x, _y, _x, _y)
im = ImageOps.expand(im, padding, '#f9f6f2')
return await convert_img(im)
def split_text(content: str):
# 按规定宽度分组
max_line_height, total_lines = 0, 0
allText = []
for text in content.split('\n'):
duanluo, line_height, line_count = get_duanluo(text)
max_line_height = max(line_height, max_line_height)
total_lines += line_count
allText.append((duanluo, line_count))
line_height = max_line_height
total_height = total_lines * line_height
drow_height = total_lines * line_height
return allText, total_height, line_height, drow_height
def get_duanluo(text: str):
txt = Image.new('RGBA', (600, 800), (255, 255, 255, 0))
draw = ImageDraw.Draw(txt)
# 所有文字的段落
duanluo = ''
max_width = 1080
# 宽度总和
sum_width = 0
# 几行
line_count = 1
# 行高
line_height = 0
for char in text:
width, height = draw.textsize(char, gs_font_26)
sum_width += width
if sum_width > max_width: # 超过预设宽度就修改段落 以及当前行数
line_count += 1
sum_width = 0
duanluo += '\n'
duanluo += char
line_height = max(height, line_height)
if not duanluo.endswith('\n'):
duanluo += '\n'
return duanluo, line_height, line_count
def sub_ann(group):
groups = string_config.get_config('Ann_Groups')
if group in groups:
return '已经订阅了'
else:
groups.append(group)
string_config.set_config('Ann_Groups', groups)
return '成功订阅原神公告'
def unsub_ann(group):
groups = string_config.get_config('Ann_Groups')
if group in groups:
groups.remove(group)
string_config.set_config('Ann_Groups', groups)
return '成功取消订阅原神公告'
else:
return '已经不在订阅中了'

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,120 @@
import httpx
from .util import _Dict, black_ids, filter_list, cache_request_json
# https://webstatic.mihoyo.com/hk4e/announcement/index.html?auth_appid=announcement&authkey_ver=1&bundle_id=hk4e_cn&channel_id=1&game=hk4e&game_biz=hk4e_cn&lang=zh-cn&level=57&platform=pc&region=cn_gf01&sdk_presentation_style=fullscreen&sdk_screen_transparent=true&sign_type=2&uid=105293904#/
api_url = 'https://hk4e-api-static.mihoyo.com/common/hk4e_cn/announcement/api/'
api_params = (
'?game=hk4e'
'&game_biz=hk4e_cn'
'&lang=zh-cn'
'&bundle_id=hk4e_cn'
'&level=57'
'&platform={platform}'
'&region={region}'
'&uid={uid}'
)
ann_content_url = f'{api_url}getAnnContent{api_params}'
ann_list_url = f'{api_url}getAnnList{api_params}'
class ann:
ann_list_data = []
ann_content_data = []
today = 0
def __init__(self, platform='pc', uid='114514', region='cn_gf01'):
# self.today = datetime.datetime.fromtimestamp(
# time.mktime(datetime.date.today().timetuple()))
self.platform = platform
self.uid = uid
self.region = region
async def get_ann_content(self):
url = ann_content_url.format(
platform=self.platform, uid=self.uid, region=self.region
)
res = await cache_request_json(url=url)
if res.retcode == 0:
self.ann_content_data = res.data.list
return self.ann_content_data
async def get_ann_list(self):
url = ann_list_url.format(
platform=self.platform, uid=self.uid, region=self.region
)
res = await cache_request_json(url=url)
if res.retcode == 0:
result = []
for data in res.data.list:
data_list = [
x for x in data['list'] if not x['ann_id'] in black_ids
]
data['list'] = data_list
result.append(data)
self.ann_list_data = result
return self.ann_list_data
async def get_ann_ids(self):
await self.get_ann_list()
if not self.ann_list_data:
return []
ids = []
for label in self.ann_list_data:
ids += [x['ann_id'] for x in label['list']]
return ids
async def get_consume_remind_ann_ids(region, platform, uid):
ann_list = await ann(
platform=platform, uid=uid, region=region
).get_ann_list()
ids = []
for label in ann_list:
ids += filter_list(label.list, lambda x: x.remind == 1)
return [x.ann_id for x in ids]
async def consume_remind(uid):
region = 'cn_gf01'
if uid[0] == "5":
region = 'cn_qd01'
platform = ['pc']
ids = []
for p in platform:
ids += await get_consume_remind_ann_ids(region, p, uid)
ids = set(ids)
msg = f'取消公告红点完毕! 一共取消了{len(ids)}'
async with httpx.AsyncClient(
base_url="https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api"
) as client:
for ann_id in ids:
for p in platform:
res = await client.get(
"/consumeRemind",
timeout=10,
params={
'ann_id': ann_id,
'auth_appid': 'announcement',
'authkey_ver': '1',
'bundle_id': 'hk4e_cn',
'channel_id': '1',
'game': 'hk4e',
'game_biz': 'hk4e_cn',
'lang': 'zh-cn',
'level': '57',
'platform': p,
'region': region,
'sdk_presentation_style': 'fullscreen',
'sdk_screen_transparent': 'true',
'sign_type': '2',
'uid': uid,
},
)
res = res.json(object_hook=_Dict)
if res.retcode != 0:
msg += '\n %s 失败,原因:%s' % (ann_id, res.message)
return msg

View File

@ -0,0 +1,65 @@
# -*- coding: UTF-8 -*-
import inspect
import datetime
import functools
from typing import Dict, Optional, TypedDict
import httpx
class _Dict(dict):
__setattr__ = dict.__setitem__ # type: ignore
__getattr__ = dict.__getitem__
class _CacheData(TypedDict):
time: Optional[datetime.datetime]
value: Optional[int]
def filter_list(plist, func):
return list(filter(func, plist))
def cache(ttl=datetime.timedelta(hours=1), **kwargs):
def wrap(func):
cache_data: Dict[str, _CacheData] = {}
@functools.wraps(func)
async def wrapped(*args, **kw):
nonlocal cache_data
bound = inspect.signature(func).bind(*args, **kw)
bound.apply_defaults()
ins_key = '|'.join(
['%s_%s' % (k, v) for k, v in bound.arguments.items()]
)
default_data: _CacheData = {
'time': None,
'value': None,
}
data = cache_data.get(ins_key, default_data)
now = datetime.datetime.now()
if not data['time'] or now - data['time'] > ttl:
try:
data['value'] = await func(*args, **kw)
data['time'] = now
cache_data[ins_key] = data
except Exception as e:
raise e
return data['value']
return wrapped
return wrap
@cache(ttl=datetime.timedelta(minutes=30), arg_key='url')
async def cache_request_json(url):
async with httpx.AsyncClient() as client:
res = await client.get(url, timeout=10)
return res.json(object_hook=_Dict)
black_ids = [762, 422, 423, 1263, 495, 1957, 2522, 2388, 2516, 2476]

View File

@ -0,0 +1,186 @@
import random
import asyncio
from typing import Union
from nonebot import on_command
from nonebot.log import logger
from nonebot.matcher import Matcher
from nonebot.permission import SUPERUSER
from nonebot_plugin_apscheduler import scheduler
from nonebot.adapters.onebot.v11 import (
Bot,
GroupMessageEvent,
PrivateMessageEvent,
)
from ..config import priority
from .backup_data import data_backup
from ..genshinuid_meta import register_menu
from ..utils.nonebot2.rule import FullCommand
from ..utils.exception.handle_exception import handle_exception
from ..utils.db_operation.db_cache_and_check import check_db, check_stoken_db
from ..utils.db_operation.db_operation import delete_cookies, get_all_push_list
from ..utils.message.get_cqhttp_data import (
get_all_friend_list,
get_group_member_list,
)
backup = on_command('gs清除缓存', rule=FullCommand(), priority=priority)
check = on_command('校验全部Cookies', rule=FullCommand(), priority=priority)
check_stoken = on_command('校验全部Stoken', rule=FullCommand(), priority=priority)
remove_invalid_user = on_command(
'清除无效用户', rule=FullCommand(), priority=priority
)
backup_scheduler = scheduler
@backup_scheduler.scheduled_job('cron', hour=0)
async def daily_refresh_charData():
await data_backup()
@backup.handle()
@handle_exception('清除缓存', '清除缓存错误')
@register_menu(
'清除缓存',
'清除缓存',
'清除插件产生的缓存数据',
trigger_method='超级用户指令',
detail_des=(
'介绍:\n'
'备份一份插件数据库后清除插件产生的文件与数据库缓存\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>清除缓存</ft>'
),
)
async def send_backup_msg(
bot: Bot,
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
):
if not await SUPERUSER(bot, event):
return
await data_backup()
await matcher.finish('操作成功完成!')
@remove_invalid_user.handle()
@handle_exception('清除无效用户', '清除无效用户错误')
@register_menu(
'清除无效用户',
'清除无效用户',
'清除非好友或非推送群成员的数据',
trigger_method='超级用户指令',
detail_des=(
'介绍:\n'
'从数据库中删除掉 开启了私聊推送但不是Bot好友的用户 '
'以及 开启了群聊推送但不在推送目标群的用户 的数据\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>清除无效用户</ft>'
),
)
async def send_remove_invalid_user_msg(
bot: Bot,
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
):
if not await SUPERUSER(bot, event):
return
im_list = []
invalid_user = {}
invalid_uid_list = []
user_list = await get_all_push_list()
friend_list = await get_all_friend_list(bot)
for user in user_list:
if user['StatusA'] == 'on':
if user['QID'] not in friend_list:
invalid_user['qid'] = user['UID']
invalid_uid_list.append(user['UID'])
else:
group_member_list = await get_group_member_list(
bot, int(user['StatusA'])
)
if user['QID'] not in group_member_list:
invalid_user['qid'] = user['UID']
invalid_uid_list.append(user['UID'])
for uid in invalid_uid_list:
im_list.append(await delete_cookies(str(uid)))
logger.warning(f'无效UID已被删除: {uid}')
await matcher.finish(f'已清理失效用户{len(im_list)}个!')
# 群聊内 校验Cookies 是否正常的功能,不正常自动删掉
@check.handle()
@handle_exception('Cookie校验', 'Cookie校验错误')
@register_menu(
'校验全部Cookies',
'校验全部Cookies',
'校验数据库内所有Cookies是否正常',
detail_des=(
'介绍:\n'
'校验数据库内所有Cookies是否正常不正常的会自动删除\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>校验全部Cookies</ft>\n'
'注意<ft color=(238,120,0)>Cookies</ft>的'
'<ft color=(238,120,0)>C</ft>为大写'
),
)
async def send_check_cookie(bot: Bot, matcher: Matcher):
raw_mes = await check_db()
im = raw_mes[0]
await matcher.send(im)
for i in raw_mes[1]:
await bot.call_api(
api='send_private_msg',
**{
'user_id': i[0],
'message': (
'您绑定的Cookiesuid{})已失效,以下功能将会受到影响:\n'
'查看完整信息列表\n查看深渊配队\n自动签到/当前状态/每月统计\n'
'请及时重新绑定Cookies并重新开关相应功能。'
).format(i[1]),
},
)
await asyncio.sleep(3 + random.randint(1, 3))
await matcher.finish()
# 群聊内 校验Stoken 是否正常的功能,不正常自动删掉
@check_stoken.handle()
@handle_exception('Stoken校验', 'Stoken校验错误')
@register_menu(
'校验全部Stoken',
'校验全部Stoken',
'校验数据库内所有Stoken是否正常',
detail_des=(
'介绍:\n'
'校验数据库内所有Stoken是否正常不正常的会自动删除\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>校验全部Stoken</ft>\n'
'注意<ft color=(238,120,0)>Stoken</ft>的<ft color=(238,120,0)>S</ft>为大写'
),
)
async def send_check_stoken(bot: Bot, matcher: Matcher):
raw_mes = await check_stoken_db()
im = raw_mes[0]
await matcher.send(im)
for i in raw_mes[1]:
await bot.call_api(
api='send_private_msg',
**{
'user_id': i[0],
'message': (
'您绑定的Stokenuid{})已失效,以下功能将会受到影响:\n'
'gs开启自动米游币开始获取米游币。\n'
'重新添加后需要重新开启自动米游币。'
).format(i[1]),
},
)
await asyncio.sleep(3 + random.randint(1, 3))
await matcher.finish()

View File

@ -0,0 +1,30 @@
import os
import datetime
from shutil import copyfile
from nonebot.log import logger
from ..utils.db_operation.db_operation import empty_cache
from ..utils.download_resource.RESOURCE_PATH import TEMP_PATH
async def data_backup():
try:
today = datetime.date.today()
endday = today - datetime.timedelta(days=5)
date_format = today.strftime("%Y_%d_%b")
endday_format = endday.strftime("%Y_%d_%b")
copyfile('ID_DATA.db', f'ID_DATA_BAK_{date_format}.db')
if os.path.exists(f'ID_DATA_BAK_{endday_format}.db'):
os.remove(f'ID_DATA_BAK_{endday_format}.db')
logger.info(f'————已删除数据库备份{endday_format}————')
logger.info('————数据库成功备份————')
for f in TEMP_PATH.glob('*.jpg'):
try:
f.unlink()
except OSError as e:
print("Error: %s : %s" % (f, e.strerror))
await empty_cache()
logger.info('————缓存成功清除————')
except Exception:
logger.info('————数据库备份失败————')

View File

@ -0,0 +1,112 @@
from typing import Union
from nonebot import on_command
from nonebot.log import logger
from nonebot.matcher import Matcher
from nonebot.params import Depends, CommandArg
from nonebot.adapters.onebot.v11 import (
Message,
MessageSegment,
GroupMessageEvent,
PrivateMessageEvent,
)
from ..genshinuid_meta import register_menu
from ..utils.data_convert.get_uid import get_uid
from ..utils.message.error_reply import UID_HINT
from ..utils.message.get_image_and_at import ImageAndAt
from ..utils.exception.handle_exception import handle_exception
from .draw_collection_card import draw_explora_img, draw_collection_img
get_collection_info = on_command('查询收集', aliases={'收集', 'sj'}, block=True)
get_explora_info = on_command('查询探索', aliases={'探索', 'ts'}, block=True)
@get_collection_info.handle()
@handle_exception('查询收集信息')
@register_menu(
'查询收集信息',
'查询(@某人)收集',
'查询你的或者指定人的宝箱收集度',
detail_des=(
'介绍:\n'
'可以用来查看你的或者指定人的宝箱收集度\n'
'可以在命令文本后带一张图以自定义背景图\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>{查询</ft>'
'<ft color=(125,125,125)>(@某人)</ft>'
'<ft color=(238,120,0)>|uid</ft><ft color=(0,148,200)>xx</ft>'
'<ft color=(238,120,0)>|mys</ft><ft color=(0,148,200)>xx</ft>'
'<ft color=(238,120,0)>}</ft>'
'<ft color=(238,120,0)>{收集|宝箱|sj|bx}</ft>\n'
' \n'
'示例:\n'
'- <ft color=(238,120,0)>查询收集</ft>\n'
'- <ft color=(238,120,0)>uid123456789宝箱</ft>\n'
'- <ft color=(238,120,0)>查询</ft><ft color=(0,123,67)>@无疑Wuyi'
'</ft> <ft color=(238,120,0)>bx</ft>'
),
)
async def send_collection_info(
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
args: Message = CommandArg(),
custom: ImageAndAt = Depends(),
):
logger.info('开始执行[查询收集信息]')
logger.info('[查询收集信息]参数: {}'.format(args))
raw_mes = args.extract_plain_text().strip()
at = custom.get_first_at()
if at:
qid = at
else:
qid = event.user_id
# 获取uid
uid = await get_uid(qid, raw_mes)
logger.info('[查询角色面板]uid: {}'.format(uid))
if '未找到绑定的UID' in uid:
await matcher.finish(UID_HINT)
im = await draw_collection_img(qid, uid)
if isinstance(im, str):
await matcher.finish(im)
elif isinstance(im, bytes):
await matcher.finish(MessageSegment.image(im))
else:
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
@get_explora_info.handle()
@handle_exception('查询探索信息')
async def send_explora_info(
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
args: Message = CommandArg(),
custom: ImageAndAt = Depends(),
):
logger.info('开始执行[查询探索信息]')
logger.info('[查询探索信息]参数: {}'.format(args))
raw_mes = args.extract_plain_text().strip()
at = custom.get_first_at()
if at:
qid = at
else:
qid = event.user_id
# 获取uid
uid = await get_uid(qid, raw_mes)
logger.info('[查询角色面板]uid: {}'.format(uid))
if '未找到绑定的UID' in uid:
await matcher.finish(UID_HINT)
im = await draw_explora_img(qid, uid)
if isinstance(im, str):
await matcher.finish(im)
elif isinstance(im, bytes):
await matcher.finish(MessageSegment.image(im))
else:
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')

View File

@ -0,0 +1,220 @@
from pathlib import Path
from typing import Dict, Tuple, Union, Literal
from PIL import Image, ImageDraw
from ..utils.get_cookies.get_cookies import GetCookies
from ..utils.enka_api.map.GS_MAP_PATH import avatarId2Name
from ..utils.draw_image_tools.send_image_tool import convert_img
from ..utils.genshin_fonts.genshin_fonts import gs_font_30, gs_font_40
from ..utils.draw_image_tools.draw_image_tool import (
draw_bar,
get_color_bg,
get_qq_avatar,
draw_pic_with_ring,
)
TEXT_PATH = Path(__file__).parent / 'texture2D'
first_color = (29, 29, 29)
brown_color = (41, 25, 0)
red_color = (255, 66, 66)
green_color = (74, 189, 119)
max_data = {
'成就': 945,
'华丽的宝箱': 192,
'珍贵的宝箱': 510,
'精致的宝箱': 1639,
'普通的宝箱': 2690,
'奇馈宝箱': 161,
'解锁传送点': 304,
'解锁秘境': 51,
}
award_data = {
'成就': 5,
'华丽的宝箱': 10,
'珍贵的宝箱': 8,
'精致的宝箱': 3,
'普通的宝箱': 1,
'奇馈宝箱': 2,
'解锁传送点': 0,
'解锁秘境': 0,
}
expmax_data = {
'获得角色数': len(avatarId2Name) - 2,
'风神瞳': 66,
'岩神瞳': 131,
'雷神瞳': 181,
'草神瞳': 271,
}
async def draw_collection_img(
qid: Union[str, int], uid: str
) -> Union[str, bytes]:
return await draw_base_img(qid, uid, '收集')
async def draw_explora_img(
qid: Union[str, int], uid: str
) -> Union[str, bytes]:
return await draw_base_img(qid, uid, '探索')
async def get_base_data(uid: str) -> Union[str, Dict]:
# 获取Cookies
data_def = GetCookies()
retcode = await data_def.get_useable_cookies(uid)
if retcode:
return retcode
raw_data = data_def.raw_data
if data_def.uid:
uid = data_def.uid
# 获取数据
if raw_data:
raw_data = raw_data['data']
else:
return '数据为空~'
return raw_data
async def get_explore_data(
uid: str,
) -> Union[str, Tuple[Dict[str, float], Dict[str, str], str, str, str]]:
raw_data = await get_base_data(uid)
if isinstance(raw_data, str):
return raw_data
# 处理数据
data: Dict[str, int] = {
'获得角色数': raw_data['stats']['avatar_number'],
'风神瞳': raw_data['stats']['anemoculus_number'],
'岩神瞳': raw_data['stats']['geoculus_number'],
'雷神瞳': raw_data['stats']['electroculus_number'],
'草神瞳': raw_data['stats']['dendroculus_number'],
}
for i in raw_data['world_explorations']:
data[i['name']] = i['exploration_percentage']
percent_data = {}
value_data = {}
day: str = str(raw_data['stats']['active_day_number'])
me_percent = 0
world_percent = 0
for name in data:
# 百分比
p_str = f'{data[name]}'
if name in expmax_data:
percent = data[name] / expmax_data[name]
if name != '获得角色数':
me_percent += percent
value = f'{p_str} / {expmax_data[name]} | {_f(percent * 100)}'
else:
percent = data[name] / 1000
world_percent += percent
value = f'{_f(percent * 100)}'
percent_data[name] = percent
value_data[name] = value
me_percent = _f(me_percent * 100 / (len(expmax_data) - 1))
world_percent = _f(world_percent * 100 / (len(data) - len(expmax_data)))
return percent_data, value_data, day, me_percent, world_percent
async def get_collection_data(
uid: str,
) -> Union[str, Tuple[Dict[str, float], Dict[str, str], str, str, str]]:
raw_data = await get_base_data(uid)
if isinstance(raw_data, str):
return raw_data
raw_data = raw_data['stats']
# 处理数据
data: Dict[str, int] = {
'成就': raw_data['achievement_number'],
'普通的宝箱': raw_data['common_chest_number'],
'精致的宝箱': raw_data['exquisite_chest_number'],
'珍贵的宝箱': raw_data['precious_chest_number'],
'华丽的宝箱': raw_data['luxurious_chest_number'],
'奇馈宝箱': raw_data['magic_chest_number'],
'解锁传送点': raw_data['way_point_number'],
'解锁秘境': raw_data['domain_number'],
}
percent_data = {}
value_data = {}
left = 0
day: str = str(raw_data['active_day_number'])
all_percent = 0
for name in data:
# 百分比
percent = data[name] / max_data[name]
all_percent += percent
p_str = f'{data[name]} / {max_data[name]}'
value = f'{p_str} | {_f(percent * 100)}'
# 可获石头
left += award_data[name] * (max_data[name] - data[name])
percent_data[name] = percent
value_data[name] = value
all_percent = _f(all_percent * 100 / len(data))
return percent_data, value_data, day, all_percent, f'{left}'
async def draw_base_img(
qid: Union[str, int], uid: str, mode: Literal['探索', '收集'] = '收集'
) -> Union[str, bytes]:
# 获取数据
if mode == '收集':
data = await get_collection_data(uid)
else:
data = await get_explore_data(uid)
if isinstance(data, str):
return data
percent_data, value_data = data[0], data[1]
# 获取背景图片各项参数
_id = str(qid)
if _id.startswith('http'):
char_pic = await get_qq_avatar(avatar_url=_id)
else:
char_pic = await get_qq_avatar(qid=qid)
char_pic = await draw_pic_with_ring(char_pic, 264)
if mode == '收集':
title = Image.open(TEXT_PATH / 'collection_title.png')
else:
title = Image.open(TEXT_PATH / 'explora_title.png')
img = await get_color_bg(750, 600 + len(percent_data) * 115)
img.paste(title, (0, 0), title)
img.paste(char_pic, (241, 40), char_pic)
for index, name in enumerate(percent_data):
percent = percent_data[name]
value = value_data[name]
bar = await draw_bar(f'·{name}', percent, value)
img.paste(bar, (0, 600 + index * 115), bar)
# 头
img_draw = ImageDraw.Draw(img)
img_draw.text((378, 357), f'UID {uid}', first_color, gs_font_30, 'mm')
img_draw.text((137, 498), data[2], first_color, gs_font_40, 'mm')
img_draw.text((372, 498), data[3], first_color, gs_font_40, 'mm')
img_draw.text((607, 498), data[4], first_color, gs_font_40, 'mm')
res = await convert_img(img)
return res
def _f(value: float) -> str:
return '{:.2f}%'.format(value)

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,185 @@
from typing import Any, Tuple, Union
from nonebot.log import logger
from nonebot.matcher import Matcher
from nonebot import on_regex, on_command
from nonebot.permission import SUPERUSER
from nonebot.params import Depends, CommandArg, RegexGroup
from nonebot.adapters.onebot.v11 import (
Bot,
Message,
MessageSegment,
GroupMessageEvent,
PrivateMessageEvent,
)
from ..genshinuid_meta import register_menu
from .draw_config_card import draw_config_img
from ..utils.message.error_reply import UID_HINT
from ..utils.db_operation.db_operation import select_db
from ..utils.message.get_image_and_at import ImageAndAt
from .set_config import set_push_value, set_config_func
from ..utils.exception.handle_exception import handle_exception
open_and_close_switch = on_regex(
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
r'(gs)(开启|关闭)(.*)'
r'(\[CQ:at,qq=[0-9]+\])?( )?$'
)
push_config = on_regex(
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
r'(gs)(设置)([\u4e00-\u9fffa-zA-Z]*)([0-9]*)'
r'(\[CQ:at,qq=[0-9]+\])?( )?$'
)
config_card = on_command('gs配置')
@config_card.handle()
@handle_exception('发送配置表')
@register_menu(
'发送配置表',
'gs配置',
'查看插件当前配置项开关情况',
detail_des=(
'介绍:\n'
'查看插件当前配置项开关情况\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>gs配置</ft>'
),
)
async def send_config_card(matcher: Matcher, args: Message = CommandArg()):
if args:
await matcher.finish()
logger.info('开始执行[gs配置]')
im = await draw_config_img()
if isinstance(im, str):
await matcher.finish(im)
elif isinstance(im, bytes):
await matcher.finish(MessageSegment.image(im))
else:
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
@push_config.handle()
@handle_exception('设置推送服务')
@register_menu(
'设置推送阈值',
'gs设置xx(@某人)',
'设置自己或指定人的推送服务阈值',
detail_des=(
'介绍:\n'
'设置某人的推送服务阈值\n'
'超级用户可以设置他人的推送服务阈值\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>gs设置</ft>'
'<ft color=(0,148,200)>[服务名称][阈值]</ft>'
'<ft color=(125,125,125)>(@某人)</ft>\n'
' \n'
'示例:\n'
'- <ft color=(238,120,0)>gs设置推送140</ft>'
),
)
async def send_config_msg(
bot: Bot,
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
args: Tuple[Any, ...] = RegexGroup(),
custom: ImageAndAt = Depends(),
):
logger.info('开始执行[设置阈值信息]')
logger.info('[设置阈值信息]参数: {}'.format(args))
qid = event.user_id
at = custom.get_first_at()
if at and await SUPERUSER(bot, event):
qid = at
elif at and at != qid:
await matcher.finish('你没有权限操作别人的状态噢~', at_sender=True)
logger.info('[设置阈值信息]qid: {}'.format(qid))
try:
uid = await select_db(qid, mode='uid')
except TypeError:
await matcher.finish(UID_HINT)
func = args[4].replace('阈值', '')
if args[5]:
try:
value = int(args[5])
except ValueError:
await matcher.finish('请输入数字哦~', at_sender=True)
else:
await matcher.finish('请输入正确的阈值数字!', at_sender=True)
logger.info('[设置阈值信息]func: {}, value: {}'.format(func, value))
im = await set_push_value(func, str(uid), value)
await matcher.finish(im, at_sender=True)
# 开启 自动签到 和 推送树脂提醒 功能
@open_and_close_switch.handle()
@register_menu(
'开关推送服务',
'gs{开启|关闭}xx(@某人)',
'开关自己或指定人的推送服务状态',
detail_des=(
'介绍:\n'
'设置某人的推送服务开关状态\n'
'超级用户可以设置他人的推送服务状态\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>gs{开启|关闭}</ft>'
'<ft color=(0,148,200)>[服务名称]</ft>'
'<ft color=(125,125,125)>(@某人)</ft>\n'
' \n'
'示例:\n'
'- <ft color=(238,120,0)>gs开启推送</ft>'
),
)
async def open_switch_func(
bot: Bot,
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
args: Tuple[Any, ...] = RegexGroup(),
at: ImageAndAt = Depends(),
):
qid = event.user_id
atqq = at.get_first_at() if at else None
config_name = args[4]
logger.info(f'[{qid}]尝试[{args[3]}]了[{config_name}]功能')
if args[3] == '开启':
query = 'OPEN'
gid = (
event.get_session_id().split('_')[1]
if len(event.get_session_id().split('_')) == 3
else 'on'
)
else:
query = 'CLOSED'
gid = 'off'
is_admin = await SUPERUSER(bot, event)
if atqq:
if is_admin:
qid = atqq
elif atqq != qid:
await matcher.finish('你没有权限操作别人的状态噢~', at_sender=True)
uid = await select_db(qid, mode='uid')
if uid is None or not isinstance(uid, str) or not uid.isdecimal():
await matcher.finish(UID_HINT)
im = await set_config_func(
config_name=config_name,
uid=uid,
qid=str(qid),
option=gid,
query=query,
is_admin=is_admin,
)
await matcher.finish(im, at_sender=True)

View File

@ -0,0 +1,86 @@
import json
from typing import Dict, List, Union, Literal, overload
from ..utils.download_resource.RESOURCE_PATH import CONFIG_PATH
CONIFG_DEFAULT = {
'proxy': '',
'_pass_API': '',
'random_pic_API': 'https://genshin-res.cherishmoon.fun/img?name=',
'Ann_Groups': [],
'Ann_Ids': [],
}
STR_CONFIG = Literal['proxy', '_pass_API', 'random_pic_API']
LIST_CONFIG = Literal['Ann_Groups', 'Ann_Ids']
class StringConfig:
def __init__(self) -> None:
if not CONFIG_PATH.exists():
with open(CONFIG_PATH, 'w', encoding='UTF-8') as file:
json.dump(CONIFG_DEFAULT, file, ensure_ascii=False)
self.update_config()
def write_config(self):
with open(CONFIG_PATH, 'w', encoding='UTF-8') as file:
json.dump(self.config, file, ensure_ascii=False)
def update_config(self):
# 打开config.json
with open(CONFIG_PATH, 'r', encoding='UTF-8') as f:
self.config: Dict = json.load(f)
# 对没有的值,添加默认值
for key in CONIFG_DEFAULT:
if key not in self.config:
self.config[key] = CONIFG_DEFAULT[key]
# 对默认值没有的值,直接删除
delete_keys = []
for key in self.config:
if key not in CONIFG_DEFAULT:
delete_keys.append(key)
for key in delete_keys:
self.config.pop(key)
# 重新写回
self.write_config()
@overload
def get_config(self, key: STR_CONFIG) -> str:
...
@overload
def get_config(self, key: LIST_CONFIG) -> List:
...
def get_config(self, key: str) -> Union[str, List]:
if key in self.config:
return self.config[key]
elif key in CONIFG_DEFAULT:
self.update_config()
return self.config[key]
else:
return []
@overload
def set_config(self, key: STR_CONFIG, value: str) -> bool:
...
@overload
def set_config(self, key: LIST_CONFIG, value: List) -> bool:
...
def set_config(self, key: str, value: Union[str, List]) -> bool:
if key in CONIFG_DEFAULT:
# 设置值
self.config[key] = value
# 重新写回
self.write_config()
return True
else:
return False
string_config = StringConfig()

View File

@ -0,0 +1,100 @@
import asyncio
from pathlib import Path
from typing import Union
from nonebot.log import logger
from PIL import Image, ImageDraw
from .set_config import SWITCH_MAP
from ..utils.download_resource.RESOURCE_PATH import TEXT2D_PATH
from ..utils.draw_image_tools.send_image_tool import convert_img
from ..utils.draw_image_tools.draw_image_tool import CustomizeImage
from ..utils.genshin_fonts.genshin_fonts import genshin_font_origin
from ..utils.db_operation.db_operation import (
get_all_uid,
config_check,
get_all_cookie,
get_all_stoken,
)
TEXT_PATH = Path(__file__).parent / 'texture2d'
config_title = Image.open(TEXT_PATH / 'config_title.png')
config_on = Image.open(TEXT_PATH / 'config_on.png')
config_off = Image.open(TEXT_PATH / 'config_off.png')
gs_font_36 = genshin_font_origin(36)
gs_font_40 = genshin_font_origin(40)
gs_font_24 = genshin_font_origin(24)
first_color = (20, 20, 20)
second_color = (57, 57, 57)
DETAIL_MAP = {
'米游币推送': '开启后会私聊每个用户当前米游币任务完成情况',
'简洁签到报告': '开启后可以大大减少每日签到报告字数 ',
'私聊报告': '关闭后将不再给主人推送当天米游币任务完成情况',
'随机图': '开启后[查询心海]等命令展示图将替换为随机图片',
'定时签到': '开启后每晚00:30将开始自动签到任务',
'定时米游币': '开启后每晚01:16将开始自动米游币任务',
'催命模式': '开启后当达到推送阈值将会一直推送',
'网页控制台': '开启后重启生效,地址位于Bot所处端口下/genshinuid',
'重启使用Poetry': '将会以Poetry方式重启',
'旧面板': '会稍微增加面板访问速度,但会损失很多功能',
'多彩面板': '面板颜色不按照属性来渲染,而按照自定义颜色',
'失效项': '可能有一定危险性',
'无效项': '可能有一定危险性',
}
async def draw_config_img() -> Union[bytes, str]:
# 获取背景图片各项参数
based_w = 850
based_h = 850 + 155 * (len(SWITCH_MAP) - 3)
CI_img = CustomizeImage('', based_w, based_h)
img = CI_img.bg_img
color = CI_img.bg_color
color_mask = Image.new('RGBA', (based_w, based_h), color)
config_mask = Image.open(TEXT2D_PATH / 'mask.png').resize(
(based_w, based_h)
)
img.paste(color_mask, (0, 0), config_mask)
img.paste(config_title, (0, 0), config_title)
img_draw = ImageDraw.Draw(img)
# 获取数据
uid_list = await get_all_uid()
cookie_list = await get_all_cookie()
stoken_list = await get_all_stoken()
uid_num = len(uid_list)
cookie_num = len(cookie_list)
stoken_num = len(stoken_list)
img_draw.text((210, 600), str(uid_num), first_color, gs_font_40, 'mm')
img_draw.text((431, 600), str(cookie_num), first_color, gs_font_40, 'mm')
img_draw.text((651, 600), str(stoken_num), first_color, gs_font_40, 'mm')
tasks = []
for index, name in enumerate(DETAIL_MAP):
tasks.append(_draw_config_line(img, name, index))
await asyncio.gather(*tasks)
res = await convert_img(img)
logger.info('[查询配置信息]绘图已完成,等待发送!')
return res
async def _draw_config_line(img: Image.Image, name: str, index: int):
detail = DETAIL_MAP[name]
switch_name = SWITCH_MAP[name]
config_line = Image.open(TEXT_PATH / 'config_line.png')
config_line_draw = ImageDraw.Draw(config_line)
if name.startswith('定时'):
name += '(全部)'
config_line_draw.text((52, 46), name, first_color, gs_font_36, 'lm')
config_line_draw.text((52, 80), detail, second_color, gs_font_24, 'lm')
if await config_check(switch_name):
config_line.paste(config_on, (613, 21), config_on)
else:
config_line.paste(config_off, (613, 21), config_off)
img.paste(config_line, (26, 850 + index * 155), config_line)

View File

@ -0,0 +1,137 @@
from typing import Optional
from nonebot.log import logger
from ..utils.message.error_reply import CK_HINT
from ..utils.db_operation.db_operation import (
open_push,
config_check,
update_push_value,
update_push_status,
)
SWITCH_MAP = {
'自动签到': 'StatusB',
'推送': 'StatusA',
'自动米游币': 'StatusC',
'米游币推送': 'MhyBBSCoinReport',
'简洁签到报告': 'SignReportSimple',
'私聊报告': 'PrivateReport',
'随机图': 'RandomPic',
'定时签到': 'SchedSignin',
'定时米游币': 'SchedMhyBBSCoin',
'催命模式': 'CrazyNotice',
'网页控制台': 'OpenWeb',
'重启使用Poetry': 'UsePoetry',
'旧面板': 'OldPanle',
'多彩面板': 'ColorBG',
'失效项': 'CaptchaPass',
'无效项': 'MhyPass',
}
PUSH_MAP = {
'宝钱': 'Coin',
'体力': 'Resin',
'派遣': 'Go',
'质变仪': 'Transform',
}
HINT_MAP = {
'米游币推送': '\n该选项不会影响到实际米游币获取\n*【管理员命令全局生效】',
'简洁签到报告': '\n该选项将减少每日群内签到报告的字数\n*【管理员命令全局生效】',
'网页控制台': '\n初始账admin,密admin,请务必及时修改账密!',
}
SWITCH_STR = ''
PUSH_STR = ''
for switch in SWITCH_MAP:
SWITCH_STR += '\n' + switch
for push in PUSH_MAP:
PUSH_STR += '\n' + push
async def set_push_value(func: str, uid: str, value: int):
if func in PUSH_MAP:
status = PUSH_MAP[func]
else:
return f'该配置项不存在!\n当前推送配置:{PUSH_STR}'
logger.info('[设置推送阈值]func: {}, value: {}'.format(status, value))
if await update_push_value(int(uid), status, int(value)):
return f'设置成功!\n当前{func}推送阈值:{value}'
else:
return '设置失败!\n请检查参数是否正确!'
async def set_config_func(
config_name: str = '',
uid: str = '0',
qid: Optional[str] = None,
option: str = '0',
query: Optional[str] = None,
is_admin: bool = False,
):
"""
:说明:
设置配置项
如果config_name为私人服务, 例如['自动签到', '推送', '自动米游币'],
则需要传入uid, qid和option
---
如果config_name为群服务, 例如['米游币推送', '简洁签到报告'],
则需要传入query即可
:参数:
* config_name (str): 设置的参数名。
* uid (str): 用户id。
* qid (str): 群id。
* option (str): 'off'(关闭), 'on'(开启), '群号'(开启至群聊推送)。
* query (str): 'CLOSED', 'OPEN'
* is_admin (bool): 是否为管理员。
:返回:
* im: 设置消息。
"""
# 这里将传入的中文config_name转换为英文status
if config_name in SWITCH_MAP:
status = SWITCH_MAP[config_name]
elif config_name in PUSH_MAP:
status = PUSH_MAP[config_name]
else:
return f'该配置项不存在!\n当前配置项:{SWITCH_STR}\n当前推送配置:{PUSH_STR}'
# 这里判断是否是私人服务
if config_name in ['自动签到', '推送', '自动米游币']:
logger.info(
f'uid: {uid}, qid: {qid}, option: {option}, config_name: {status}'
)
# 执行设置
if await open_push(uid, qid, option, status):
if option == 'on':
succeed_msg = '开启至私聊消息!'
elif option == 'off':
succeed_msg = '关闭!'
else:
succeed_msg = f'开启至{option}'
im = f'{config_name}{succeed_msg}'
else:
im = '设置失败, 可能是未绑定Coookie或者Cookie已过期。\n' + CK_HINT
elif config_name in PUSH_MAP:
logger.info('[设置推送信息]func: {}'.format(config_name))
if await update_push_status(int(uid), status, option):
return f'设置{config_name}成功, 状态为{option}!\n'
else:
return f'设置{config_name}失败, '
# 这里判断是否是群服务
else:
if is_admin:
logger.info(f'config_name:{status},query:{query}')
# 执行设置
if query:
if await config_check(status, query):
im = '成功设置{}{}'.format(config_name, query)
if config_name in HINT_MAP:
im += HINT_MAP[config_name]
else:
im = '设置失败!'
else:
im = '未传入参数query!'
else:
im = '只有管理员才能设置群服务。'
return im

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

View File

@ -0,0 +1,15 @@
from nonebot import on_command
from nonebot.matcher import Matcher
from nonebot.permission import SUPERUSER
from .export_data import export_v3
from ..utils.nonebot2.rule import FullCommand
export_v3_data = on_command('导出v3数据', permission=SUPERUSER, rule=FullCommand())
@export_v3_data.handle()
async def send_export_msg(matcher: Matcher):
await matcher.send('开始导出数据..可能需要一定时间!')
await export_v3()
await matcher.send('导出数据成功!')

View File

@ -0,0 +1,53 @@
import re
import json
from ..utils.download_resource.RESOURCE_PATH import MAIN_PATH
from ..utils.db_operation.db_operation import get_all_bind, get_user_bind_data
DATA_PATH = MAIN_PATH / 'v3_data.json'
BOT_ID = 'onebot'
RECOGNIZE_SERVER = {
'1': 'cn_gf01',
'2': 'cn_gf01',
'5': 'cn_qd01',
'6': 'os_usa',
'7': 'os_euro',
'8': 'os_asia',
'9': 'os_cht',
}
async def export_v3():
result = {'bot_id': BOT_ID, 'bind': [], 'user': []}
bind_list = await get_all_bind()
for bind in bind_list:
bind_data = {}
bind_data['bot_id'] = BOT_ID
bind_data['user_id'] = str(bind['USERID'])
bind_data['uid'] = str(bind['UID']) # 导出bind数据
bind_data['mys_id'] = str(bind['MYSID'])
if bind_data not in result['bind']:
result['bind'].append(bind_data)
uid_list = bind['UID'].split('_')
for uid in uid_list:
new_data = {}
data = await get_user_bind_data(uid)
if not data:
continue
new_data['bot_id'] = BOT_ID
new_data['user_id'] = data['QID']
new_data['region'] = RECOGNIZE_SERVER[uid[0]]
new_data['stoken'] = data['Stoken']
new_data['cookie'] = data['Cookies']
account_id = re.search(r'account_id=(\d*)', new_data['cookie'])
assert account_id is not None
new_data['mys_id'] = str(account_id.group(1))
new_data['uid'] = uid
new_data['push_switch'] = data['StatusA']
new_data['sign_switch'] = data['StatusB']
new_data['bbs_switch'] = data['StatusC']
new_data['status'] = data['Extra']
if new_data not in result['user']:
result['user'].append(new_data)
with open(DATA_PATH, 'w', encoding='UTF-8') as file:
json.dump(result, file, ensure_ascii=False, indent=2)

View File

@ -0,0 +1,329 @@
import re
import random
import asyncio
from typing import Tuple, Union
from nonebot import on_command
from nonebot.log import logger
from nonebot.matcher import Matcher
from nonebot.permission import SUPERUSER
from nonebot.params import Depends, CommandArg
from nonebot_plugin_apscheduler import scheduler
from nonebot.adapters.onebot.v11 import (
Bot,
Message,
MessageSegment,
GroupMessageEvent,
PrivateMessageEvent,
)
from ..config import priority
from .get_enka_img import draw_enka_img
from ..genshinuid_meta import register_menu
from ..utils.nonebot2.rule import FullCommand
from .draw_char_rank import draw_cahrcard_list
from ..utils.message.error_reply import UID_HINT
from ..utils.enka_api.get_enka_data import switch_api
from ..utils.enka_api.enka_to_card import enka_to_card
from ..utils.enka_api.enka_to_data import enka_to_data
from ..utils.message.get_image_and_at import ImageAndAt
from ..utils.download_resource.RESOURCE_PATH import TEMP_PATH
from ..utils.exception.handle_exception import handle_exception
from ..utils.db_operation.db_operation import select_db, get_all_uid
refresh = on_command('强制刷新')
original_pic = on_command('原图', rule=FullCommand())
change_api = on_command('切换api')
get_charcard_list = on_command('毕业度统计')
get_char_info = on_command(
'查询',
priority=priority,
)
AUTO_REFRESH = False
refresh_scheduler = scheduler
@change_api.handle()
@handle_exception('切换api')
@register_menu(
'切换API',
'切换api',
'切换获取角色面板时使用的API',
detail_des=(
'介绍:\n'
'切换获取角色面板时使用的Enka Network API\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>切换api</ft>'
),
)
async def send_change_api_info(
bot: Bot,
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
args: Message = CommandArg(),
):
if args or not await SUPERUSER(bot, event):
return
im = await switch_api()
await matcher.finish(im)
@original_pic.handle()
@handle_exception('原图')
@register_menu(
'查看面板原图',
'原图',
'查看角色面板中原随机图',
trigger_method='回复+指令',
detail_des=(
'介绍:\n'
'查看开启随机图功能时角色面板中角色位置的原图,需要回复要查看原图的面板图片消息\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>原图</ft>'
),
)
async def send_original_pic(
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
):
if event.reply:
msg_id = event.reply.message_id
path = TEMP_PATH / f'{msg_id}.jpg'
if path.exists():
logger.info('[原图]访问图片: {}'.format(path))
with open(path, 'rb') as f:
await matcher.finish(MessageSegment.image(f.read()))
@get_char_info.handle()
@handle_exception('查询角色面板')
@register_menu(
'查询角色面板',
'查询(@某人)角色名',
'查询你的或者指定人的已缓存展柜角色的面板',
detail_des=(
'介绍:\n'
'可以用来查看你的或者指定人的已缓存展柜角色的面板\n'
'支持部分角色别名\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>{查询</ft>'
'<ft color=(125,125,125)>(@某人)</ft>'
'<ft color=(238,120,0)>|uid</ft><ft color=(0,148,200)>xx</ft>'
'<ft color=(238,120,0)>|mys</ft><ft color=(0,148,200)>xx</ft>'
'<ft color=(238,120,0)>}</ft>'
'<ft color=(0,148,200)>[角色名]</ft>\n'
'后面可以跟 '
'<ft color=(238,120,0)>换</ft>'
'<ft color=(125,125,125)>(精{一|二|三|四|五})</ft>'
'<ft color=(0,148,200)>[武器名]</ft> '
'来更换展示的武器\n'
'可以跟 '
'<ft color=(125,125,125)>(成长)</ft><ft color=(238,120,0)>曲线</ft> '
'来查询该角色成长曲线\n'
' \n'
'示例:\n'
'- <ft color=(238,120,0)>查询宵宫</ft>\n'
'- <ft color=(238,120,0)>查询绫华换精五雾切</ft>\n'
'- <ft color=(238,120,0)>查询一斗成长曲线</ft>\n'
'- <ft color=(238,120,0)>查询</ft><ft color=(0,123,67)>@无疑Wuyi</ft>'
' <ft color=(238,120,0)>公子</ft>'
),
)
@register_menu(
'查询展柜角色',
'查询展柜角色',
'查询插件已缓存的展柜角色列表',
detail_des=(
'介绍:\n'
'查询插件当前已缓存的展柜角色列表\n'
' \n'
'指令:\n'
'- <ft color=(238,120,0)>查询展柜角色</ft>'
),
)
async def send_char_info(
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
args: Message = CommandArg(),
custom: ImageAndAt = Depends(),
):
raw_mes = args.extract_plain_text().strip()
name = ''.join(re.findall('[\u4e00-\u9fa5]', raw_mes))
if not name:
return
logger.info('开始执行[查询角色面板]')
at = custom.get_first_at()
img = custom.get_first_image()
if at:
qid = at
else:
qid = event.user_id
logger.info('[查询角色面板]QQ: {}'.format(qid))
# 获取uid
uid = re.findall(r'\d+', raw_mes)
if uid:
uid = uid[0]
else:
uid = await select_db(qid, mode='uid')
uid = str(uid)
logger.info('[查询角色面板]uid: {}'.format(uid))
if '未找到绑定的UID' in uid:
await matcher.finish(UID_HINT)
im = await draw_enka_img(raw_mes, uid, img)
if isinstance(im, str):
await matcher.finish(im)
elif isinstance(im, Tuple):
req = await matcher.send(MessageSegment.image(im[0]))
msg_id = req['message_id']
if im[1]:
with open(TEMP_PATH / f'{msg_id}.jpg', 'wb') as f:
f.write(im[1])
else:
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
async def refresh_char_data():
"""
:说明:
刷新全部绑定uid的角色展柜面板进入本地缓存。
"""
uid_list = await get_all_uid()
t = 0
for uid in uid_list:
try:
im = await enka_to_data(uid)
logger.info(im)
t += 1
await asyncio.sleep(35 + random.randint(1, 20))
except Exception:
logger.exception(f'{uid}刷新失败!')
logger.error(f'{uid}刷新失败!本次自动刷新结束!')
return f'执行失败从{uid}!共刷新{str(t)}个角色!'
else:
logger.info(f'共刷新{str(t)}个角色!')
return f'执行成功!共刷新{str(t)}个角色!'
@refresh_scheduler.scheduled_job('cron', hour='4')
async def daily_refresh_charData():
global AUTO_REFRESH
if AUTO_REFRESH:
await refresh_char_data()
@refresh.handle()
@handle_exception('强制刷新')
@register_menu(
'刷新展柜缓存',
'强制刷新',
'强制刷新你的或者指定人缓存的角色展柜数据',
detail_des=(
'指令:'
'<ft color=(238,120,0)>强制刷新</ft>'
'<ft color=(125,125,125)>(uid/全部数据)</ft>\n'
' \n'
'用于强制刷新你的或者指定人缓存的角色展柜数据\n'
'当刷新全部数据时需要机器人管理员权限\n'
' \n'
'示例:\n'
'<ft color=(238,120,0)>强制刷新</ft>\n'
'<ft color=(238,120,0)>强制刷新123456789</ft>\n'
'<ft color=(238,120,0)>强制刷新全部数据</ft>'
),
)
async def send_card_info(
bot: Bot,
matcher: Matcher,
event: Union[GroupMessageEvent, PrivateMessageEvent],
args: Message = CommandArg(),
custom: ImageAndAt = Depends(),
):
message = args.extract_plain_text().strip().replace(' ', '')
uid = re.findall(r'\d+', message) # str
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
qid = event.user_id
at = custom.get_first_at()
if at:
qid = at
if len(uid) >= 1:
uid = uid[0]
else:
if m == '全部数据':
if await SUPERUSER(bot, event):
await matcher.send('开始刷新全部数据,这可能需要相当长的一段时间!!')
im = await refresh_char_data()
await matcher.finish(str(im))
else:
return
else:
uid = await select_db(qid, mode='uid')
uid = str(uid)
if not uid:
await matcher.finish(UID_HINT)
im = await enka_to_card(uid)
if isinstance(im, str):
await matcher.finish(im)
elif isinstance(im, bytes):
await matcher.finish(MessageSegment.image(im))
else:
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
@get_charcard_list.handle()
@handle_exception('毕业度统计')
@register_menu(
'毕业度统计',
'毕业度统计',
'查看你或指定人已缓存的展柜角色毕业度',
detail_des=(
'指令:'
'<ft color=(238,120,0)>毕业度统计</ft>'
'<ft color=(125,125,125)>(@某人)</ft>\n'
' \n'
'可以查看你或指定人已缓存的所有展柜角色毕业度\n'
' \n'
'示例:\n'
'<ft color=(238,120,0)>毕业度统计</ft>\n'
'<ft color=(238,120,0)>毕业度统计</ft><ft color=(0,148,200)>@无疑Wuyi</ft>'
),
)
async def send_charcard_list(
event: Union[GroupMessageEvent, PrivateMessageEvent],
matcher: Matcher,
args: Message = CommandArg(),
custom: ImageAndAt = Depends(),
):
raw_mes = args.extract_plain_text().strip()
qid = event.user_id
at = custom.get_first_at()
if at:
qid = at
# 获取uid
uid = re.findall(r'\d+', raw_mes)
if uid:
uid = uid[0]
else:
uid = await select_db(qid, mode='uid')
uid = str(uid)
im = await draw_cahrcard_list(str(uid), qid)
logger.info(f'UID{uid}获取角色数据成功!')
if isinstance(im, bytes):
await matcher.finish(MessageSegment.image(im))
else:
await matcher.finish(str(im))

View File

@ -0,0 +1,58 @@
{
"神里绫华": {"Y": "冰伤收益", "B": "攻击收益", "J": "暴击收益"},
"琴": {"W": "治疗加成", "X": "攻击对治疗收益"},
"丽莎": {"B": "攻击/雷伤收益", "D": "暴击收益"},
"芭芭拉": {"Q": "治疗加成", "R": "生命收益"},
"凯亚": {"B": "攻击/冰伤收益", "D": "暴击收益"},
"迪卢克": {"O": "精通收益", "B": "攻击/火伤收益", "K": "暴击收益"},
"雷泽": {"AE": "物伤收益", "B": "攻击收益", "D": "暴击收益"},
"安柏": {"P": "精通收益", "B": "火伤收益", "D": "暴击收益", "L": "攻击收益"},
"温迪": {},
"香菱": {"N": "精通收益", "B": "攻击/火伤收益", "D": "暴击收益"},
"北斗": {"L": "雷伤收益", "B": "攻击收益", "D": "暴击收益"},
"行秋": {"E": "精通收益", "B": "水伤收益", "L": "攻击收益", "D": "暴击收益"},
"魈": {"AK": "风伤收益", "B": "攻击收益", "K": "暴击收益"},
"凝光": {"L": "岩伤收益", "B": "攻击收益", "D": "暴击收益"},
"可莉": {"E": "精通收益", "B": "攻击收益", "M": "火伤收益", "D": "暴击收益"},
"钟离": {"M": "岩伤收益", "AB": "生命收益", "D": "暴击收益"},
"菲谢尔": {"C": "物伤收益", "L": "攻击收益", "B": "雷伤收益", "D": "暴击收益"},
"班尼特": {"E": "精通收益", "B": "攻击收益", "D": "暴击收益"},
"达达利亚": {"E": "精通收益", "M": "水伤收益", "B": "攻击收益", "D": "暴击收益"},
"诺艾尔": {"B": "岩伤收益", "AC": "防御收益", "D": "暴击收益"},
"七七": {"W": "治疗加成", "Z": "攻击对治疗收益"},
"重云": {"E": "精通收益", "B": "冰伤收益", "L": "攻击收益", "D": "暴击收益"},
"甘雨": {"E": "精通收益", "B": "攻击/冰伤收益", "J": "暴击收益"},
"阿贝多": {"M": "岩伤收益", "C": "防御收益", "D": "暴击收益"},
"迪奥娜": {"Q": "治疗加成", "AA": "生命收益"},
"莫娜": {"E": "精通收益", "S": "水伤收益", "B": "攻击收益", "D": "暴击收益"},
"刻晴": {"C": "物伤收益", "B": "攻击/雷伤收益", "J": "暴击收益"},
"砂糖": {},
"辛焱": {"C": "物伤收益", "L": "攻击收益", "D": "暴击收益", "B": "火伤收益"},
"罗莎莉亚": {"L": "攻击收益", "D": "暴击收益", "B": "冰伤收益"},
"胡桃": {"I": "精通收益", "B": "火伤收益", "H": "生命收益", "J": "暴击收益"},
"枫原万叶": {},
"烟绯": {"E": "精通收益", "B": "攻击收益", "L": "火伤收益", "D": "暴击收益"},
"宵宫": {"O": "精通收益", "B": "攻击/火伤收益", "K": "暴击收益"},
"托马": {},
"优菈": {"C": "物伤收益", "B": "攻击收益", "J": "暴击收益"},
"雷电将军": {"AG": "攻击收益", "AF": "雷伤收益", "D": "暴击收益"},
"早柚": {"Q": "治疗加成", "AL": "攻击对治疗收益", "AM": "精通对治疗收益"},
"珊瑚宫心海": {"M": "水伤收益", "T": "生命收益"},
"五郎": {"L": "岩伤收益", "C": "防御收益", "D": "暴击收益"},
"九条裟罗": {"L": "攻击收益", "B": "雷伤收益", "D": "暴击收益"},
"荒泷一斗": {"B": "岩伤收益", "AD": "防御收益", "K": "暴击收益"},
"八重神子": {"B": "攻击/雷伤收益", "K": "暴击收益"},
"鹿野院平藏": {"L": "风伤收益", "B": "攻击收益", "D": "暴击收益"},
"夜兰": {"B": "水伤收益", "U": "生命收益", "K": "暴击收益"},
"埃洛伊": {"B": "攻击收益", "M": "冰伤收益", "D": "暴击收益"},
"申鹤": {"B": "冰伤收益", "M": "攻击收益", "D": "暴击收益"},
"云堇": {"B": "岩伤收益", "C": "防御收益", "D": "暴击收益"},
"久岐忍": {"Q": "治疗加成", "AH": "生命对治疗收益", "AI": "精通对治疗收益"},
"神里绫人": {"B": "水伤收益", "V": "4浪闪攻击收益", "J": "暴击收益"},
"柯莱": {},
"多莉": {"Q": "治疗加成", "AJ": "生命对治疗收益"},
"提纳里": {},
"妮露": {},
"赛诺": {"B": "雷伤收益", "L": "攻击收益", "J": "暴击收益"},
"坎蒂丝": {"B": "水伤收益", "L": "生命收益", "D": "暴击收益"}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,220 @@
import json
from pathlib import Path
from typing import List, Tuple
from PIL import Image, ImageDraw
from ...utils.genshin_fonts.genshin_fonts import genshin_font_origin
DATA_PATH = Path(__file__).parent
TEXT_PATH = DATA_PATH / 'texture2D'
WEIGHT_MAP = {
'暴击率': 1,
'治疗加成': 1.15,
'百分比攻击力': 1.5,
'百分比血量': 1.5,
'元素伤害加成': 1.5,
'元素充能效率': 1.67,
'百分比防御力': 1.875,
'物理伤害加成': 1.875,
'暴击伤害': 2,
'元素精通': 6,
}
COLOR_MAP = {
'攻击': '#f19b60',
'精通': '#4dbe6b',
'暴击': '#5dbbee',
'物伤': '#ffffff',
'': '#a1252a',
'生命': '#67c750',
'防御': '#9999de',
'治疗': '#f9deb3',
'充能': '#ff5858',
}
# 引入曲线Map
with open(DATA_PATH / 'char_curve.json', 'r', encoding='UTF-8') as f:
CHAR_CURVE = json.load(f)
# 引入曲线Map
with open(DATA_PATH / 'curve.json', 'r', encoding='UTF-8') as f:
CURVE = json.load(f)
async def get_weight_temp(prop: dict, attr: str) -> List[float]:
weight = []
if '攻击' in attr:
weight.append(
(prop['atk_green'] / prop['baseAtk']) * 100 / WEIGHT_MAP['百分比攻击力']
)
elif '生命' in attr:
weight.append(
(prop['hp_green'] / prop['baseHp']) * 100 / WEIGHT_MAP['百分比血量']
)
elif '防御' in attr:
weight.append(
(prop['def_green'] / prop['baseDef']) * 100 / WEIGHT_MAP['百分比防御力']
)
elif '精通' in attr:
weight.append(prop['elementalMastery'] / WEIGHT_MAP['元素精通'])
elif '充能' in attr:
weight.append(prop['energyRecharge'] * 100 / WEIGHT_MAP['元素充能效率'])
elif '物伤' in attr:
weight.append(prop['physicalDmgBonus'] * 100 / WEIGHT_MAP['物理伤害加成'])
elif '' in attr:
weight.append(prop['dmgBonus'] * 100 / WEIGHT_MAP['元素伤害加成'])
elif '治疗' in attr:
weight.append(prop['healBonus'] * 100 / WEIGHT_MAP['治疗加成'])
elif '暴击' in attr:
weight.append(prop['critRate'] * 100 / WEIGHT_MAP['暴击率'])
weight.append(prop['critDmg'] * 100 / WEIGHT_MAP['暴击伤害'])
return weight
async def get_weight(prop: dict, attr: str) -> List[float]:
weight = []
if '/' in attr:
attr_list = attr.split('/')
else:
attr_list = [attr]
for i in attr_list:
weight.extend(await get_weight_temp(prop, i))
return weight
BLUE = "#0000ff"
lu_point = (23, 45)
rd_point = (927, 495)
X_D = rd_point[0] - lu_point[0]
Y_D = rd_point[1] - lu_point[1]
gs_font_22 = genshin_font_origin(22)
frame_img = Image.open(TEXT_PATH / 'frame.png')
point_img = Image.open(TEXT_PATH / 'point.png')
async def draw_char_curve_data(
char_name: str, raw_data: dict
) -> Tuple[Image.Image, int]:
# 如果曲线列表里不存在该角色,则返回空白图片
if char_name not in CHAR_CURVE or CHAR_CURVE[char_name] == {}:
return Image.new('RGBA', (950, 1)), 0
# 获得面板属性
if 'avatarFightProp' in raw_data:
fight_prop = raw_data['avatarFightProp']
else:
fight_prop = raw_data
fight_prop['atk_green'] = fight_prop['atk'] - fight_prop['baseAtk']
fight_prop['def_green'] = fight_prop['def'] - fight_prop['baseDef']
fight_prop['hp_green'] = fight_prop['hp'] - fight_prop['baseHp']
img = Image.open(TEXT_PATH / 'curve_bg.png')
img_draw = ImageDraw.Draw(img)
# 初始化X_MAX和Y_MAX值
X_MAX = 0
Y_MAX = 0
wight_point_dict: dict = {}
line_points_dict: dict = {}
wight_temp_dict: dict = {}
# 遍历曲线列表,根据函数获得权重
for col in CHAR_CURVE[char_name]:
wight_temp = await get_weight(fight_prop, CHAR_CURVE[char_name][col])
wight_temp_dict[CHAR_CURVE[char_name][col]] = wight_temp
# 对单个属性的权重列表进行遍历
for i in wight_temp:
# 确定X_MAX值
if i >= X_MAX:
X_MAX = i
# 确定Y_MAX值
for j in CURVE[col]:
if j >= Y_MAX:
Y_MAX = j
# 增加Y_MAX和X_MAX的值
X_MAX = X_MAX + 15
Y_MAX = Y_MAX + 0.002
# 遍历曲线列表,COL为列名,这一步拿到所有曲线的点,和所有权重的点
for col_index, col in enumerate(CHAR_CURVE[char_name]):
line_points = []
# 确定颜色
for m in COLOR_MAP:
if m in CHAR_CURVE[char_name][col]:
color = COLOR_MAP[m]
break
else:
color = '#ffffff'
for index, i in enumerate(CURVE[col]):
if index >= X_MAX:
break
x, y = (X_D / X_MAX) * index + lu_point[0], (
Y_D - (Y_D / Y_MAX) * i
) + lu_point[1]
line_points.append((x, y))
line_points_dict[color] = line_points
for wight in wight_temp_dict[CHAR_CURVE[char_name][col]]:
w_x = (wight / X_MAX) * X_D + lu_point[0]
w_y = line_points[int(wight)][1]
if CHAR_CURVE[char_name][col] not in wight_point_dict:
wight_point_dict[CHAR_CURVE[char_name][col]] = {
'color': color,
'point': [(w_x, w_y)],
}
else:
wight_point_dict[CHAR_CURVE[char_name][col]]['point'].append(
(w_x, w_y)
)
# 绘制右上角方块和文字
img_draw.rectangle(
((710, 65 + col_index * 30), (750, 85 + col_index * 30)),
fill=color,
)
img_draw.text(
(762, 75 + col_index * 30),
f'{CHAR_CURVE[char_name][col]}',
color,
gs_font_22,
'lm',
)
# 根据素材画曲线
for c in line_points_dict:
img_draw.line(line_points_dict[c], width=6, fill=c, joint='curve')
for attr in wight_point_dict:
attr_str = attr.replace('收益', '')
if attr_str == '暴击':
attr_list = ['暴击', '爆伤']
else:
attr_list = attr_str.split('/')
for index, point in enumerate(wight_point_dict[attr]['point']):
img_draw.text(
(point[0], 512),
f'{int((point[0] - lu_point[0])/X_D * X_MAX)}',
wight_point_dict[attr]['color'],
gs_font_22,
'mm',
)
img_draw.text(
(point[0], 535),
attr_list[index],
wight_point_dict[attr]['color'],
gs_font_22,
'mm',
)
img.paste(
point_img, (int(point[0] - 15), int(point[1] - 15)), point_img
)
img_draw.line(
[point, (point[0], rd_point[1])], width=1, fill=(255, 255, 255)
)
img.paste(frame_img, (0, 0), frame_img)
return img, 550

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

View File

@ -0,0 +1,92 @@
base_value_list = [
8.6,
9.3,
10.0,
10.6,
11.3,
12.3,
13.3,
14.4,
15.7,
17.1,
18.6,
20.3,
22.2,
24.3,
26.9,
29.5,
32.2,
34.9,
37.6,
40.3,
43.1,
45.9,
48.6,
51.4,
54.2,
56.6,
59.1,
61.5,
64.9,
68.2,
71.3,
74.5,
77.7,
80.9,
84.6,
88.3,
92,
95.9,
99.8,
103.7,
107.7,
112.1,
116.8,
121.1,
128.0,
134.3,
140.8,
147.5,
154.5,
161.8,
168.4,
175.3,
182.2,
189.3,
199.3,
208.2,
217.2,
226.5,
236.3,
246.4,
256.8,
269.6,
282.8,
296.3,
312.2,
325.7,
339.8,
353.9,
368.3,
382.8,
397.4,
412.3,
425.6,
438.9,
457.1,
473.4,
489.7,
505.6,
522.4,
538.7,
555.0,
571.5,
588.2,
605.1,
626.9,
644.5,
622.7,
681.7,
702.6,
723.4,
]

View File

@ -0,0 +1,112 @@
from typing import Dict, Tuple
from PIL import Image, ImageDraw
from ..mono.Enemy import Enemy
from ..mono.Fight import Fight
from ..etc.MAP_PATH import dmgMap
from ..mono.Character import Character
from ..etc.etc import TEXT_PATH, get_char_std
from ...utils.genshin_fonts.genshin_fonts import gs_font_28
dmgBar_1 = Image.open(TEXT_PATH / 'dmgBar_1.png')
dmgBar_2 = Image.open(TEXT_PATH / 'dmgBar_2.png')
text_color = (255, 255, 255)
title_color = (255, 255, 100)
async def get_char_dmg_percent(char: Character) -> Dict:
enemy = Enemy(char.char_level, char.char_level)
fight = Fight({char.char_name: char}, enemy)
dmg_data = await fight.get_dmg_dict(char.char_name)
without_talent = await fight.get_dmg_dict(char.char_name, True)
percent = 0
char.seq_str = '无匹配'
if char.char_name in dmgMap:
std = await get_char_std(char.card_prop, char.char_name)
if std['skill']:
value = 0
std_value = 0
if std['skill'] == 'atk':
value = char.fight_prop['atk']
std_value = std['atk']
elif std['skill'] == 'def':
value = char.fight_prop['def']
std_value = std['other']['防御']
elif std['skill'] in without_talent:
if without_talent[std['skill']]['crit'] == 0:
value = without_talent[std['skill']]['normal']
elif char.char_name == '妮露':
value = without_talent[std['skill']]['normal']
else:
value = without_talent[std['skill']]['avg']
std_value = std['value']
if char.char_name == '夜兰':
std_value *= 3
elif char.char_name == '刻晴':
std_value *= 2
if std_value != 0:
percent = (value / std_value) * 100
char.seq_str = (
'|'.join([i[:2] for i in std['seq'].split('|')])
+ std['seq'][-1]
)
char.percent = '{:.2f}'.format(percent)
char.dmg_data = dmg_data
return dmg_data
async def draw_dmg_img(char: Character) -> Tuple[Image.Image, int]:
# 获取值
dmg_data = await get_char_dmg_percent(char)
if dmg_data == {}:
return Image.new('RGBA', (950, 1)), 0
# 计算伤害计算部分图片长宽值
w = 950
h = 40 * (len(dmg_data) + 1)
result_img = Image.new('RGBA', (w, h), (0, 0, 0, 0))
# 反复贴上不同颜色的长条
for i in range(0, len(dmg_data) + 1):
pic = dmgBar_1 if i % 2 == 0 else dmgBar_2
result_img.paste(pic, (0, i * 40))
result_draw = ImageDraw.Draw(result_img)
text_size = gs_font_28
result_draw.text((45, 22), '角色动作', title_color, text_size, anchor='lm')
result_draw.text((450, 22), '暴击值', title_color, text_size, anchor='lm')
result_draw.text((615, 22), '期望值', title_color, text_size, anchor='lm')
result_draw.text((780, 22), '普通值', title_color, text_size, anchor='lm')
for index, name in enumerate(dmg_data):
result_draw.text(
(45, 22 + (index + 1) * 40),
name,
text_color,
text_size,
anchor='lm',
)
result_draw.text(
(450, 22 + (index + 1) * 40),
str(round(dmg_data[name]['crit'])),
text_color,
text_size,
anchor='lm',
)
result_draw.text(
(615, 22 + (index + 1) * 40),
str(round(dmg_data[name]['avg'])),
text_color,
text_size,
anchor='lm',
)
result_draw.text(
(780, 22 + (index + 1) * 40),
str(round(dmg_data[name]['normal'])),
text_color,
text_size,
anchor='lm',
)
return result_img, len(dmg_data) + 2

View File

@ -0,0 +1,77 @@
from typing import Tuple, Union, Optional
from PIL import Image, ImageDraw
from .mono.Character import Character
from .dmg_calc.dmg_calc import draw_dmg_img
from .draw_char_curve import draw_char_curve_card
from .etc.etc import TEXT_PATH, get_all_artifacts_value
from ..utils.draw_image_tools.send_image_tool import convert_img
from ..utils.genshin_fonts.genshin_fonts import gs_font_18, gs_font_50
from .draw_normal import (
get_bg_card,
get_char_img,
get_artifacts_card,
get_char_card_base,
)
async def draw_char_img(
char: Character,
charUrl: Optional[str] = None,
is_curve: bool = False,
) -> Union[str, Tuple[bytes, Optional[bytes]]]:
if is_curve:
res = await draw_char_curve_card(char, charUrl)
else:
res = await draw_char_card(char, charUrl)
return res, char.char_bytes
async def draw_char_card(char: Character, char_url: Optional[str]) -> bytes:
dmg_img, dmg_len = await draw_dmg_img(char)
char_img = await get_char_img(char, char_url)
ex_len = dmg_len * 40 + 765
img = await get_bg_card(char.char_element, ex_len, char_img)
img.paste(char_img, (0, 0), char_img)
char_info_1 = await get_char_card_base(char)
char_info_2 = Image.open(TEXT_PATH / 'char_info_2.png')
img.paste(char_info_1, (0, 0), char_info_1)
img.paste(char_info_2, (0, 1085), char_info_2)
img.paste(dmg_img, (0, 1850), dmg_img)
await get_artifacts_card(char, img)
img_text = ImageDraw.Draw(img)
artifacts_all_score = await get_all_artifacts_value(
char.card_prop, char.baseHp, char.baseAtk, char.baseDef, char.char_name
)
if char.percent == '0.00':
percent_str = '暂无匹配'
else:
percent_str = f'{char.percent}%'
# 角色评分
img_text.text(
(768, 1564),
f'{round(artifacts_all_score, 1)}',
(255, 255, 255),
gs_font_50,
anchor='mm',
)
img_text.text(
(768, 1726),
percent_str,
(255, 255, 255),
gs_font_50,
anchor='mm',
)
img_text.text(
(768, 1673),
f'{char.seq_str}',
(255, 255, 255),
gs_font_18,
anchor='mm',
)
res = await convert_img(img)
if isinstance(res, str):
res = b''
return res

View File

@ -0,0 +1,80 @@
from io import BytesIO
from typing import Optional
from PIL import Image, ImageDraw
from .etc.etc import TEXT_PATH
from .mono.Character import Character
from .curve_calc.curve_calc import draw_char_curve_data
from ..utils.genshin_fonts.genshin_fonts import genshin_font_origin
from .draw_normal import (
get_bg_card,
get_char_img,
get_artifacts_card,
get_char_card_base,
)
async def get_adv_card() -> Image.Image:
adv_img = Image.open(TEXT_PATH / 'adv.png')
return adv_img
async def draw_char_curve_card(
char: Character, char_url: Optional[str]
) -> bytes:
await get_artifacts_card(char, Image.new('RGB', (1, 1)))
curve_img, curve_len = await draw_char_curve_data(
char.char_name, char.card_prop
)
curve2_img, curve2_len = await draw_char_curve_data(
char.char_name, char.fight_prop
)
char_img = await get_char_img(char, char_url)
adv_img = await get_adv_card()
img = await get_bg_card(
char.char_element, curve_len + curve2_len + 460, char_img
)
img.paste(char_img, (0, 0), char_img)
char_info_1 = await get_char_card_base(char)
img.paste(char_info_1, (0, 0), char_info_1)
img.paste(curve_img, (0, 1085), curve_img)
img.paste(curve2_img, (0, 1085 + curve_len), curve2_img)
img.paste(adv_img, (0, 1085 + curve_len + curve2_len), adv_img)
img_text = ImageDraw.Draw(img)
# 顶栏
img_text.text(
(475, 2240),
'曲线(上)为正常面板,曲线(下)为触发各种战斗buff后面板',
(255, 255, 255),
genshin_font_origin(32),
anchor='mm',
)
# 角色评分
img_text.text(
(785, 2380),
f'{round(char.artifacts_all_score, 1)}',
(255, 255, 255),
genshin_font_origin(50),
anchor='mm',
)
img_text.text(
(785, 2542),
f'{str(char.percent)+"%"}',
(255, 255, 255),
genshin_font_origin(50),
anchor='mm',
)
img_text.text(
(785, 2490),
f'{char.seq_str}',
(255, 255, 255),
genshin_font_origin(18),
anchor='mm',
)
img = img.convert('RGB')
result_buffer = BytesIO()
img.save(result_buffer, format='JPEG', subsampling=0, quality=90)
res = result_buffer.getvalue()
return res

View File

@ -0,0 +1,242 @@
import json
import asyncio
from typing import Tuple, Union, Literal
from PIL import Image, ImageDraw
from .mono.Character import Character
from .dmg_calc.dmg_calc import get_char_dmg_percent
from .etc.etc import TEXT_PATH, get_all_artifacts_value
from ..utils.draw_image_tools.send_image_tool import convert_img
from ..utils.genshin_fonts.genshin_fonts import genshin_font_origin
from ..utils.alias.avatarId_to_char_star import avatar_id_to_char_star
from ..utils.download_resource.RESOURCE_PATH import (
CHAR_PATH,
PLAYER_PATH,
WEAPON_PATH,
)
from ..utils.draw_image_tools.draw_image_tool import (
get_color_bg,
get_qq_avatar,
get_fetter_pic,
get_talent_pic,
draw_pic_with_ring,
get_weapon_affix_pic,
)
black_color = (24, 24, 24)
white_color = (245, 245, 245)
level_color = {
5: (230, 0, 0),
4: (203, 131, 21),
3: (97, 17, 156),
2: (17, 105, 156),
1: (94, 96, 95),
}
level_map = {
'skill': {
10: 5,
7: 4,
5: 3,
3: 2,
0: 1,
},
'equip': {33: 5, 27: 4, 21: 3, 15: 2, 0: 1},
'percent': {99: 5, 90: 4, 85: 3, 70: 2, 0: 1},
}
star_color_map = {
'1': (94, 96, 95),
'2': (17, 105, 156),
'3': (91, 141, 192),
'4': (143, 123, 174),
'5': (205, 135, 76),
}
gs_font_24 = genshin_font_origin(24)
gs_font_26 = genshin_font_origin(26)
gs_font_28 = genshin_font_origin(28)
gs_font_30 = genshin_font_origin(30)
gs_font_36 = genshin_font_origin(36)
char_rank_title = Image.open(TEXT_PATH / 'char_rank_title.png')
skill_mask = Image.open(TEXT_PATH / 'skill_mask.png')
percent_mask = Image.open(TEXT_PATH / 'percent_mask.png')
value_mask = Image.open(TEXT_PATH / 'value_mask.png')
async def draw_cahrcard_list(
uid: str, qid: Union[str, int]
) -> Union[str, bytes]:
uid_fold = PLAYER_PATH / str(uid)
char_file_list = uid_fold.glob('*')
char_list = []
for i in char_file_list:
file_name = i.name
if '\u4e00' <= file_name[0] <= '\u9fff':
char_list.append(file_name.split('.')[0])
if not char_list:
return '你还没有已缓存的角色!\n请先使用【强制刷新】进行刷新!'
char_done_list = []
for char_name in char_list:
temp = {}
with open(uid_fold / f'{char_name}.json', 'r', encoding='UTF-8') as f:
raw_data = json.load(f)
skill_list = raw_data['avatarSkill']
temp['char_name'] = char_name
temp['fetter'] = raw_data['avatarFetter']
temp['id'] = raw_data['avatarId']
char = Character(raw_data)
await char.new()
await char.get_fight_prop()
await get_char_dmg_percent(char)
temp['percent'] = char.percent
temp['percent'] = float(temp['percent'])
temp['value'] = await get_all_artifacts_value(
raw_data,
char.baseHp,
char.baseAtk,
char.baseDef,
char_name,
)
temp['value'] = float('{:.2f}'.format(temp['value']))
temp['avatarElement'] = raw_data['avatarElement']
temp['a_skill_level'] = skill_list[0]['skillLevel']
temp['e_skill_level'] = skill_list[1]['skillLevel']
temp['q_skill_level'] = skill_list[-1]['skillLevel']
temp['talent_num'] = len(raw_data['talentList'])
# 武器
temp['weapon_name'] = raw_data['weaponInfo']['weaponName']
temp['weapon_level'] = raw_data['weaponInfo']['weaponLevel']
temp['weapon_affix'] = raw_data['weaponInfo']['weaponAffix']
temp['weapon_star'] = raw_data['weaponInfo']['weaponStar']
char_done_list.append(temp)
# 排序
char_done_list.sort(key=lambda x: (-x['percent']))
qid = str(qid)
if qid.startswith('http'):
char_pic = await get_qq_avatar(avatar_url=qid)
else:
char_pic = await get_qq_avatar(qid=qid)
char_pic = await draw_pic_with_ring(char_pic, 320)
img = await get_color_bg(950, 540 + 100 * len(char_done_list))
img.paste(char_rank_title, (0, 0), char_rank_title)
img.paste(char_pic, (318, 83), char_pic)
img_draw = ImageDraw.Draw(img)
img_draw.text((475, 464), f'UID {uid}', black_color, gs_font_36, 'mm')
tasks = []
for index, char in enumerate(char_done_list):
tasks.append(draw_single_rank(img, char, index))
await asyncio.wait(tasks)
res = await convert_img(img)
return res
async def get_color(
type: Literal['skill', 'equip', 'percent'], value: int
) -> Tuple[int, int, int]:
for v in level_map[type]:
if value >= v:
level = level_map[type][v]
break
else:
level = 1
return level_color[level]
async def draw_single_rank(img: Image.Image, char: dict, index: int):
char_id = char['id']
char_rank = Image.open(TEXT_PATH / 'char_rank.png')
char_pic = Image.open(CHAR_PATH / f'{char_id}.png')
char_star = await avatar_id_to_char_star(char_id)
weapon_star = str(char['weapon_star'])
char_pic = await draw_pic_with_ring(
char_pic, 82, star_color_map[char_star]
)
weapon_pic = Image.open(WEAPON_PATH / f'{char["weapon_name"]}.png')
weapon_pic = await draw_pic_with_ring(
weapon_pic, 82, star_color_map[weapon_star]
)
char_rank.paste(char_pic, (0, 0), char_pic)
char_rank.paste(weapon_pic, (626, 0), weapon_pic)
char_rank_draw = ImageDraw.Draw(char_rank)
# 角色名称
char_rank_draw.text(
(85, 24), char['char_name'], black_color, gs_font_28, 'lm'
)
# AEQ等级
for s_index, s in enumerate(['a', 'e', 'q']):
s_offset = s_index * 38
skill_color_img = Image.new(
'RGBA',
(35, 28),
await get_color('skill', char[f'{s}_skill_level']),
)
char_rank.paste(skill_color_img, (86 + s_offset, 44), skill_mask)
char_rank_draw.text(
(103 + s_offset, 58),
str(char[f'{s}_skill_level']),
white_color,
gs_font_26,
'mm',
)
# 圣遗物词条数
value_color_img = Image.new(
'RGBA',
(77, 33),
await get_color('equip', char['value']),
)
char_rank.paste(value_color_img, (233, 23), value_mask)
char_rank_draw.text(
(271, 40),
f'{str(char["value"])[:4]}',
white_color,
gs_font_24,
'mm',
)
# 毕业度
percent_color_img = Image.new(
'RGBA',
(99, 33),
await get_color('percent', char['percent']),
)
char_rank.paste(percent_color_img, (329, 23), percent_mask)
char_rank_draw.text(
(379, 40),
f'{char["percent"]}%',
white_color,
gs_font_24,
'mm',
)
# 好感和天赋
fetter_pic = await get_fetter_pic(char['fetter'])
fetter_pic = fetter_pic.resize((77, 33))
talent_pic = await get_talent_pic(char['talent_num'])
talent_pic = talent_pic.resize((66, 33))
char_rank.paste(fetter_pic, (444, 23), fetter_pic)
char_rank.paste(talent_pic, (536, 23), talent_pic)
# 武器
weapon_affix_pic = await get_weapon_affix_pic(char['weapon_affix'])
char_rank.paste(weapon_affix_pic, (714, 42), weapon_affix_pic)
char_rank_draw.text(
(788, 56), f'Lv.{char["weapon_level"]}', black_color, gs_font_26, 'lm'
)
char_rank_draw.text(
(712, 22), str(char['weapon_name']), black_color, gs_font_26, 'lm'
)
img.paste(char_rank, (30, 540 + 100 * index), char_rank)

View File

@ -0,0 +1,170 @@
from typing import Dict, List, Union
from PIL import Image, ImageDraw
from .mono.Enemy import Enemy
from .mono.Fight import Fight
from .etc.etc import TEXT_PATH
from .mono.Character import Character
from .mono.SEQ import ALL_SEQ, SEQ_ARG
from ..utils.download_resource.RESOURCE_PATH import CHAR_PATH
from ..utils.draw_image_tools.send_image_tool import convert_img
from ..utils.alias.avatarId_and_name_covert import name_to_avatar_id
from ..utils.draw_image_tools.draw_image_tool import (
get_color_bg,
draw_pic_with_ring,
)
from ..utils.genshin_fonts.genshin_fonts import (
gs_font_26,
gs_font_32,
gs_font_44,
gs_font_50,
)
TD_PATH = TEXT_PATH / 'team_dmg'
team_title = Image.open(TD_PATH / 'team_title.png')
action_title = Image.open(TD_PATH / 'action_title.png')
async def get_group_dmg_data(
char_list: List[Character],
) -> Union[Dict[float, Dict], str]:
# 获取值
enemy = Enemy(90, 90)
char_dict: Dict[str, Character] = {}
char_arg = [char.char_name for char in char_list]
for arg in SEQ_ARG:
if sorted(char_arg) == sorted(SEQ_ARG[arg]):
seq = ALL_SEQ[arg]
break
else:
return '暂时不支持该配队...'
for char in char_list:
char_dict[char.char_name] = char
fight = Fight(char_dict, enemy)
fight.SEQ = seq
dmg_data: Dict[float, Dict] = await fight.update_dmg()
return dmg_data
def _f(value: float, is_float: bool = True) -> str:
if is_float:
return '{:.1f}'.format(value)
else:
return str(int(value))
def _p(value: float) -> str:
return '{:.2f}%'.format(value * 100)
async def draw_group_dmg_img(
uid: str, char_list: List[Character]
) -> Union[bytes, str]:
# 获取数据
dmg_data = await get_group_dmg_data(char_list)
if isinstance(dmg_data, str):
return dmg_data
# 计算高度
bar_offset = 65
h = 900 + 120 + len(dmg_data) * bar_offset + 50
# 开始绘图
img = await get_color_bg(950, h, 'teamdmg_bg')
img.paste(team_title, (0, 0), team_title)
# 角色基本情况
for index, char in enumerate(char_list):
char_bg = Image.open(TD_PATH / 'char_bg.png')
char_pic = Image.open(CHAR_PATH / f'{char.char_id}.png')
char_img = await draw_pic_with_ring(char_pic, 100)
char_bg.paste(char_img, (31, 27), char_img)
hp = _f(char.fight_prop['hp'], False)
atk = _f(char.fight_prop['atk'], False)
critr = _p(char.fight_prop['critRate'])
critd = _p(char.fight_prop['critDmg'])
lv = f'Lv.{char.char_level}'
char_draw = ImageDraw.Draw(char_bg)
char_draw.text((210, 69), hp, 'white', gs_font_26, 'lm')
char_draw.text((344, 69), atk, 'white', gs_font_26, 'lm')
char_draw.text((210, 130), critr, 'white', gs_font_26, 'lm')
char_draw.text((344, 130), critd, 'white', gs_font_26, 'lm')
char_draw.text((85, 154), lv, 'white', gs_font_26, 'mm')
# 将绘制好的角色卡贴到队伍伤害卡上
img.paste(
char_bg,
(16 + 443 * (index % 2), 540 + 170 * (index // 2)),
char_bg,
)
img.paste(action_title, (0, 895), action_title)
# 初始化一些数值
all_avgdmg = 0
all_critdmg = 0
dmg_info = {}
# 粘贴动作序列
for index, time in enumerate(dmg_data):
_data = dmg_data[time]
char_id = await name_to_avatar_id(_data['char'])
char_pic = Image.open(CHAR_PATH / f'{char_id}.png')
char_img = await draw_pic_with_ring(char_pic, 50)
bar = Image.open(TD_PATH / 'dmg_bar.png')
bar.paste(char_img, (100, 10), char_img)
bar_draw = ImageDraw.Draw(bar)
# Action
bar_draw.text((190, 35), _data['action'], 'white', gs_font_32, 'lm')
# 具体伤害
_dmg = _data['avg_dmg'] if _data['avg_dmg'] else _data['normal_dmg']
bar_draw.text((600, 35), _f(_dmg), 'white', gs_font_32, 'lm')
img.paste(bar, (0, 1030 + index * bar_offset), bar)
# 总平均伤害加值
all_avgdmg += _data['avg_dmg']
all_critdmg += _data['crit_dmg']
# 计算一些数据
if _data['char'] not in dmg_info:
dmg_info[_data['char']] = _data['avg_dmg']
else:
dmg_info[_data['char']] += _data['avg_dmg']
ac_len = len(dmg_data)
all_time = list(dmg_data.keys())[-1]
avg_dps = all_avgdmg / all_time
char_id = '10000029'
char_pic = Image.open(CHAR_PATH / f'{char_id}.png')
char_img = await draw_pic_with_ring(char_pic, 280)
img.paste(char_img, (60, 78), char_img)
img_draw = ImageDraw.Draw(img)
# UID
img_draw.text((395, 98), f'UID{uid}', 'white', gs_font_50, 'lm')
# 标题
img_draw.text((396, 200), '总期望伤害', 'white', gs_font_26, 'lm')
img_draw.text((656, 200), '总暴击伤害', 'white', gs_font_26, 'lm')
img_draw.text((396, 297), '平均DPS', 'white', gs_font_26, 'lm')
img_draw.text((656, 297), f'{ac_len}个动作', 'white', gs_font_26, 'lm')
# 数值
img_draw.text((390, 236), f'{_f(all_avgdmg)}', 'white', gs_font_44, 'lm')
img_draw.text((650, 236), f'{_f(all_critdmg)}', 'white', gs_font_44, 'lm')
img_draw.text((390, 333), f'{_f(avg_dps)}', 'white', gs_font_44, 'lm')
img_draw.text((650, 333), f'{_f(all_time)}秒内', 'white', gs_font_44, 'lm')
img = await convert_img(img)
return img

View File

@ -0,0 +1,596 @@
import math
import random
from io import BytesIO
from typing import Optional
import aiofiles
from httpx import get
from PIL import Image, ImageDraw, ImageChops
from .mono.Character import Character
from .etc.MAP_PATH import COLOR_MAP, avatarName2SkillAdd
from ..utils.db_operation.db_operation import config_check
from ..genshinuid_config.default_config import string_config
from ..utils.genshin_fonts.genshin_fonts import genshin_font_origin
from .etc.etc import TEXT_PATH, strLenth, get_star_png, get_artifacts_value
from ..utils.draw_image_tools.draw_image_tool import (
CustomizeImage,
get_weapon_affix_pic,
)
from ..utils.download_resource.RESOURCE_PATH import (
REL_PATH,
ICON_PATH,
CU_CHBG_PATH,
GACHA_IMG_PATH,
CHAR_STAND_PATH,
)
ARTIFACTS_POS = {
'生之花': (18, 1075),
'死之羽': (318, 1075),
'时之沙': (618, 1075),
'空之杯': (18, 1447),
'理之冠': (318, 1447),
}
PIC_API = string_config.get_config('random_pic_API')
async def get_char_card_base(char: Character) -> Image.Image:
card_prop = char.card_prop
char_info_1 = Image.open(TEXT_PATH / 'char_info_1.png')
# 命座处理
lock_img = Image.open(TEXT_PATH / 'icon_lock.png')
# holo_img = Image.open(TEXT_PATH / 'holo.png')
for talent_num in range(0, 6):
if talent_num + 1 <= len(card_prop['talentList']):
talent = card_prop['talentList'][talent_num]
try:
talent_img = Image.open(
ICON_PATH / '{}.png'.format(talent['talentIcon'])
)
except Exception:
talent_img = Image.open(
ICON_PATH / 'UI_Talent_S_Kazuha_02.png'
)
talent_img_new = talent_img.resize(
(50, 50), Image.Resampling.LANCZOS
).convert("RGBA")
for _ in range(2):
char_info_1.paste(
talent_img_new,
(850, 375 + talent_num * 81),
talent_img_new,
)
else:
char_info_1.paste(lock_img, (850, 375 + talent_num * 81), lock_img)
# 天赋处理
skillList = card_prop['avatarSkill']
a_skill_level = skillList[0]['skillLevel']
e_skill_level = skillList[1]['skillLevel']
q_skill_level = skillList[-1]['skillLevel']
if char.char_name in avatarName2SkillAdd:
skill_add = avatarName2SkillAdd[char.char_name]
else:
skill_add = ['E', 'Q']
for skillAdd_index in range(0, 2):
if len(card_prop['talentList']) >= 3 + skillAdd_index * 2:
if skill_add[skillAdd_index] == 'E':
e_skill_level += 3
elif skill_add[skillAdd_index] == 'Q':
q_skill_level += 3
for skill_num, skill in enumerate(skillList[0:2] + [skillList[-1]]):
skill_img = Image.open(ICON_PATH / '{}.png'.format(skill['skillIcon']))
skill_img_new = skill_img.resize(
(50, 50), Image.Resampling.LANCZOS
).convert("RGBA")
char_info_1.paste(
skill_img_new, (78, 756 + 101 * skill_num), skill_img_new
)
# 武器部分
char_info_text = ImageDraw.Draw(char_info_1)
weapon_star_img = get_star_png(card_prop['weaponInfo']['weaponStar'])
weaponName = card_prop['weaponInfo']['weaponName']
weaponAtk = card_prop['weaponInfo']['weaponStats'][0]['statValue']
weaponLevel = card_prop['weaponInfo']['weaponLevel']
weaponAffix = card_prop['weaponInfo']['weaponAffix']
weaponEffect = card_prop['weaponInfo']['weaponEffect']
weapon_type = card_prop['weaponInfo']['weaponType']
char_info_1.paste(weapon_star_img, (402, 825), weapon_star_img)
char_info_text.text(
(412, 670),
weaponName,
(255, 255, 255),
genshin_font_origin(50),
anchor='lm',
)
char_info_text.text(
(412, 710),
weapon_type,
(255, 255, 255),
genshin_font_origin(20),
anchor='lm',
)
char_info_text.text(
(412, 750),
'基础攻击力',
(255, 255, 255),
genshin_font_origin(32),
anchor='lm',
)
char_info_text.text(
(755, 750),
str(weaponAtk),
(255, 255, 255),
genshin_font_origin(32),
anchor='rm',
)
if len(card_prop['weaponInfo']['weaponStats']) == 2:
weapon_sub_info = card_prop['weaponInfo']['weaponStats'][1]['statName']
weapon_sub_value = card_prop['weaponInfo']['weaponStats'][1][
'statValue'
]
char_info_text.text(
(412, 801),
weapon_sub_info,
(255, 255, 255),
genshin_font_origin(32),
anchor='lm',
)
char_info_text.text(
(755, 801),
str(weapon_sub_value),
(255, 255, 255),
genshin_font_origin(32),
anchor='rm',
)
else:
char_info_text.text(
(412, 801),
'该武器无副词条',
(255, 255, 255),
genshin_font_origin(32),
anchor='lm',
)
char_info_text.text(
(460, 893),
f'Lv.{weaponLevel}',
(255, 255, 255),
genshin_font_origin(28),
anchor='mm',
)
affix_pic = await get_weapon_affix_pic(weaponAffix)
char_info_1.paste(affix_pic, (420 + len(weaponName) * 50, 660), affix_pic)
'''
char_info_text.text(
(517, 895),
f'精炼{str(weaponAffix)}阶',
(255, 239, 173),
genshin_font_origin(28),
anchor='lm',
)
'''
weaponEffect = strLenth(weaponEffect, 25, 455)
weaponEffect = '\n'.join(weaponEffect.split('\n')[:5])
char_info_text.text(
(412, 925), weaponEffect, (255, 255, 255), genshin_font_origin(25)
)
fight_prop = card_prop['avatarFightProp']
hp = fight_prop['hp']
attack = fight_prop['atk']
defense = fight_prop['def']
em = fight_prop['elementalMastery']
critrate = fight_prop['critRate']
critdmg = fight_prop['critDmg']
ce = fight_prop['energyRecharge']
dmgBonus = (
fight_prop['dmgBonus']
if fight_prop['physicalDmgBonus'] <= fight_prop['dmgBonus']
else fight_prop['physicalDmgBonus']
)
hp_green = fight_prop['hp'] - fight_prop['baseHp']
attack_green = fight_prop['atk'] - fight_prop['baseAtk']
defense_green = fight_prop['def'] - fight_prop['baseDef']
# 角色基本信息
char_info_text.text(
(411, 72),
char.char_name,
(255, 255, 255),
genshin_font_origin(55),
anchor='lm',
)
char_info_text.text(
(411, 122),
'等级{}'.format(char.char_level),
(255, 255, 255),
genshin_font_origin(40),
anchor='lm',
)
char_info_text.text(
(747, 126),
str(char.char_fetter),
(255, 255, 255),
genshin_font_origin(28),
anchor='lm',
)
char_info_text.text(
(103, 812),
f'{str(a_skill_level)}',
(255, 255, 255),
genshin_font_origin(30),
anchor='mm',
)
char_info_text.text(
(103, 915),
f'{str(e_skill_level)}',
(255, 255, 255),
genshin_font_origin(30),
anchor='mm',
)
char_info_text.text(
(103, 1016),
f'{str(q_skill_level)}',
(255, 255, 255),
genshin_font_origin(30),
anchor='mm',
)
# 属性
char_info_text.text(
(785, 174),
str(round(hp)),
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
char_info_text.text(
(785, 227),
str(round(attack)),
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
char_info_text.text(
(785, 280),
str(round(defense)),
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
char_info_text.text(
(785, 333),
str(round(em)),
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
char_info_text.text(
(785, 386),
f'{str(round(critrate * 100, 2))}%',
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
char_info_text.text(
(785, 439),
f'{str(round(critdmg * 100, 2))}%',
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
char_info_text.text(
(785, 492),
f'{str(round(ce * 100, 1))}%',
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
char_info_text.text(
(785, 545),
f'{str(round(dmgBonus * 100, 1))}%',
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
char_info_text.text(
(805, 174),
f'(+{str(round(hp_green))})',
(95, 251, 80),
genshin_font_origin(28),
anchor='lm',
)
char_info_text.text(
(805, 227),
f'(+{str(round(attack_green))})',
(95, 251, 80),
genshin_font_origin(28),
anchor='lm',
)
char_info_text.text(
(805, 280),
f'(+{str(round(defense_green))})',
(95, 251, 80),
genshin_font_origin(28),
anchor='lm',
)
uid = card_prop['playerUid']
data_time = card_prop['dataTime']
# uid
char_info_text.text(
(350, 1035),
f'UID{uid}',
(255, 255, 255),
genshin_font_origin(24),
anchor='rm',
)
# 数据最后更新时间
char_info_text.text(
(780, 600),
f'数据最后更新于{data_time}',
(255, 255, 255),
genshin_font_origin(22),
anchor='rm',
)
return char_info_1
async def get_bg_card(
char_element: str, ex_len: int, char_img: Image.Image
) -> Image.Image:
img_w, img_h = 950, 1085 + ex_len
overlay = Image.open(TEXT_PATH / 'overlay.png')
overlay_w, overlay_h = overlay.size
if overlay_h < img_h:
new_overlay_h = img_h
new_overlay_w = math.ceil(new_overlay_h * overlay_w / overlay_h)
overlay = overlay.resize(
(new_overlay_w, new_overlay_h), Image.Resampling.LANCZOS
)
overlay = overlay.crop((0, 0, img_w, img_h))
elif overlay_h > img_h:
new_overlay_w = img_w
new_overlay_h = math.ceil(overlay_w / new_overlay_w * overlay_h)
overlay = overlay.resize(
(new_overlay_w, new_overlay_h), Image.Resampling.LANCZOS
)
overlay = overlay.crop((0, 0, img_w, img_h))
if await config_check('ColorBG') and await config_check('RandomPic'):
bg_color = CustomizeImage.get_bg_color(char_img)
else:
bg_color = COLOR_MAP[char_element]
color_img = Image.new('RGBA', overlay.size, bg_color)
return ImageChops.overlay(color_img, overlay)
async def get_char_img(
char: Character, char_url: Optional[str] = None
) -> Image.Image:
char_name = char.char_name
if await config_check('RandomPic') and char_url is None:
if char_name == '旅行者':
char_name_url = ''
else:
char_name_url = char_name
chbg_path = CU_CHBG_PATH / char_name_url
char_url = f'{PIC_API}{char_name_url}'
if chbg_path.exists():
cuch_img = random.choice(list(chbg_path.iterdir()))
async with aiofiles.open(cuch_img, 'rb') as f:
char.char_bytes = await f.read()
else:
char_data = get(char_url, follow_redirects=True)
if 'application/json' in char_data.headers['Content-Type']:
char_url = None
else:
char.char_bytes = char_data.content
based_w, based_h = 600, 1200
if char_url:
offset_x, offset_y = 200, 0
if char.char_bytes is None:
char.char_bytes = get(char_url).content
char_img = Image.open(BytesIO(char.char_bytes)).convert('RGBA')
else:
offset_x, offset_y = 200, 0
if char_name == '旅行者':
char_img = (
Image.open(CHAR_STAND_PATH / '10000007.png')
.convert('RGBA')
.resize((1421, 800))
)
else:
char_img = Image.open(GACHA_IMG_PATH / f'{char_name}.png') # 角色图像
# 确定图片的长宽
w, h = char_img.size
if (w, h) != (based_w, based_h):
based_new_w, based_new_h = based_w + offset_x, based_h + offset_y
based_scale = '%.3f' % (based_new_w / based_new_h)
scale_f = '%.3f' % (w / h)
new_w = math.ceil(based_new_h * float(scale_f))
new_h = math.ceil(based_new_w / float(scale_f))
if scale_f > based_scale:
bg_img2 = char_img.resize(
(new_w, based_new_h), Image.Resampling.LANCZOS
)
x1 = new_w / 2 - based_new_w / 2 + offset_x
y1 = 0 + offset_y / 2
x2 = new_w / 2 + based_new_w / 2
y2 = based_new_h - offset_y / 2
else:
bg_img2 = char_img.resize(
(based_new_w, new_h), Image.Resampling.LANCZOS
)
x1 = 0 + offset_x
y1 = new_h / 2 - based_new_h / 2 + offset_y / 2
x2 = based_new_w
y2 = new_h / 2 + based_new_h / 2 - offset_y / 2
char_img = bg_img2.crop((x1, y1, x2, y2)) # type: ignore
char_info_mask = Image.open(TEXT_PATH / 'char_info_mask.png')
char_result = Image.new('RGBA', (based_w, based_h), (0, 0, 0, 0))
char_result.paste(char_img, (0, 0), char_info_mask)
return char_result
async def get_artifacts_card(char: Character, img: Image.Image):
card_prop = char.card_prop
# 圣遗物部分
for aritifact in card_prop['equipList']:
artifacts_img = Image.open(TEXT_PATH / 'char_info_artifacts.png')
artifacts_piece_img = Image.open(
REL_PATH / '{}.png'.format(aritifact['aritifactName'])
)
artifacts_piece_new_img = artifacts_piece_img.resize(
(120, 120), Image.Resampling.LANCZOS
).convert("RGBA")
artifacts_img.paste(
artifacts_piece_new_img, (165, 22), artifacts_piece_new_img
)
aritifactStar_img = get_star_png(aritifact['aritifactStar'])
artifactsPos = aritifact['aritifactPieceName']
# 圣遗物星星和名称&位置
artifacts_img.paste(aritifactStar_img, (16, 115), aritifactStar_img)
artifacts_text = ImageDraw.Draw(artifacts_img)
if len(aritifact['aritifactName']) <= 5:
main_name = aritifact['aritifactName']
else:
main_name = (
aritifact['aritifactName'][:2] + aritifact['aritifactName'][4:]
)
artifacts_text.text(
(22, 100),
main_name,
(255, 255, 255),
genshin_font_origin(28),
anchor='lm',
)
'''
artifacts_text.text(
(30, 102),
artifactsPos,
(255, 255, 255),
genshin_font_origin(20),
anchor='lm',
)
'''
mainValue: float = aritifact['reliquaryMainstat']['statValue']
mainName: str = aritifact['reliquaryMainstat']['statName']
mainLevel: int = aritifact['aritifactLevel']
if mainName in ['攻击力', '血量', '防御力', '元素精通']:
mainValueStr = str(mainValue)
else:
mainValueStr = str(mainValue) + '%'
mainNameNew = (
mainName.replace('百分比', '')
.replace('伤害加成', '伤加成')
.replace('元素', '')
.replace('', '')
)
artifacts_text.text(
(34, 174),
mainNameNew,
(255, 255, 255),
genshin_font_origin(28),
anchor='lm',
)
artifacts_text.text(
(266, 174),
mainValueStr,
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
artifacts_text.text(
(246, 132),
'+{}'.format(str(mainLevel)),
(255, 255, 255),
genshin_font_origin(23),
anchor='mm',
)
artifactsScore = 0
for index, i in enumerate(aritifact['reliquarySubstats']):
subName: str = i['statName']
subValue: float = i['statValue']
if subName in ['攻击力', '血量', '防御力', '元素精通']:
subValueStr = str(subValue)
else:
subValueStr = str(subValue) + '%'
value_temp = await get_artifacts_value(
subName,
subValue,
char.baseAtk,
char.baseHp,
char.baseDef,
char.char_name,
)
artifactsScore += value_temp
subNameStr = subName.replace('百分比', '').replace('元素', '')
# 副词条文字颜色
if value_temp == 0:
artifacts_color = (160, 160, 160)
else:
artifacts_color = (255, 255, 255)
# 副词条底色
if value_temp >= 3.4:
artifacts_bg = (205, 135, 76)
if value_temp >= 4.5:
artifacts_bg = (158, 39, 39)
artifacts_text.rounded_rectangle(
(22, 209 + index * 35, 274, 238 + index * 35),
fill=artifacts_bg,
radius=8,
)
artifacts_text.text(
(22, 225 + index * 35),
'·{}'.format(subNameStr),
artifacts_color,
genshin_font_origin(25),
anchor='lm',
)
artifacts_text.text(
(266, 225 + index * 35),
'{}'.format(subValueStr),
artifacts_color,
genshin_font_origin(25),
anchor='rm',
)
if artifactsScore >= 8.4:
artifactsScore_color = (158, 39, 39)
elif artifactsScore >= 6.5:
artifactsScore_color = (205, 135, 76)
elif artifactsScore >= 5.2:
artifactsScore_color = (143, 123, 174)
else:
artifactsScore_color = (94, 96, 95)
char.artifacts_all_score += artifactsScore
artifacts_text.rounded_rectangle(
(21, 45, 104, 75), fill=artifactsScore_color, radius=8
)
artifacts_text.text(
(26, 60),
'{:.2f}'.format(artifactsScore) + '',
(255, 255, 255),
genshin_font_origin(23),
anchor='lm',
)
img.paste(artifacts_img, ARTIFACTS_POS[artifactsPos], artifacts_img)

View File

@ -0,0 +1,646 @@
{
"乐园遗落之花": {
"normal_effect": {
"2": "elementalMastery+80",
"4": ""
},
"fight_effect": {
"2": "",
"4": "a+40"
},
"group_effect": {
"2": "",
"4": ""
}
},
"水仙之梦": {
"normal_effect": {
"2": "HydroDmgBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": "addAtk+25;HydroDmgBonus+15"
},
"group_effect": {
"2": "",
"4": ""
}
},
"花海甘露之光": {
"normal_effect": {
"2": "addHp+20",
"4": ""
},
"fight_effect": {
"2": "",
"4": "EQ:dmgBonus+50"
},
"group_effect": {
"2": "",
"4": ""
}
},
"沙上楼阁史话": {
"normal_effect": {
"2": "AnemoDmgBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": "ABC:dmgBonus+40"
},
"group_effect": {
"2": "",
"4": ""
}
},
"深林的记忆": {
"normal_effect": {
"2": "DendroDmgBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": "DendroResist+-30"
},
"group_effect": {
"2": "",
"4": ""
}
},
"饰金之梦": {
"normal_effect": {
"2": "elementalMastery+80",
"4": ""
},
"fight_effect": {
"2": "",
"4": "elementalMastery+150"
},
"group_effect": {
"2": "",
"4": ""
}
},
"勇士": {
"normal_effect": {
"2": "addAtk+18",
"4": ""
},
"fight_effect": {
"2": "",
"4": "dmgBonus+30"
},
"group_effect": {
"2": "",
"4": ""
}
},
"辰砂往生录": {
"normal_effect": {
"2": "addAtk+18",
"4": ""
},
"fight_effect": {
"2": "",
"4": "addAtk+48"
},
"group_effect": {
"2": "",
"4": ""
}
},
"来歆余响": {
"normal_effect": {
"2": "addAtk+18",
"4": ""
},
"fight_effect": {
"2": "",
"4": "A:addDmg+70%atk"
},
"group_effect": {
"2": "",
"4": ""
}
},
"华馆梦醒形骸记": {
"normal_effect": {
"2": "addDef+30",
"4": ""
},
"fight_effect": {
"2": "",
"4": "dmgBonus+24;addDef+24"
},
"group_effect": {
"2": "",
"4": ""
}
},
"海染砗磲": {
"normal_effect": {
"2": "healBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"绝缘之旗印": {
"normal_effect": {
"2": "energyRecharge+20",
"4": ""
},
"fight_effect": {
"2": "",
"4": "Q:dmgBonus+75%25%energyrecharge"
},
"group_effect": {
"2": "",
"4": ""
}
},
"追忆之注连": {
"normal_effect": {
"2": "addAtk+18",
"4": ""
},
"fight_effect": {
"2": "",
"4": "ABC:dmgBonus+50"
},
"group_effect": {
"2": "",
"4": ""
}
},
"千岩牢固": {
"normal_effect": {
"2": "addHp+20",
"4": ""
},
"fight_effect": {
"2": "",
"4": "addAtk+20;shieldBonus+30"
},
"group_effect": {
"2": "",
"4": "addAtk+20;shieldBonus+30"
}
},
"苍白之火": {
"normal_effect": {
"2": "physicalDmgBonus+25",
"4": ""
},
"fight_effect": {
"2": "",
"4": "addAtk+18;physicalDmgBonus+25"
},
"group_effect": {
"2": "",
"4": ""
}
},
"平息鸣雷的尊者": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": "dmgBonus+35"
},
"group_effect": {
"2": "",
"4": ""
}
},
"炽烈的炎之魔女": {
"normal_effect": {
"2": "PyroDmgBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": "a+15;dmgBonus+22.5"
},
"group_effect": {
"2": "",
"4": ""
}
},
"流浪大地的乐团": {
"normal_effect": {
"2": "elementalMastery+80",
"4": ""
},
"fight_effect": {
"2": "",
"4": "B:dmgBonus+35"
},
"group_effect": {
"2": "",
"4": ""
}
},
"染血的骑士道": {
"normal_effect": {
"2": "physicalDmgBonus+25",
"4": ""
},
"fight_effect": {
"2": "",
"4": "B:dmgBonus+50"
},
"group_effect": {
"2": "",
"4": ""
}
},
"被怜爱的少女": {
"normal_effect": {
"2": "healBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": "healBonus+20"
},
"group_effect": {
"2": "",
"4": ""
}
},
"角斗士的终幕礼": {
"normal_effect": {
"2": "addAtk+18",
"4": ""
},
"fight_effect": {
"2": "",
"4": "A:dmgBonus+35"
},
"group_effect": {
"2": "",
"4": ""
}
},
"渡过烈火的贤人": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": "dmgBonus+35"
},
"group_effect": {
"2": "",
"4": ""
}
},
"悠古的磐岩": {
"normal_effect": {
"2": "GeoDmgBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": "dmgBonus+35"
}
},
"如雷的盛怒": {
"normal_effect": {
"2": "ElectroDmgBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"沉沦之心": {
"normal_effect": {
"2": "HydroDmgBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": "AB:dmgBonus+30"
},
"group_effect": {
"2": "",
"4": ""
}
},
"逆飞的流星": {
"normal_effect": {
"2": "shieldBonus+35",
"4": ""
},
"fight_effect": {
"2": "",
"4": "AB:dmgBonus+40"
},
"group_effect": {
"2": "",
"4": ""
}
},
"昔日宗室之仪": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "Q:dmgBonus+20",
"4": "addAtk+20"
},
"group_effect": {
"2": "",
"4": "addAtk+20"
}
},
"翠绿之影": {
"normal_effect": {
"2": "AnemoDmgBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": "g+60;Resist+-40"
},
"group_effect": {
"2": "",
"4": ""
}
},
"冰风迷途的勇士": {
"normal_effect": {
"2": "CryoDmgBonus+15",
"4": ""
},
"fight_effect": {
"2": "",
"4": "critRate+40"
},
"group_effect": {
"2": "",
"4": ""
}
},
"勇士之心": {
"normal_effect": {
"2": "addAtk+18",
"4": ""
},
"fight_effect": {
"2": "",
"4": "dmgBonus+30"
},
"group_effect": {
"2": "",
"4": ""
}
},
"教官": {
"normal_effect": {
"2": "elementalMastery+80",
"4": ""
},
"fight_effect": {
"2": "",
"4": "elementalMastery+120"
},
"group_effect": {
"2": "",
"4": "elementalMastery+120"
}
},
"流放者": {
"normal_effect": {
"2": "energyRecharge+20",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"战狂": {
"normal_effect": {
"2": "critRate+12",
"4": ""
},
"fight_effect": {
"2": "",
"4": "critRate+24"
},
"group_effect": {
"2": "",
"4": ""
}
},
"武人": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "AB:dmgBonus+15",
"4": "AB:dmgBonus+25"
},
"group_effect": {
"2": "",
"4": ""
}
},
"学士": {
"normal_effect": {
"2": "energyRecharge+20",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"赌徒": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "E:dmgBonus+20",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"奇迹": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"行者之心": {
"normal_effect": {
"2": "addAtk+18",
"4": ""
},
"fight_effect": {
"2": "",
"4": "B:critRate+30"
},
"group_effect": {
"2": "",
"4": ""
}
},
"守护之心": {
"normal_effect": {
"2": "addDef+30",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"幸运儿": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"冒险家": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"游医": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"祭冰之人": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"祭雷之人": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"祭火之人": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
},
"祭水之人": {
"normal_effect": {
"2": "",
"4": ""
},
"fight_effect": {
"2": "",
"4": ""
},
"group_effect": {
"2": "",
"4": ""
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,266 @@
{
"旅行者": [
"E",
"Q"
],
"胡桃": [
"E",
"Q"
],
"托马": [
"E",
"Q"
],
"宵宫": [
"E",
"Q"
],
"烟绯": [
"E",
"Q"
],
"可莉": [
"E",
"Q"
],
"迪卢克": [
"E",
"Q"
],
"辛焱": [
"E",
"Q"
],
"安柏": [
"Q",
"E"
],
"香菱": [
"Q",
"E"
],
"班尼特": [
"E",
"Q"
],
"珊瑚宫心海": [
"Q",
"E"
],
"达达利亚": [
"E",
"Q"
],
"行秋": [
"Q",
"E"
],
"莫娜": [
"Q",
"E"
],
"芭芭拉": [
"Q",
"E"
],
"申鹤": [
"E",
"Q"
],
"神里绫华": [
"Q",
"E"
],
"优菈": [
"Q",
"E"
],
"甘雨": [
"Q",
"E"
],
"凯亚": [
"E",
"Q"
],
"重云": [
"Q",
"E"
],
"七七": [
"Q",
"E"
],
"迪奥娜": [
"Q",
"E"
],
"罗莎莉亚": [
"E",
"Q"
],
"埃洛伊": [
null,
null
],
"八重神子": [
"E",
"Q"
],
"雷电将军": [
"Q",
"E"
],
"九条裟罗": [
"Q",
"E"
],
"刻晴": [
"Q",
"E"
],
"雷泽": [
"Q",
"E"
],
"菲谢尔": [
"E",
"Q"
],
"丽莎": [
"Q",
"E"
],
"北斗": [
"E",
"Q"
],
"雷主": [
"E",
"Q"
],
"早柚": [
"Q",
"E"
],
"枫原万叶": [
"E",
"Q"
],
"魈": [
"E",
"Q"
],
"温迪": [
"Q",
"E"
],
"琴": [
"Q",
"E"
],
"砂糖": [
"E",
"Q"
],
"风主": [
"E",
"Q"
],
"荒泷一斗": [
"E",
"Q"
],
"五郎": [
"E",
"Q"
],
"阿贝多": [
"E",
"Q"
],
"钟离": [
"E",
"Q"
],
"诺艾尔": [
"E",
"Q"
],
"凝光": [
"Q",
"E"
],
"岩主": [
"E",
"Q"
],
"云堇": [
"Q",
"E"
],
"神里绫人": [
"E",
"Q"
],
"夜兰": [
"Q",
"E"
],
"久岐忍": [
"E",
"Q"
],
"鹿野院平藏": [
"E",
"Q"
],
"柯莱": [
"E",
"Q"
],
"提纳里": [
"Q",
"E"
],
"多莉": [
"E",
"Q"
],
"妮露": [
"Q",
"E"
],
"赛诺": [
"Q",
"E"
],
"坎蒂丝": [
"Q",
"E"
],
"莱依拉": [
"E",
"Q"
],
"纳西妲": [
"E",
"Q"
],
"流浪者": [
"E",
"Q"
],
"珐露珊": [
"E",
"Q"
],
"卡维": [
"Q",
"E"
],
"白术": [
"Q",
"E"
]
}

View File

@ -0,0 +1,364 @@
{
"神里绫人": [
"血量",
"攻击力",
"暴击率",
"暴击伤害",
"元素精通"
],
"八重神子": [
"攻击力",
"暴击率",
"暴击伤害",
"元素精通",
""
],
"申鹤": [
"攻击力",
"元素充能效率"
],
"云堇": [
"防御力",
"元素充能效率"
],
"荒泷一斗": [
"防御力",
"暴击率",
"暴击伤害"
],
"五郎": [
"防御力",
"元素充能效率"
],
"班尼特": [
"血量",
"攻击力",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"枫原万叶": [
"元素精通",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"雷电将军": [
"攻击力",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"行秋": [
"攻击力",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"钟离": [
"血量",
"攻击力",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"神里绫华": [
"攻击力",
"暴击率",
"暴击伤害"
],
"香菱": [
"攻击力",
"暴击率",
"暴击伤害",
"元素充能效率",
"元素精通"
],
"胡桃": [
"血量",
"暴击率",
"暴击伤害",
"元素精通"
],
"甘雨": [
"攻击力",
"暴击率",
"暴击伤害",
"元素精通"
],
"温迪": [
"元素精通",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"珊瑚宫心海": [
"血量",
"元素充能效率"
],
"莫娜": [
"元素精通",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"阿贝多": [
"防御力",
"暴击率",
"暴击伤害"
],
"迪奥娜": [
"血量",
"元素充能效率"
],
"优菈": [
"攻击力",
"暴击率",
"暴击伤害"
],
"达达利亚": [
"攻击力",
"暴击率",
"暴击伤害",
"元素精通"
],
"魈": [
"攻击力",
"暴击率",
"暴击伤害"
],
"宵宫": [
"攻击力",
"暴击率",
"暴击伤害",
"元素精通"
],
"九条裟罗": [
"攻击力",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"琴": [
"攻击力",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"菲谢尔": [
"攻击力",
"暴击率",
"暴击伤害"
],
"罗莎莉亚": [
"攻击力",
"暴击率",
"暴击伤害"
],
"可莉": [
"攻击力",
"暴击率",
"暴击伤害"
],
"凝光": [
"攻击力",
"暴击率",
"暴击伤害"
],
"北斗": [
"攻击力",
"暴击率",
"暴击伤害"
],
"刻晴": [
"攻击力",
"暴击率",
"暴击伤害"
],
"托马": [
"血量",
"元素充能效率"
],
"迪卢克": [
"攻击力",
"暴击率",
"暴击伤害",
"元素精通"
],
"芭芭拉": [
"血量",
"元素充能效率"
],
"诺艾尔": [
"防御力",
"暴击率",
"暴击伤害"
],
"旅行者": [
"攻击力",
"暴击率",
"暴击伤害"
],
"重云": [
"攻击力",
"暴击率",
"暴击伤害"
],
"七七": [
"攻击力",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"凯亚": [
"攻击力",
"暴击率",
"暴击伤害"
],
"烟绯": [
"攻击力",
"暴击率",
"暴击伤害",
"元素精通"
],
"早柚": [
"元素精通",
"元素充能效率"
],
"安柏": [
"攻击力",
"暴击率",
"暴击伤害",
"元素精通"
],
"丽莎": [
"攻击力",
"暴击率",
"暴击伤害"
],
"埃洛伊": [
"攻击力",
"暴击率",
"暴击伤害"
],
"辛焱": [
"攻击力",
"暴击率",
"暴击伤害"
],
"砂糖": [
"元素精通",
"元素充能效率"
],
"雷泽": [
"攻击力",
"暴击率",
"暴击伤害"
],
"夜兰": [
"血量",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"久岐忍": [
"血量",
"元素充能效率",
"元素精通"
],
"鹿野院平藏": [
"攻击力",
"暴击率",
"暴击伤害"
],
"柯莱": [
"元素充能效率",
"元素精通",
"暴击率",
"暴击伤害"
],
"提纳里": [
"攻击力",
"元素精通",
"暴击率",
"暴击伤害"
],
"多莉": [
"元素充能效率",
"血量"
],
"妮露": [
"血量",
"暴击率",
"暴击伤害",
"元素精通"
],
"坎蒂丝": [
"血量",
"元素充能效率",
"暴击率",
"暴击伤害"
],
"赛诺": [
"攻击力",
"暴击率",
"暴击伤害",
"元素精通"
],
"莱依拉": [
"血量",
"元素充能效率"
],
"纳西妲": [
"元素精通",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"流浪者": [
"暴击率",
"暴击伤害",
"攻击力"
],
"珐露珊": [
"攻击力",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"艾尔海森": [
"元素精通",
"暴击率",
"暴击伤害",
"元素充能效率"
],
"瑶瑶": [
"元素充能效率",
"血量",
"攻击力"
],
"迪希雅": [
"血量",
"攻击力",
"暴击率",
"暴击伤害"
],
"米卡": [
"元素充能效率",
"血量"
],
"白术": [
"血量",
"元素充能效率",
"精通",
"暴击率",
"暴击伤害"
],
"卡维": [
"元素充能效率",
"精通",
"暴击率",
"暴击伤害",
"攻击力"
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
import json
from pathlib import Path
from typing import Dict, List, TypedDict
EFFECT_PATH = Path(__file__).parents[1] / 'effect'
class ActionMAP(TypedDict):
name: str
type: str
plus: float
value: List[str]
with open(EFFECT_PATH / 'weapon_effect.json', "r", encoding='UTF-8') as f:
weapon_effect_map: Dict[
str, Dict[str, Dict[str, Dict[str, str]]]
] = json.load(f)
with open(EFFECT_PATH / 'char_effect.json', "r", encoding='UTF-8') as f:
char_effect_map: Dict[
str, Dict[str, Dict[str, Dict[str, str]]]
] = json.load(f)
with open(EFFECT_PATH / 'artifact_effect.json', "r", encoding='UTF-8') as f:
artifact_effect_map: Dict[str, Dict[str, Dict[str, str]]] = json.load(f)
with open(EFFECT_PATH / 'value_attr.json', 'r', encoding='UTF-8') as f:
ATTR_MAP: Dict[str, List[str]] = json.load(f)
with open(EFFECT_PATH / 'char_action.json', 'r', encoding='UTF-8') as f:
char_action: Dict[str, Dict[str, ActionMAP]] = json.load(f)
with open(EFFECT_PATH / 'dmg_map.json', 'r', encoding='UTF-8') as f:
dmgMap = json.load(f)
with open(EFFECT_PATH / 'skill_add.json', 'r', encoding='UTF-8') as f:
avatarName2SkillAdd: Dict[str, List[str]] = json.load(f)
COLOR_MAP = {
'Anemo': (0, 145, 137),
'Cryo': (4, 126, 152),
'Dendro': (28, 145, 0),
'Electro': (133, 12, 159),
'Geo': (147, 112, 3),
'Hydro': (51, 73, 162),
'Pyro': (136, 28, 33),
}

View File

@ -0,0 +1,83 @@
PERCENT_ATTR = ['dmgBonus', 'addAtk', 'addDef', 'addHp']
baseWeaponInfo = {
'itemId': 0,
'nameTextMapHash': '0',
'weaponIcon': 'UI_EquipIcon_Bow_Changed',
'weaponType': '',
'weaponName': '',
'weaponStar': 0,
'promoteLevel': 0,
'weaponLevel': 0,
'weaponAffix': 1,
'weaponStats': [
{
'appendPropId': '',
'statName': '基础攻击力',
'statValue': 0,
},
{
'appendPropId': '',
'statName': '',
'statValue': 0,
},
],
'weaponEffect': '',
}
baseFightProp = {
'hp': 0.0,
'baseHp': 0.0,
'addHp': 0.0,
'exHp': 0.0,
'atk': 0.0,
'baseAtk': 0.0,
'addAtk': 0.0,
'exAtk': 0.0,
'def': 0.0,
'baseDef': 0.0,
'addDef': 0.0,
'exDef': 0.0,
'elementalMastery': 0.0,
'critRate': 0.05,
'critDmg': 0.5,
'energyRecharge': 1.0,
'healBonus': 0.0,
'healedBonus': 0.0,
'physicalDmgSub': 0.0,
'physicalDmgBonus': 0.0,
'dmgBonus': 0.0,
}
ATTR_MAP = {
'元素精通': 'elementalMastery',
'物理伤害加成': 'physicalDmgBonus',
'元素伤害加成': 'dmgBonus',
'充能效率': 'energyRecharge',
'暴击伤害': 'critDmg',
'暴击率': 'critRate',
'攻击力': 'addAtk',
'防御力': 'addDef',
'生命值': 'addHp',
'百分比血量': 'addHp',
}
ELEMENT_MAP = {
'': 'Anemo',
'': 'Cryo',
'': 'Dendro',
'': 'Electro',
'': 'Geo',
'': 'Hydro',
'': 'Pyro',
}
ICON_ELEMENT = {
'': 'Wind',
'': 'Ice',
'': 'Grass',
'': 'Water',
'': 'Electric',
'': 'Rock',
'': 'Fire',
}

View File

@ -0,0 +1,201 @@
from pathlib import Path
from PIL import Image
from .MAP_PATH import ATTR_MAP, dmgMap
R_PATH = Path(__file__).parents[1]
TEXT_PATH = R_PATH / 'texture2D'
SCORE_MAP = {
'暴击率': 2,
'暴击伤害': 1,
'元素精通': 0.25,
'元素充能效率': 0.65,
'百分比血量': 0.86,
'百分比攻击力': 1,
'百分比防御力': 0.7,
'血量': 0.014,
'攻击力': 0.12,
'防御力': 0.18,
}
VALUE_MAP = {
'攻击力': 4.975,
'血量': 4.975,
'防御力': 6.2,
'元素精通': 19.75,
'元素充能效率': 5.5,
'暴击率': 3.3,
'暴击伤害': 6.6,
}
def get_star_png(star: int) -> Image.Image:
png = Image.open(TEXT_PATH / 's-{}.png'.format(str(star)))
return png
def strLenth(r: str, size: int, limit: int = 540) -> str:
result = ''
temp = 0
for i in r:
if temp >= limit:
result += '\n' + i
temp = 0
else:
result += i
if i.isdigit():
temp += round(size / 10 * 6)
elif i == '/':
temp += round(size / 10 * 2.2)
elif i == '.':
temp += round(size / 10 * 3)
elif i == '%':
temp += round(size / 10 * 9.4)
else:
temp += size
return result
async def get_artifacts_score(subName: str, subValue: int) -> int:
score = subValue * SCORE_MAP[subName]
return score
async def get_artifacts_value(
subName: str,
subValue: float,
baseAtk: int,
baseHp: int,
baseDef: int,
charName: str,
) -> float:
if charName not in ATTR_MAP:
ATTR_MAP[charName] = ['攻击力', '暴击率', '暴击伤害']
if subName in ATTR_MAP[charName] and subName in ['血量', '防御力', '攻击力']:
if subName == '血量':
base = (subValue / baseHp) * 100
elif subName == '防御力':
base = (subValue / baseDef) * 100
elif subName == '攻击力':
base = (subValue / baseAtk) * 100
else:
base = 1.0
value = float('{:.2f}'.format(base / VALUE_MAP[subName]))
elif subName in ['百分比血量', '百分比防御力', '百分比攻击力']:
subName = subName.replace('百分比', '')
if subName in ATTR_MAP[charName]:
value = float('{:.2f}'.format(subValue / VALUE_MAP[subName]))
else:
return 0
else:
if subName in ATTR_MAP[charName]:
value = float('{:.2f}'.format(subValue / VALUE_MAP[subName]))
else:
value = 0
if charName == '胡桃' and subName == '攻击力':
value = value * 0.4
return value
async def get_all_artifacts_value(
raw_data: dict, baseHp: int, baseAtk: int, baseDef: int, char_name: str
) -> float:
artifactsValue = 0
raw_data = raw_data['equipList']
for aritifact in raw_data:
for i in aritifact['reliquarySubstats']:
subName = i['statName']
subValue = i['statValue']
value_temp = await get_artifacts_value(
subName, subValue, baseAtk, baseHp, baseDef, char_name
)
artifactsValue += value_temp
return artifactsValue
async def get_first_main(mainName: str) -> str:
if '伤害加成' in mainName:
equipMain = mainName[0]
elif '元素' in mainName:
equipMain = mainName[2]
elif '百分比' in mainName:
if '血量' in mainName:
equipMain = ''
else:
equipMain = mainName[3]
else:
equipMain = mainName[0]
return equipMain
async def get_char_std(raw_data: dict, char_name: str) -> dmgMap:
weaponName = raw_data['weaponInfo']['weaponName']
equipMain = ''
for aritifact in raw_data['equipList']:
mainName = aritifact['reliquaryMainstat']['statName']
artifactsPos = aritifact['aritifactPieceName']
if artifactsPos == '时之沙':
equipMain += await get_first_main(mainName)
elif artifactsPos == '空之杯':
equipMain += await get_first_main(mainName)
elif artifactsPos == '理之冠':
equipMain += await get_first_main(mainName)
if 'equipSets' in raw_data:
equipSets = raw_data['equipSets']
else:
artifact_set_list = []
for i in raw_data['equipList']:
artifact_set_list.append(i['aritifactSetsName'])
equipSetList = set(artifact_set_list)
equipSets = {'type': '', 'set': ''}
for equip in equipSetList:
if artifact_set_list.count(equip) >= 4:
equipSets['type'] = '4'
equipSets['set'] = equip
break
elif artifact_set_list.count(equip) == 1:
pass
elif artifact_set_list.count(equip) >= 2:
equipSets['type'] += '2'
equipSets['set'] += equip
if equipSets['type'] in ['2', '']:
seq = ''
else:
seq = '{}|{}|{}'.format(
weaponName.replace('', '').replace('', ''),
equipSets['set'],
equipMain,
)
std_prop = dmgMap[char_name]
seq_temp_a = ''
seq_temp_w = ''
for std_seq in std_prop:
# 如果序列完全相同, 则直接使用这个序列
if std_seq['seq'] == seq:
std = std_seq
break
# 如果不完全相同, 但是杯子的主词条相同, 也可以使用这个
if len(seq) >= 2 and len(std_seq['seq']) >= 2:
if std_seq['seq'][:2] == seq[:2] and seq_temp_w == '':
seq_temp_w = std_seq
if std_seq['seq'][-2] == seq[-2] and seq_temp_a == '':
seq_temp_a = std_seq
else:
# 如果存在备选那就用备选
if seq_temp_w:
std = seq_temp_w
elif seq_temp_a:
std = seq_temp_a
# 不存在则使用第一个
else:
std = dmgMap[char_name][0]
return std

View File

@ -0,0 +1,109 @@
from typing import List, Literal
from ..etc.base_info import ELEMENT_MAP
from .MAP_PATH import char_effect_map, weapon_effect_map, artifact_effect_map
async def get_buff_list(
raw_data: dict,
type: Literal['group', 'normal', 'fight'],
with_talent: bool = True,
) -> List[str]:
all_effect: List[str] = []
# 获取初始数据
char_name = raw_data['avatarName']
# 处理旅行者
if char_name == '旅行者':
for element in ELEMENT_MAP:
if raw_data['avatarElement'] == ELEMENT_MAP[element]:
char_name += f'({element})'
break
char_level = int(raw_data['avatarLevel'])
weaponName = raw_data['weaponInfo']['weaponName']
weaponAffix = raw_data['weaponInfo']['weaponAffix']
main = type
if type == 'group':
main = 'fight'
# 计算武器效果
WEM = weapon_effect_map[weaponName]
weapon_effet = WEM[main][f'{type}_effect'][str(weaponAffix)]
all_effect.append(weapon_effet)
# 计算圣遗物套装
if 'equipSets' in raw_data:
equipSets = raw_data['equipSets']
else:
artifact_set_list = []
for i in raw_data['equipList']:
artifact_set_list.append(i['aritifactSetsName'])
equipSetList = set(artifact_set_list)
equipSets = {'type': '', 'set': ''}
for equip in equipSetList:
if artifact_set_list.count(equip) >= 4:
equipSets['type'] = '4'
equipSets['set'] = equip
break
elif artifact_set_list.count(equip) == 1:
pass
elif artifact_set_list.count(equip) >= 2:
equipSets['type'] += '2'
equipSets['set'] += '|' + equip
if equipSets['set'].startswith('|'):
equipSets['set'] = equipSets['set'][1:]
# 计算圣遗物buff
if equipSets['type'] == '4':
all_effect.append(
artifact_effect_map[equipSets['set']][f'{type}_effect']['2']
)
all_effect.append(
artifact_effect_map[equipSets['set']][f'{type}_effect']['4']
)
elif equipSets['type'] == '2':
all_effect.append(
artifact_effect_map[equipSets['set']][f'{type}_effect']['2']
)
elif equipSets['type'] == '22':
if equipSets['set'][-2] == '':
e = equipSets['set'][-3:]
else:
e = equipSets['set'][-2:]
if equipSets['set'][2] == '':
t = equipSets['set'][:3]
else:
t = equipSets['set'][:2]
for i in artifact_effect_map:
if i.startswith(t):
all_effect.extend(
artifact_effect_map[i][f'{type}_effect']['2'].split(';')
)
elif i.endswith(e):
all_effect.extend(
artifact_effect_map[i][f'{type}_effect']['2'].split(';')
)
# 计算技能buff
if char_name in char_effect_map:
if with_talent:
for talent in char_effect_map[char_name][main][f'{type}_talent']:
if len(raw_data['talentList']) >= int(talent):
all_effect.append(
char_effect_map[char_name][main][f'{type}_talent'][
talent
]
)
# 计算角色buff
for skill in char_effect_map[char_name][main][f'{type}_skill']:
if char_level >= int(skill):
all_effect.append(
char_effect_map[char_name][main][f'{type}_skill'][skill]
)
return all_effect

View File

@ -0,0 +1,433 @@
STATUS_CHAR_LIST = {
'': [
{
'name': 'Q普通攻击/重击/下落攻击伤害提升',
'type': '攻击力',
'plus': 1,
'value': [
'58.5%',
'61.9%',
'65.5%',
'70.0%',
'73.5%',
'77.0%',
'81.6%',
'86.1%',
'90.6%',
'95.2%',
'99.8%',
'104.3%',
'108.9%',
'113.4%',
'117.9%',
],
'effect': 'ABC:dmgBonus+{}',
}
],
'诺艾尔': [
{
'name': 'Q攻击力提高',
'type': '防御',
'plus': 1,
'value': [
'40%',
'43%',
'46%',
'50%',
'53%',
'56%',
'60%',
'64%',
'68%',
'72%',
'76%',
'80%',
'85%',
'90%',
'95%',
],
'effect': 'exAtk+{}def',
}
],
'胡桃': [
{
'name': 'E攻击力提高',
'type': '生命值',
'plus': 1,
'value': [
'3.84%',
'4.07%',
'4.30%',
'4.60%',
'4.83%',
'5.06%',
'5.36%',
'5.66%',
'5.96%',
'6.26%',
'6.55%',
'6.85%',
'7.15%',
'7.45%',
'7.75%',
],
'effect': 'exAtk+{}hp',
}
],
'烟绯': [
{
'name': 'Q重击伤害提升',
'type': '攻击力',
'plus': 1,
'value': [
'33%',
'35%',
'37%',
'40%',
'42%',
'44%',
'47%',
'49%',
'52%',
'54%',
'57%',
'60%',
'62%',
'65%',
'67%',
],
'effect': 'B:dmgBonus+{}',
}
],
'珊瑚宫心海': [
{
'name': 'Q普通攻击伤害提高',
'type': '生命值',
'plus': 1,
'value': [
'4.8%',
'5.2%',
'5.6%',
'6.0%',
'6.4%',
'6.8%',
'7.3%',
'7.7%',
'8.2%',
'8.7%',
'9.2%',
'9.7%',
'10.3%',
'10.9%',
'11.5%',
],
'effect': 'A:addDmg+{}hp',
},
{
'name': 'Q重击伤害提高',
'type': '生命值',
'plus': 1,
'value': [
'6.8%',
'7.3%',
'7.8%',
'8.5%',
'9.0%',
'9.5%',
'10.2%',
'10.8%',
'11.5%',
'12.2%',
'12.9%',
'13.6%',
'14.4%',
'15.2%',
'16.1%',
],
'effect': 'B:addDmg+{}hp',
},
{
'name': 'Q化海月伤害提高',
'type': '生命值',
'plus': 1,
'value': [
'7.1%',
'7.6%',
'8.2%',
'8.9%',
'9.4%',
'9.9%',
'10.6%',
'11.4%',
'12.1%',
'12.8%',
'13.5%',
'14.2%',
'15.1%',
'16.0%',
'16.9%',
],
'effect': 'E:addDmg+{}hp',
},
],
'荒泷一斗': [
{
'name': 'Q攻击力提高',
'type': '防御',
'plus': 1,
'value': [
'57.6%',
'61.9%',
'66.2%',
'72.0%',
'76.3%',
'80.6%',
'86.4%',
'92.2%',
'97.9%',
'103.7%',
'109.4%',
'115.2%',
'122.4%',
'129.6%',
'136.8%',
],
'effect': 'exAtk+{}def',
}
],
'宵宫': [
{
'name': 'A普通攻击伤害提升',
'type': '攻击力',
'plus': 1,
'value': [
1.3790899515151978,
1.4017900228500366,
1.424489974975586,
1.4539999961853027,
1.476699948310852,
1.499400019645691,
1.5289100408554077,
1.558419942855835,
1.5879299640655518,
1.6174399852752686,
1.6469500064849854,
1.6764600276947021,
1.705970048904419,
1.7354799509048462,
1.764989972114563,
],
'effect': 'A:baseArea+{}',
}
],
'流浪者': [
{
'name': 'A普通攻击伤害提升',
'type': '攻击力',
'plus': 1,
'value': [
1.3298250436782837,
1.3495750427246094,
1.369325041770935,
1.3949999809265137,
1.4147499799728394,
1.434499979019165,
1.4601750373840332,
1.4858499765396118,
1.51152503490448,
1.5371999740600586,
1.5628750324249268,
1.5885499715805054,
1.6142250299453735,
1.6398999691009521,
1.6655750274658203,
],
'effect': 'A:baseArea+{}',
},
{
'name': 'A普通攻击伤害提升',
'type': '攻击力',
'plus': 1,
'value': [
1.2638599872589111,
1.2796599864959717,
1.2954599857330322,
1.315999984741211,
1.3317999839782715,
1.347599983215332,
1.3681399822235107,
1.3886799812316895,
1.4092199802398682,
1.4297599792480469,
1.4502999782562256,
1.4708399772644043,
1.491379976272583,
1.5119199752807617,
1.5324599742889404,
],
'effect': 'B:baseArea+{}',
},
],
'神里绫人': [
{
'name': 'Q普通攻击伤害提升',
'type': '攻击力',
'plus': 1,
'value': [
'11.0%',
'12.0%',
'13.0%',
'14.0%',
'15.0%',
'16.0%',
'17.0%',
'18.0%',
'19.0%',
'20.0%',
'20.0%',
'20.0%',
'20.0%',
'20.0%',
'20.0%',
],
'effect': 'A:dmgBonus+{}',
},
{
'name': 'E浪闪',
'type': '生命值',
'plus': 4,
'value': [
0.005611000116914511,
0.006066999863833189,
0.006523999851197004,
0.0071760001592338085,
0.007633000146597624,
0.008155000396072865,
0.00887299980968237,
0.009589999914169312,
0.01030800025910139,
0.011091000400483608,
0.011873999610543251,
0.012656999751925468,
0.013438999652862549,
0.014221999794244766,
0.015004999935626984,
],
'effect': '瞬水剑:addDmg+{}hp',
},
],
}
EXTRA_CHAR_LIST = {
'雷电将军': {
"Q愿力加成": {
"type": "攻击",
"plus": 1,
"value": [
"3.89+0.73",
"4.18+0.78",
"4.47+0.84",
"4.86+0.91",
"5.15+0.96",
"5.44+1.02",
"5.83+1.09",
"6.22+1.16",
"6.61+1.23",
"7.00+1.31",
"7.39+1.38",
"7.78+1.45",
"8.26+1.54",
"8.75+1.63",
"9.23+1.72",
],
},
'Q伤害提升': {
"type": "攻击",
"plus": 1,
'value': [
0.002199999988079071,
0.002300000051036477,
0.002400000113993883,
0.0024999999441206455,
0.0026000000070780516,
0.0027000000700354576,
0.00279999990016222,
0.002899999963119626,
0.003000000026077032,
0.003000000026077032,
0.003000000026077032,
0.003000000026077032,
0.003000000026077032,
0.003000000026077032,
0.003000000026077032,
],
},
},
'优菈': {
"Q每层能量伤害": {
"type": "攻击",
"plus": 1,
'value': [
0.7499200105667114,
0.8109599947929382,
0.871999979019165,
0.9592000246047974,
1.0202399492263794,
1.090000033378601,
1.185920000076294,
1.2818399667739868,
1.3777600526809692,
1.4823999404907227,
1.6023000478744507,
1.7433019876480103,
1.8843050003051758,
2.0253069400787354,
2.1791279315948486,
],
}
},
'纳西妲': {
"E灭净三业伤害提升0": {
"type": "攻击",
"plus": 1,
'value': [
0.14880000054836273,
0.15996000170707703,
0.17112000286579132,
0.1860000044107437,
0.197160005569458,
0.2083200067281723,
0.2231999933719635,
0.2380799949169159,
0.2529599964618683,
0.2678399980068207,
0.28271999955177307,
0.29760000109672546,
0.31619998812675476,
0.33480000495910645,
0.35339999198913574,
],
},
"E灭净三业伤害提升1": {
"type": "攻击",
"plus": 1,
'value': [
0.2231999933719635,
0.23994000256061554,
0.2566800117492676,
0.27900001406669617,
0.295740008354187,
0.31248000264167786,
0.33480000495910645,
0.35712000727653503,
0.3794400095939636,
0.4017600119113922,
0.4240800142288208,
0.446399986743927,
0.47429999709129333,
0.5022000074386597,
0.5300999879837036,
],
},
},
}

View File

@ -0,0 +1,270 @@
import re
import json
from typing import Dict, List, Tuple, Union, Optional
from nonebot.log import logger
from .draw_char_card import draw_char_img
from .draw_group_dmg import draw_group_dmg_img
from .mono.Character import Character, get_char
from ..utils.message.error_reply import CHAR_HINT
from ..utils.enka_api.enka_to_card import draw_enka_card
from ..utils.alias.alias_to_char_name import alias_to_char_name
from ..utils.alias.enName_to_avatarId import avatarId_to_enName
from ..utils.download_resource.RESOURCE_PATH import PLAYER_PATH
from ..utils.enka_api.map.GS_MAP_PATH import avatarName2Element
from ..utils.alias.avatarId_and_name_covert import name_to_avatar_id
CHAR_TO_INT = {
'': 0,
'': 1,
'': 2,
'': 3,
'': 4,
'': 5,
'': 6,
'': 6,
}
WEAPON_TO_INT = {
'': 1,
'': 2,
'': 3,
'': 4,
'': 5,
'': 5,
}
async def draw_enka_img(
raw_mes: str, uid: str, url: Optional[str]
) -> Union[str, Tuple[Union[bytes, str], Optional[bytes]]]:
# 获取角色名
msg = ' '.join(re.findall('[\u4e00-\u9fa5]+', raw_mes))
# msg = raw_mes.strip()
# 判断是否开启成长曲线或最佳, 并且去除
is_curve = False
is_group = False
if '成长曲线' in msg or '曲线' in msg:
is_curve = True
msg = msg.replace('成长曲线', '').replace('曲线', '')
if '队伍' in msg or '队伍伤害' in msg:
is_group = True
msg = msg.replace('队伍', '').replace('伤害', '').strip()
if '展柜角色' in msg:
sc = await get_showcase(uid)
if isinstance(sc, str):
return sc
return sc, None
msg_list = msg.split(' ')
char_list = []
for msg in msg_list:
_args = await get_char_args(msg, uid)
if isinstance(_args, str):
return _args
else:
if isinstance(_args[0], str):
return _args[0]
if is_group:
char = await get_char(*_args)
char_list.append(char)
else:
break
else:
im = await draw_group_dmg_img(uid, char_list)
if isinstance(im, str):
return im
return im, None
char = await get_char(*_args)
if isinstance(char, str):
logger.info('[查询角色] 绘图失败, 替换的武器不正确!')
return char
im = await draw_char_img(char, url, is_curve)
logger.info('[查询角色] 绘图完成,等待发送...')
return im
async def get_char_data(uid: str, char_name: str) -> Union[Dict, str]:
player_path = PLAYER_PATH / str(uid)
if '旅行者' in char_name:
char_name = '旅行者'
else:
char_name = await alias_to_char_name(char_name)
char_path = player_path / f'{char_name}.json'
if char_path.exists():
with open(char_path, 'r', encoding='utf8') as fp:
char_data = json.load(fp)
else:
return CHAR_HINT.format(char_name)
return char_data
async def get_showcase(uid: str) -> Union[bytes, str]:
player_path = PLAYER_PATH / str(uid)
char_file_list = player_path.glob('*')
char_list = []
for i in char_file_list:
file_name = i.name
if '\u4e00' <= file_name[0] <= '\u9fff':
char_list.append(file_name.split('.')[0])
if char_list == []:
return '您还没有已缓存的角色噢~\n请先使用[强制刷新]命令缓存~'
img = await draw_enka_card(uid=uid, char_list=char_list)
return img
async def change_equip(
uid: str, char_data: Dict, part: str, s: str, i: int
) -> Dict:
char_name = part.replace(part[-1], '')
fake_data = await get_char_data(uid, char_name)
if isinstance(fake_data, str):
return {}
for equip in fake_data['equipList']:
if equip['aritifactPieceName'] == s:
char_data['equipList'][i] = equip
break
return char_data
async def get_char_args(
msg: str, uid: str
) -> Union[Tuple[Dict, Optional[str], Optional[int], Optional[int]], str]:
# 可能进来的值
# 六命公子带天空之卷换可莉圣遗物换刻晴羽换可莉花
# 六命公子带天空之卷换刻晴羽
# 公子换刻晴羽
fake_name = ''
talent_num = None
char_data = {}
weapon, weapon_affix = None, None
msg = msg.replace('', '').replace('', '')
# 公子带天空之卷换可莉圣遗物
msg_list = msg.split('')
for index, part in enumerate(msg_list):
# 判断主体
if index == 0:
fake_name, talent_num = await get_fake_char_str(part)
# 判断是否开启fake_char
if '圣遗物' in msg:
char_data = await get_fake_char_data(char_data, fake_name, uid)
else:
char_data = await get_char_data(uid, fake_name)
if isinstance(char_data, str):
return char_data
continue
if '圣遗物' in part:
fake_data = await get_char_data(uid, part.replace('圣遗物', ''))
if isinstance(fake_data, str):
return fake_data
char_data = await get_fake_char_data(fake_data, fake_name, uid)
if isinstance(char_data, str):
return char_data
else:
for i, s in enumerate(['生之花', '死之羽', '时之沙', '空之杯', '理之冠']):
if '赤沙' in part:
continue
if part[-1] == s[-1]:
if isinstance(char_data, str):
return char_data
char_data = await change_equip(uid, char_data, part, s, i)
if not char_data:
return '要替换的部件不存在噢~'
break
else:
weapon, weapon_affix = await get_fake_weapon_str(part)
return char_data, weapon, weapon_affix, talent_num
async def get_single_percent(char_data: Dict, uid: str, num: int, best: List):
char = Character(char_data)
await char.init_prop()
percent = float(char.percent.replace('%', ''))
logger.info(f'[查找最佳圣遗物] UID:{uid}{num}次迭代...毕业度为{percent}!')
best.append({'percent': percent, 'char_data': char.card_prop})
async def get_artifacts_repo(uid: str) -> Dict[str, List[Dict]]:
artifacts_repo = {
'flower': [],
'plume': [],
'sands': [],
'goblet': [],
'circlet': [],
}
logger.info(f'[建立圣遗物仓库] UID:{uid}开始...')
# 开始查找全部角色
uid_fold = PLAYER_PATH / str(uid)
char_file_list = uid_fold.glob('*')
for i in char_file_list:
if '\u4e00' <= i.name[0] <= '\u9fff':
with open(uid_fold / f'{i.name}', 'r', encoding='UTF-8') as f:
raw_data = json.load(f)
for equip in raw_data['equipList']:
if equip not in artifacts_repo[equip['aritifactSetPiece']]:
artifacts_repo[equip['aritifactSetPiece']].append(equip)
logger.info(
f'[建立圣遗物仓库] UID:{uid}完成!共计\
{len(artifacts_repo["flower"])},\
{len(artifacts_repo["plume"])},\
{len(artifacts_repo["sands"])},\
{len(artifacts_repo["goblet"])},\
{len(artifacts_repo["circlet"])}个圣遗物!'
)
return artifacts_repo
async def get_fake_char_data(
char_data: Dict, fake_name: str, uid: str
) -> Union[Dict, str]:
fake_name = await alias_to_char_name(fake_name)
original_data = await get_char_data(uid, fake_name)
if isinstance(original_data, Dict):
char_data['weaponInfo'] = original_data['weaponInfo']
char_data['avatarName'] = fake_name
char_data['avatarId'] = await name_to_avatar_id(fake_name)
en_name = await avatarId_to_enName(char_data['avatarId'])
char_data['avatarEnName'] = en_name
if fake_name in avatarName2Element:
char_data['avatarElement'] = avatarName2Element[fake_name]
else:
return '要查询的角色不存在...'
char_data['avatarLevel'] = '90'
char_data['avatarSkill'] = [
{'skillLevel': 10, 'skillIcon': 'Skill_A_02'},
{'skillLevel': 10, 'skillIcon': f'Skill_S_{en_name}_01'},
{'skillLevel': 10, 'skillIcon': f'Skill_E_{en_name}_01'},
]
return char_data
async def get_fake_char_str(char_name: str) -> Tuple[str, Optional[int]]:
'''
获取一个角色信息
'''
talent_num = None
if '' in char_name and char_name[0] in CHAR_TO_INT:
talent_num = CHAR_TO_INT[char_name[0]]
char_name = char_name[2:]
return char_name, talent_num
async def get_fake_weapon_str(msg: str) -> Tuple[str, Optional[int]]:
weapon_affix = None
if '' in msg and msg[1] in WEAPON_TO_INT:
weapon_affix = WEAPON_TO_INT[msg[1]]
weapon = msg[2:]
else:
weapon = msg
return weapon, weapon_affix

View File

@ -0,0 +1,897 @@
from copy import deepcopy
from typing import Dict, List, Tuple, Optional
from nonebot.log import logger
from .Power import sp_prop
from ..etc.get_buff_list import get_buff_list
from ...utils.db_operation.db_operation import config_check
from ..etc.status_change import EXTRA_CHAR_LIST, STATUS_CHAR_LIST
from ...utils.alias.avatarId_and_name_covert import name_to_avatar_id
from ..etc.MAP_PATH import ActionMAP, char_action, avatarName2SkillAdd
from ...utils.alias.avatarId_to_char_star import avatar_id_to_char_star
from ...utils.minigg_api.get_minigg_data import get_char_info, get_weapon_info
from ...utils.enka_api.map.GS_MAP_PATH import (
avatarName2Weapon,
avatarName2Element,
)
from ...utils.ambr_api.convert_ambr_data import (
convert_ambr_to_minigg,
convert_ambr_to_weapon,
)
from ..etc.base_info import (
ATTR_MAP,
ELEMENT_MAP,
ICON_ELEMENT,
PERCENT_ATTR,
baseFightProp,
baseWeaponInfo,
)
class Character:
def __init__(self, card_prop: Dict):
# 面板数据
self.card_prop: Dict = card_prop
# 无命座效果
self.without_talent_card = card_prop
# 战斗数据
self.fight_prop: Dict[str, float] = {}
# 战斗数据
self.without_talent_fight: Dict[str, float] = {}
# 实时数据
self.real_prop: Dict[str, float] = {}
# 角色等级,名称,元素,武器类型
self.char_level: int = int(card_prop['avatarLevel'])
self.char_id: str = '10000029'
self.char_name: str = card_prop['avatarName']
self.char_element = self.card_prop['avatarElement']
self.char_fetter = self.card_prop['avatarFetter']
self.char_talent: int = len(self.card_prop['talentList'])
self.weapon_type = self.card_prop['weaponInfo']['weaponType']
self.char_bytes: Optional[bytes] = None
self.rarity: str = '4'
self.power_name: str = ''
self.attack_type: str = ''
# 角色的圣遗物总分
self.artifacts_all_score: float = 0
self.percent: str = '0.0'
self.dmg_data: Dict = {}
self.seq_str: str = '无匹配'
# 特殊
self.sp_list: List = []
self.sp: sp_prop = sp_prop()
self.extra_effect: Dict = {}
self.time: float = 0
self.buff: List = []
self.enemy_debuff: List = []
self.power_list: Dict[str, ActionMAP] = {}
# 处理旅行者
self.s_char_name = self.char_name
if self.char_name == '旅行者':
for element in ELEMENT_MAP:
if self.char_element == ELEMENT_MAP[element]:
self.s_char_name += f'({element})'
break
async def new(
self,
weapon: Optional[str] = None,
weapon_affix: Optional[int] = None,
talent_num: Optional[int] = None,
):
'''
<初始化角色 - 1>
<新生成角色的基础属性>
如果要替换武器也在这边进行处理
参数:
weapon: `Optional[str]`
武器名称(fake)
weapon_affix: `Optional[int]`
武器精炼次数(fake)
talent_num: `Optional[int]`
命座数量(fake)
'''
if not await config_check('OldPanle'):
self.card_prop = await self.get_card_prop(
weapon, weapon_affix, talent_num
)
if self.card_prop == {}:
return '要替换的武器不正确或发生了未知错误~'
self.baseHp = self.card_prop['avatarFightProp']['baseHp']
self.baseAtk = self.card_prop['avatarFightProp']['baseAtk']
self.baseDef = self.card_prop['avatarFightProp']['baseDef']
self.rarity = await avatar_id_to_char_star(
str(self.card_prop['avatarId'])
)
self.char_id = await name_to_avatar_id(self.char_name)
async def get_card_prop(
self,
weapon: Optional[str] = None,
weapon_affix: Optional[int] = None,
talent_num: Optional[int] = None,
) -> dict:
# 创造一个假武器
if weapon:
weapon_info = deepcopy(baseWeaponInfo)
weapon_raw_data = await get_weapon_info(weapon)
if 'retcode' in weapon_raw_data:
weapon_raw_data = await convert_ambr_to_weapon(weapon)
if not weapon_raw_data:
return {}
weapon_info['weaponStar'] = int(weapon_raw_data['rarity'])
if 'level' in weapon_raw_data:
weapon_level_data = weapon_raw_data
weapon_info['weaponLevel'] = 90
weapon_info['promoteLevel'] = 6
else:
if weapon_info['weaponStar'] >= 3:
weapon_level_data = await get_weapon_info(weapon, '90')
weapon_info['weaponLevel'] = 90
weapon_info['promoteLevel'] = 6
else:
weapon_level_data = await get_weapon_info(weapon, '70')
weapon_info['weaponLevel'] = 70
weapon_info['promoteLevel'] = 4
weapon_info['weaponName'] = weapon_raw_data['name']
if weapon_affix is None:
if weapon_info['weaponStar'] >= 5:
weapon_info['weaponAffix'] = 1
else:
weapon_info['weaponAffix'] = 5
else:
weapon_info['weaponAffix'] = weapon_affix
weapon_info['weaponStats'][0]['statValue'] = round(
weapon_level_data['attack']
)
if weapon_raw_data['substat'] != '':
weapon_info['weaponStats'][1]['statName'] = weapon_raw_data[
'substat'
]
if weapon_raw_data['substat'] == '元素精通':
fake_value = round(weapon_level_data['specialized'])
else:
fake_value = float(
'{:.2f}'.format(weapon_level_data['specialized'] * 100)
)
weapon_info['weaponStats'][1]['statValue'] = fake_value
if 'effect' in weapon_raw_data:
weapon_info['weaponEffect'] = weapon_raw_data['effect'].format(
*weapon_raw_data[
'r{}'.format(str(weapon_info['weaponAffix']))
]
)
else:
weapon_info['weaponEffect'] = '无特效。'
weapon_info['weaponType'] = weapon_raw_data['weapontype']
self.card_prop['weaponInfo'] = weapon_info
# 修改假命座:
if self.s_char_name.startswith('旅行者'):
icon_name = f'Player{ICON_ELEMENT[self.s_char_name[-2]]}'
else:
icon_name = self.card_prop['avatarEnName']
if talent_num is None:
talent_num = len(self.card_prop['talentList'])
if talent_num or talent_num == 0:
talent_list = []
for i in range(1, talent_num + 1):
talent_list.append(
{
'talentId': 300 + i,
'talentName': f'FakeTalent{i}',
'talentIcon': f'UI_Talent_S_{icon_name}_0{i}',
}
)
self.card_prop['talentList'] = talent_list
fight_prop = await self.get_base_prop(self.char_name, self.char_level)
self.card_prop['avatarFightProp'] = fight_prop
self.without_talent_card = self.card_prop
# 计算圣遗物效果
all_effects = await get_artifacts_value(self.card_prop)
part_effects = deepcopy(all_effects)
all_effects.extend(await get_buff_list(self.card_prop, 'normal'))
part_effects.extend(
await get_buff_list(self.card_prop, 'normal', False)
)
fight_prop_part = await self.get_effect_prop(
deepcopy(fight_prop), part_effects, self.char_name
)
fight_prop_all = await self.get_effect_prop(
deepcopy(fight_prop), all_effects, self.char_name
)
self.card_prop['avatarFightProp'] = fight_prop_all
self.without_talent_card['avatarFightProp'] = fight_prop_part
return self.card_prop
async def get_base_prop(self, char_name: str, char_level: int) -> Dict:
# 武器基本属
weapon_atk = self.card_prop['weaponInfo']['weaponStats'][0][
'statValue'
]
if len(self.card_prop['weaponInfo']['weaponStats']) > 1:
weapon_sub = self.card_prop['weaponInfo']['weaponStats'][1][
'statName'
]
weapon_sub_val = self.card_prop['weaponInfo']['weaponStats'][1][
'statValue'
]
else:
weapon_sub = ''
weapon_sub_val = 0
fight_prop = deepcopy(baseFightProp)
if '珊瑚宫心海' == char_name:
fight_prop['critRate'] -= 1.0
fight_prop['healBonus'] += 0.25
char_name_covert = char_name
if char_name == '旅行者':
char_name_covert = ''
char_raw = await get_char_info(name=char_name_covert, mode='char')
self.char_id = await name_to_avatar_id(char_name_covert)
if not self.char_id and char_name != '旅行者':
return {}
if char_raw is not None and 'retcode' in char_raw:
char_raw = char_data = await convert_ambr_to_minigg(self.char_id)
else:
char_data = await get_char_info(
name=char_name_covert, mode='char', level=str(char_level)
)
if char_data is None or isinstance(char_data, List):
return {}
fight_prop['baseHp'] = char_data['hp']
fight_prop['baseAtk'] = char_data['attack'] + weapon_atk
fight_prop['baseDef'] = char_data['defense']
fight_prop['exHp'] = 0
fight_prop['exAtk'] = 0
fight_prop['exDef'] = 0
# 计算突破加成
if isinstance(char_raw, dict):
for attr in ATTR_MAP:
if attr in char_raw['substat']:
sp = char_data['specialized']
if attr == '暴击伤害':
sp -= 0.5
elif attr == '暴击率':
sp -= 0.05
fight_prop[ATTR_MAP[attr]] += sp
if attr in weapon_sub:
if attr == '元素精通':
weapon_sub_val *= 100
fight_prop[ATTR_MAP[attr]] += weapon_sub_val / 100
else:
return {}
return fight_prop
async def init_prop(self):
'''
<初始化角色 - 2>
生成角色的战斗属性和毕业度
'''
await self.get_fight_prop()
async def get_effect_prop(
self,
prop: dict,
effect_list: List[str],
char_name: str,
) -> dict:
logger.debug(effect_list)
if 'A_d' not in prop:
for attr in [
'shieldBonus',
'addDmg',
'addHeal',
'ignoreDef',
'd',
'g',
'a',
]:
prop[attr] = 0
prop['k'] = 1
prop['sp'] = []
prop['baseArea'] = 1
if prop['baseHp'] + prop['addHp'] == prop['hp']:
prop['exHp'] = prop['addHp']
prop['exAtk'] = prop['addAtk']
prop['exDef'] = prop['addDef']
prop['addHp'] = 0
prop['addAtk'] = 0
prop['addDef'] = 0
# 给每个技能 分别添加上属性
for prop_attr in deepcopy(prop):
for prop_limit in ['A', 'B', 'C', 'E', 'Q']:
prop[f'{prop_limit}_{prop_attr}'] = prop[prop_attr]
weapon_type = avatarName2Weapon[char_name]
# 计算角色伤害加成应该使用什么
for prop_limit in ['A', 'B', 'C', 'E', 'Q']:
if weapon_type == '法器' or char_name in [
'荒泷一斗',
'刻晴',
'诺艾尔',
'胡桃',
'宵宫',
'',
'神里绫华',
]:
prop['{}_dmgBonus'.format(prop_limit)] = prop['dmgBonus']
elif weapon_type == '':
if prop_limit in ['A', 'C']:
prop['{}_dmgBonus'.format(prop_limit)] = prop[
'physicalDmgBonus'
]
elif prop_limit in ['B', 'E', 'Q']:
prop['{}_dmgBonus'.format(prop_limit)] = prop[
'dmgBonus'
]
else:
if prop_limit in ['A', 'B', 'C']:
prop['{}_dmgBonus'.format(prop_limit)] = prop[
'physicalDmgBonus'
]
elif prop_limit in ['E', 'Q']:
prop['{}_dmgBonus'.format(prop_limit)] = prop[
'dmgBonus'
]
# 防止复数效果
with_trans_effect: List[str] = []
without_trans_effect: List[str] = []
for effect in effect_list:
if ';' in effect:
effect = effect.split(';')
else:
effect = [effect]
for _effect in effect:
if _effect == '':
continue
else:
if '%' in _effect:
with_trans_effect.append(_effect)
else:
without_trans_effect.append(_effect)
new_effect_list: List[str] = without_trans_effect + with_trans_effect
# 建立一份基于基础属性的effect_list, 确保hp,atk,def有正确的值
base_effect_list: List[List] = []
# 正式开始计算
for effect in new_effect_list:
if 'Resist' in effect:
self.enemy_debuff.append(effect)
continue
else:
self.buff.append(effect)
# 分割效果
# 例如:Q:dmgBonus+96%27%em
# 分割后:
# effect_limit = Q
effect_limit = ''
if ':' in effect:
effect_limit = effect.split(':')[0]
effect = effect.split(':')[1]
effect_attr, effect_value = effect.split('+')
effect_max = 9999999
effect_base: str = ''
# 判断effect_value中有几个百分号
p_count = effect_value.count('%')
# 如果有%,则认为是基于值的提升
base_check = True
if p_count >= 2:
effect_max, effect_value, effect_base = effect_value.split('%')
elif p_count == 1:
effect_value, effect_base = effect_value.split('%')
else:
base_check = False
# effect_attr, effect_value, effect_base, effect_max
# dmgBonus, 27, em, 96
# 暂时不处理extraDmg
if effect_attr == 'extraDmg':
continue
effect_max = float(effect_max) / 100
# 如果要增加的属性不是em元素精通,那么都要除于100
if effect_attr not in [
'exHp',
'exAtk',
'exDef',
'elementalMastery',
]:
# 正常除100
effect_value = float(effect_value) / 100
# 元素精通则为正常值
else:
if effect_base in ['hp', 'elementalMastery', 'def']:
effect_value = float(effect_value) / 100
else:
effect_value = float(effect_value)
# 如果属性是血量,攻击,防御值,并且是按照%增加的,那么增加值应为百分比乘上基础值
if base_check:
if effect_base in ['hp', 'atk', 'def']:
base_effect_list.append(
[effect_limit, effect_attr, effect_value, effect_base]
)
continue
if effect_base == 'energyRecharge':
if effect_attr in PERCENT_ATTR:
effect_base_value = prop[effect_base] - 1
else:
effect_base_value = (prop[effect_base] - 1) / 100
elif effect_base == 'energyrecharge':
effect_base = 'energyRecharge'
if effect_attr in PERCENT_ATTR:
effect_base_value = prop[effect_base]
else:
effect_base_value = prop[effect_base] / 100
elif effect_base == 'elementalMastery':
# 针对草神的
if char_name == '纳西妲' and effect_attr == 'dmgBonus':
effect_base_value = (prop[effect_base] - 200) / 100
else:
effect_base_value = prop[effect_base]
else:
effect_base_value = prop[effect_base]
effect_value = effect_value * effect_base_value
# 判断是否超过上限,超过则使用上限值
if effect_value >= effect_max:
effect_value = effect_max
if char_name == '旅行者':
char_element = 'Hydro'
else:
char_element = avatarName2Element[char_name]
# 判断是否是自己属性的叠加
if 'DmgBonus' in effect_attr:
if effect_attr.replace('DmgBonus', '') == char_element:
effect_attr = 'dmgBonus'
elif effect_attr == 'physicalDmgBonus':
effect_attr = 'physicalDmgBonus'
else:
continue
# 如果效果有限制条件
prop = await self.get_buff_value(
prop,
effect_limit,
effect_attr,
effect_value,
effect_base,
False,
)
prop = await self.get_base_value(prop)
# 重新计算加成值
# base_effect_list = [
# [limit_list, effect_attr, effect_value, effect_base]
# ]
for effect in base_effect_list:
prop = await self.get_buff_value(prop, *effect)
prop = await self.get_base_value(prop)
logger.debug(prop)
return prop
async def get_base_value(self, prop: Dict) -> Dict:
prop['hp'] = (prop['addHp'] + 1) * prop['baseHp'] + prop['exHp']
prop['atk'] = (prop['addAtk'] + 1) * prop['baseAtk'] + prop['exAtk']
prop['def'] = (prop['addDef'] + 1) * prop['baseDef'] + prop['exDef']
for prop_limit in ['A', 'B', 'C', 'E', 'Q']:
for attr in ['hp', 'atk', 'def']:
attr_up = attr[0].upper() + attr[1:]
prop[f'{prop_limit}_{attr}'] = (
prop[f'{prop_limit}_add{attr_up}'] + 1
) * prop[f'base{attr_up}'] + prop[f'ex{attr_up}']
return prop
async def get_buff_value(
self,
prop: Dict,
effect_limit: Optional[str],
effect_attr: str,
effect_value: float,
effect_base: Optional[str] = None,
is_calc_base: Optional[bool] = True,
) -> Dict:
if effect_base and is_calc_base:
effect_value = prop[effect_base] * effect_value
if effect_limit:
# 如果限制条件为中文,则为特殊label才生效
if '\u4e00' <= effect_limit[-1] <= '\u9fff':
prop['sp'].append(
{
'effect_name': effect_limit,
'effect_attr': effect_attr,
'effect_value': effect_value,
}
)
# 如果限制条件为英文,例如Q,则为Q才生效
else:
# 形如ABC:dmgBonus+75,则遍历ABC,增加值
for limit in effect_limit:
prop['{}_{}'.format(limit, effect_attr)] += effect_value
else:
if effect_attr in ['a', 'addDmg']:
pass
else:
for attr in ['A', 'B', 'C', 'E', 'Q']:
prop[f'{attr}_{effect_attr}'] += effect_value
prop[f'{effect_attr}'] += effect_value
logger.debug(f'{effect_attr} + {effect_value} 基于[{effect_base}]')
return prop
async def get_fight_prop(self) -> Dict:
'''
生成角色的倍率表
返回:
self.fight_prop
'''
# 拿到倍率表
if self.s_char_name not in char_action:
self.power_list = {}
else:
self.power_list = char_action[self.s_char_name]
# 额外增加钟离倍率
if self.char_name == '钟离':
self.power_list['E总护盾量'] = {
'name': 'E总护盾量',
'type': '生命值',
'plus': 1.5,
'value': [
f'{self.power_list["E护盾附加吸收量"]["value"][index]}+{i}'
for index, i in enumerate(
self.power_list['E护盾基础吸收量']['value']
)
],
}
elif self.char_name == '赛诺':
for power_name in ['E渡荒之雷', 'E渡荒之雷(超激化)']:
self.power_list[power_name] = {
'name': power_name,
'type': '攻击力',
'plus': 1,
'value': ['100%'] * 15,
}
elif self.char_name == '纳西妲':
for power_name in [
'E业障除(前台)',
'E业障除(蔓激化·前台)',
]:
self.power_list[power_name] = {
'name': power_name,
'type': '攻击力',
'plus': 1,
'value': ['200%+400%'] * 15,
}
elif self.char_name == '甘雨':
for power_name in [
'A霜华矢两段伤害',
'A霜华矢两段伤害(融化)',
]:
self.power_list[power_name] = {
'name': power_name,
'type': '攻击力',
'plus': 1,
'value': [
f'''{
int(i[:-1]) + int(
self.power_list[
"A霜华矢·霜华绽发伤害"
]["value"][index][:-1]
)
}%'''
for index, i in enumerate(
self.power_list['A霜华矢命中伤害']['value']
)
],
}
# 获取值
skillList = self.card_prop['avatarSkill']
prop = deepcopy(self.card_prop['avatarFightProp'])
prop['A_skill_level'] = skillList[0]['skillLevel']
prop['E_skill_level'] = skillList[1]['skillLevel']
prop['Q_skill_level'] = skillList[-1]['skillLevel']
if self.char_name in avatarName2SkillAdd:
skill_add = avatarName2SkillAdd[self.char_name]
else:
skill_add = ['E', 'Q']
for skillAdd_index in range(0, 2):
if len(self.card_prop['talentList']) >= 3 + skillAdd_index * 2:
if skill_add[skillAdd_index] == 'E':
prop['E_skill_level'] += 3
elif skill_add[skillAdd_index] == 'Q':
prop['Q_skill_level'] += 3
prop = await self.get_effect_prop(prop, [], self.char_name)
all_effect = await get_buff_list(self.card_prop, 'fight')
part_effect = await get_buff_list(self.card_prop, 'fight', False)
ex_effect = []
# 开启效果
if self.char_name in STATUS_CHAR_LIST:
for skill_effect in STATUS_CHAR_LIST[self.char_name]:
skill_level = (
prop[f'{skill_effect["name"][0]}_skill_level'] - 1
)
skill_value = skill_effect['value'][skill_level]
plus = skill_effect['plus']
if isinstance(skill_value, float):
skill_value = '{:.4f}%'.format(skill_value * 100 * plus)
skill: str = skill_effect['effect'].format(skill_value)
if skill.endswith('%'):
skill = skill[:-1]
ex_effect.append(skill)
# 特殊效果,目前有雷神满愿力
if self.char_name in EXTRA_CHAR_LIST:
if self.char_name == '雷电将军':
skill1 = EXTRA_CHAR_LIST[self.char_name]['Q愿力加成']['value']
skill2 = EXTRA_CHAR_LIST[self.char_name]['Q伤害提升']['value']
attack_type = 'Q'
skill_level = prop[f'{attack_type}_skill_level'] - 1
value_1 = float(skill1[skill_level].split('+')[0])
value_1 *= 0.6
value_2 = float(skill1[skill_level].split('+')[1])
value_2 *= 0.6
value_3 = skill2[skill_level] * 90
ex_effect.append((f'Q梦想一刀基础伤害:dmgBonus+{value_3}'))
self.extra_effect = {
'Q梦想一刀基础伤害(满愿力)': value_1,
'Q一段伤害(满愿力)': value_2,
'Q重击伤害(满愿力)': value_2,
'Q高空下落伤害(满愿力)': value_2,
}
if self.card_prop['weaponInfo']['weaponName'] == '薙草之稻光':
weaponAffix = self.card_prop['weaponInfo']['weaponAffix']
_ex = 10 + weaponAffix * 2
ex_effect.append(f'Q:dmgBonus+{_ex}')
elif self.char_name == '优菈':
skill_effect = EXTRA_CHAR_LIST[self.char_name]['Q每层能量伤害'][
'value'
]
attack_type = 'Q'
skill_level = prop[f'{attack_type}_skill_level'] - 1
value = float(skill_effect[skill_level])
self.extra_effect = {
'Q光降之剑基础伤害(13层)': value * 13,
'Q光降之剑基础伤害(24层)': value * 24,
}
elif self.char_name == '纳西妲':
self.char_talent = len(self.card_prop['talentList'])
if self.char_talent >= 1:
char_talent = 1
else:
char_talent = 0
skill_effect = EXTRA_CHAR_LIST[self.char_name][
f'E灭净三业伤害提升{char_talent}'
]['value']
attack_type = 'E'
skill_level = prop[f'{attack_type}_skill_level'] - 1
value = float(skill_effect[skill_level])
ex_effect.append((f'前台:dmgBonus+{value*100}'))
# 在计算buff前, 引入特殊效果
if self.char_name == '雷电将军':
ex_effect.append('Q:dmgBonus+27')
elif self.char_name == '钟离':
ex_effect.append('AnemoResist+-20;PhysicalResist+-20')
ex_effect.append('CryoResist+-20;DendroResist+-20')
ex_effect.append('ElectroResist+-20;HydroResist+-20')
ex_effect.append('PyroResist+-20;GeoResist+-20')
elif self.char_name == '妮露':
ex_effect.append('addHp+25')
ex_effect.append('elementalMastery+80')
all_effect.extend(ex_effect)
part_effect.extend(ex_effect)
# 计算全部的buff添加入属性
self.fight_prop = await self.get_effect_prop(
deepcopy(prop), all_effect, self.char_name
)
if self.rarity != '5' and self.char_name != '香菱':
self.without_talent_fight = self.fight_prop
else:
if self.char_name == '香菱':
part_effect.append('exAtk+1202')
self.without_talent_fight = await self.get_effect_prop(
deepcopy(prop), part_effect, self.char_name
)
return self.fight_prop
async def get_sp_fight_prop(self, power_name: str) -> sp_prop:
'''
获得角色的特殊状态战斗加成
返回:
self.sp: `sp_prop`
'''
self.sp = sp_prop()
for sp_single in self.fight_prop['sp']: # type:ignore
if sp_single['effect_name'] in power_name:
if sp_single['effect_attr'] == 'dmgBonus':
self.sp.dmgBonus += sp_single['effect_value']
elif sp_single['effect_attr'] == 'addDmg':
self.sp.addDmg += sp_single['effect_value']
elif sp_single['effect_attr'] == 'atk':
self.sp.attack += sp_single['effect_value']
else:
self.sp.attack += sp_single['effect_value']
return self.sp
async def get_attack_type(self, power_name: str) -> str:
'''
获得角色的当前攻击类型
参数:
power_name: `str`
返回:
self.attack_type: `Literal['A','B','C','E','Q']`
'''
# 攻击类型ABCEQ应为label首位
self.attack_type = power_name[0]
# 如果是雷电将军, 则就按首位,因为Q的几段伤害均视为元素爆发
if self.char_name == '雷电将军':
pass
else:
# 重击或瞄准射击在label内,则视为B重击伤害,例如公子E内的重击伤害,不视为E伤害,而是B伤害
if '重击' in power_name or '瞄准射击' in power_name:
self.attack_type = 'B'
# 特殊重击类型,例如甘雨和夜兰
elif (
'破局矢' in power_name
or '霜华矢' in power_name
or '藏蕴花矢' in power_name
or '花筥箭' in power_name
or '刀风界' in power_name
):
self.attack_type = 'B'
# 下落伤害类型,例如魈
elif '高空下落' in power_name:
self.attack_type = 'C'
# 一段伤害, 二段伤害等等 应视为A伤害
elif '' in power_name and '伤害' in power_name:
self.attack_type = 'A'
elif '不生断' in power_name:
self.attack_type = 'A'
return self.attack_type
async def update(self, time):
self.time += time
# TODO 遍历buff列表, 超过时间的移除
async def p2v(power: str, power_plus: int) -> Tuple[float, float]:
"""
将power转换为value
"""
# 如果存在123%+123%形式的
if '+' in power:
power_percent = (
float(power.split('+')[0].replace('%', '')) / 100
) * power_plus
power_value = power.split('+')[1]
if '%' in power_value:
power_percent += (
float(power_value.replace('%', '')) / 100 * power_plus
)
power_value = 0
else:
power_value = float(power_value)
elif '%' in power:
power_percent = float(power.replace('%', '')) / 100 * power_plus
power_value = 0
else:
power_percent = 0
power_value = float(power)
return power_percent, power_value
async def get_artifacts_value(raw_data: Dict) -> List[str]:
# 计算圣遗物效果
all_effects = []
for equip in raw_data['equipList']:
statNmae = equip['reliquaryMainstat']['statName']
statValue = equip['reliquaryMainstat']['statValue']
all_effects.append(await text_to_effect(statNmae, statValue))
for sub in equip['reliquarySubstats']:
sub_name = sub['statName']
sub_value = sub['statValue']
all_effects.append(await text_to_effect(sub_name, sub_value))
return all_effects
async def text_to_effect(name: str, value: float) -> str:
str = ''
if name == '血量':
str = f'exHp+{value}'
elif name == '百分比血量':
str = f'addHp+{value}'
elif name == '攻击力':
str = f'exAtk+{value}'
elif name == '百分比攻击力':
str = f'addAtk+{value}'
elif name == '防御力':
str = f'exDef+{value}'
elif name == '百分比防御力':
str = f'addDef+{value}'
elif name == '暴击率':
str = f'critRate+{value}'
elif name == '暴击伤害':
str = f'critDmg+{value}'
elif name == '元素精通':
str = f'elementalMastery+{value}'
elif name == '元素充能效率':
str = f'energyRecharge+{value}'
elif name == '物理伤害加成':
str = f'physicalDmgBonus+{value}'
elif '元素伤害加成' in name:
str = f'{ELEMENT_MAP[name[0]]}DmgBonus+{value}'
elif '治疗加成' in name:
str = f'healBonus+{value}'
return str
async def get_char(
raw_data: dict,
weapon: Optional[str] = None,
weapon_affix: Optional[int] = None,
talent_num: Optional[int] = None,
):
char = Character(card_prop=raw_data)
err = await char.new(
weapon=weapon,
weapon_affix=weapon_affix,
talent_num=talent_num,
)
if isinstance(err, str):
return err
await char.init_prop()
return char

View File

@ -0,0 +1,179 @@
from typing import Dict
from enum import IntEnum
class Element(IntEnum):
Physical = 0
Anemo = 1
Cryo = 2
Dendro = 3
Electro = 4
Geo = 5
Hydro = 6
Pyro = 7
# 消耗后面元素量,抵消前面1单位元素量
reactable_elements_dict: Dict[Element, Dict[Element, Dict[str, str]]] = {
# 风反应,被所有元素克制
Element.Anemo: {
Element.Cryo: {
'value': '2',
'reaction': '扩散',
'dmg': '0',
},
Element.Dendro: {
'value': '2',
'reaction': '扩散',
'dmg': '0',
},
Element.Electro: {
'value': '2',
'reaction': '扩散',
'dmg': '0',
},
Element.Hydro: {
'value': '2',
'reaction': '扩散',
'dmg': '0',
},
Element.Pyro: {
'value': '2',
'reaction': '扩散',
'dmg': '0',
},
},
# 冰反应,被火克制,与雷水反应
Element.Cryo: {
Element.Pyro: {
'value': '2',
'reaction': '融化',
'dmg': '2',
},
Element.Electro: {
'value': '2',
'reaction': '超导',
'dmg': '0',
},
Element.Hydro: {
'value': '1',
'reaction': '冻结',
'dmg': '0',
},
},
# 草反应, 火,水,雷
Element.Dendro: {
Element.Hydro: {
'value': '1',
'reaction': '燃烧',
'dmg': '0',
},
Element.Pyro: {
'value': '2',
'reaction': '绽放',
'dmg': '0',
},
Element.Electro: {
'value': '2',
'reaction': '激化',
'dmg': '0',
},
},
# 雷反应, 水,火,冰,草
Element.Electro: {
Element.Hydro: {
'value': '1',
'reaction': '感电',
'dmg': '0',
},
Element.Pyro: {
'value': '1',
'reaction': '超载',
'dmg': '0',
},
Element.Cryo: {
'value': '1',
'reaction': '超导',
'dmg': '0',
},
Element.Dendro: {
'value': '1',
'reaction': '激化',
'dmg': '0',
},
},
# 岩反应,被所有元素克制
Element.Geo: {
Element.Cryo: {
'value': '2',
'reaction': '结晶',
'dmg': '0',
},
Element.Dendro: {
'value': '2',
'reaction': '结晶',
'dmg': '0',
},
Element.Electro: {
'value': '2',
'reaction': '结晶',
'dmg': '0',
},
Element.Hydro: {
'value': '2',
'reaction': '结晶',
'dmg': '0',
},
Element.Pyro: {
'value': '2',
'reaction': '结晶',
'dmg': '0',
},
},
# 水反应,草,火,冰,雷
Element.Hydro: {
Element.Dendro: {
'value': '1',
'reaction': '绽放',
'dmg': '0',
},
Element.Pyro: {
'value': '0.5',
'reaction': '蒸发',
'dmg': '1.5',
},
Element.Cryo: {
'value': '1',
'reaction': '冻结',
'dmg': '0',
},
Element.Electro: {
'value': '1',
'reaction': '感电',
'dmg': '0',
},
},
# 火反应, 雷,水,冰,草
Element.Pyro: {
Element.Dendro: {
'value': '1',
'reaction': '燃烧',
'dmg': '0',
},
Element.Hydro: {
'value': '2',
'reaction': '蒸发',
'dmg': '2',
},
Element.Cryo: {
'value': '0.5',
'reaction': '融化',
'dmg': '1.5',
},
Element.Electro: {
'value': '1',
'reaction': '超载',
'dmg': '0',
},
},
}

View File

@ -0,0 +1,160 @@
from typing import Dict, List, Optional
from .Character import Character
from .Element import Element, reactable_elements_dict
class Enemy:
def __init__(self, char_level: int, enemy_level: int):
self.char_level = char_level
self.level: int = enemy_level
self.hp: int = 10000000
self.time: float = 0
self.defense_resist: float = 0
self.ignore_defense: float = 0
self.element: Dict[Element, float] = {}
self.PhysicalResist: float = 0.1
self.AnemoResist: float = 0.1
self.CryoResist: float = 0.1
self.DendroResist: float = 0.1
self.ElectroResist: float = 0.1
self.GeoResist: float = 0.1
self.HydroResist: float = 0.1
self.PyroResist: float = 0.1
self.total_dmg: float = 0
self.debuff: List = []
async def update(self, time):
self.time += time
# TODO 遍历debuff列表, 超过时间的移除
async def update_resist(self, effect: str):
name, val = effect.split('+')
val = float(val) / 100
if name != 'Resist':
r = getattr(self, name)
setattr(self, name, r + val)
else:
for element in self.element:
r = getattr(self, f'{element.name}Resist')
setattr(self, name, r + val)
async def get_dmg_reaction(
self,
dmg_type: Optional[Element] = None,
char: Optional[Character] = None,
) -> float:
if char:
for react in ['蒸发', '融化']:
if react in char.power_name:
em = char.real_prop[f'{char.attack_type}_elementalMastery']
k = 0
if react == '蒸发':
if char.char_element == 'Pyro':
k = 1.5
else:
k = 2
elif react == '融化':
if char.char_element == 'Pyro':
k = 2
else:
k = 1.5
reaction_add_dmg = k * (
1 + (2.78 * em) / (em + 1400) + char.real_prop['a']
)
break
else:
reaction_add_dmg = 1
return reaction_add_dmg
else:
if dmg_type:
reaction: float = 1
# 如果是物理伤害,则不反应
if dmg_type == Element.Physical:
return 1
# 如果怪物头上没元素,给定此次伤害类型元素量1
if self.element == {}:
self.element[dmg_type] = 1
# 如果怪物头上元素相同,则刷新元素量
elif dmg_type in self.element:
self.element[dmg_type] = 1
else:
# 遍历怪物头上的元素
new_element_list = self.element
for element in self.element:
# 如果本次伤害类型,在这个元素的可反应列表里
if dmg_type in reactable_elements_dict[element]:
# 元素列表里的这个元素 就要减去反应量
new_element_list[element] -= float(
reactable_elements_dict[element][dmg_type][
'value'
]
)
# 如果是增幅反应,给出相对应的倍率
reaction_name = reactable_elements_dict[element][
dmg_type
]['reaction']
if reaction_name in [
'蒸发',
'融化',
]:
reaction *= float(
reactable_elements_dict[element][dmg_type][
'dmg'
]
)
else:
self.debuff.append(reaction_name)
# 结算怪物的元素
result_element: Dict[Element, float] = {}
for element in new_element_list:
if new_element_list[element] > 0:
result_element[element] = new_element_list[element]
self.element = result_element
return reaction
return 1
async def get_resist(self, dmg_type: Element):
# 计算抗性
r = getattr(self, f'{dmg_type.name}Resist')
if r > 0.75:
r = 1 / (1 + 4 * r)
elif r > 0:
r = 1 - r
else:
r = 1 - r / 2
return r
async def get_dmg_proof(
self,
dmg_type: Element,
extra_d: float = 0,
extra_ignoreD: float = 0,
) -> float:
proof: float = 0
# 计算抗性
r = await self.get_resist(dmg_type)
# 计算防御
d_up = self.char_level + 100
d_down = (
self.char_level
+ 100
+ (1 - self.defense_resist - extra_d)
* (1 - self.ignore_defense - extra_ignoreD)
* (self.level + 100)
)
d = d_up / d_down
proof = r * d
# 返回减伤百分比
return proof

View File

@ -0,0 +1,514 @@
from copy import deepcopy
from typing import Dict, List, Tuple, Optional
from nonebot.log import logger
from .Enemy import Enemy
from .Power import Power
from .Element import Element
from .Character import Character
from ..dmg_calc.base_value import base_value_list
class Fight:
def __init__(
self,
Character_list: Dict[str, Character],
Enemy: Enemy,
SEQ: List = [],
):
self.time = 0
self.total_crit_dmg: float = 0
self.total_normal_dmg: float = 0
self.total_avg_dmg: float = 0
self.SEQ: List = SEQ
self.seq_history: Dict = {}
self.char_list: Dict[str, Character] = Character_list
self.enemy = Enemy
self.dmg_data: Dict[str, Dict[str, float]] = {}
# 进行队伍伤害计算
async def update_dmg(self) -> Dict:
result = {}
for seq in self.SEQ:
# 获取本次攻击的信息
char_name = seq['char']
char = self.char_list[char_name]
char.power_name = seq['action']
self.time += 0.4
# 更新角色和怪物
for _char in self.char_list:
await self.char_list[_char].update(self.time)
await self.enemy.update(self.time)
# 获取本次攻击的类型
await char.get_sp_fight_prop(char.power_name)
await char.get_attack_type(char.power_name)
# 获取本次攻击的元素
dmg_type = await self.get_dmg_type(char, seq)
# 更新角色的属性
await self.get_new_fight_prop(char)
# 更新self.seq_history
self.seq_history = seq
# 聚变反应
for i in ['扩散', '绽放)', '感电', '超载']:
if i in char.power_name:
dmg = await self.get_transform_dmg(char)
break
else:
# 进行攻击
dmg = await self.get_dmg(char, dmg_type)
normal_dmg, avg_dmg, crit_dmg = dmg[0], dmg[1], dmg[2]
result[self.time] = {
'char': char_name,
'action': seq['action'],
'normal_dmg': normal_dmg,
'avg_dmg': avg_dmg,
'crit_dmg': crit_dmg,
'enemy_element': self.enemy.element,
}
logger.debug(result)
return result
# 进行单人伤害计算
async def get_dmg_dict(
self, char_name: str, without_talent: bool = False
) -> Dict:
result = {}
char = self.char_list[char_name]
# 获取本次攻击的类型
if without_talent:
if char.rarity == '4' and char_name != '香菱':
return self.dmg_data
char.fight_prop = char.without_talent_fight
for power_name in char.power_list:
# 更新powername
char.power_name = power_name
await char.get_sp_fight_prop(char.power_name)
await char.get_attack_type(char.power_name)
# 更新角色的属性
await self.get_new_fight_prop(char)
# 聚变反应
for i in ['扩散', '绽放)', '感电', '超载']:
if i in power_name:
dmg = await self.get_transform_dmg(char)
break
else:
dmg = []
# 正常伤害
if not dmg:
if '治疗' in power_name or '回复' in power_name:
dmg = await self.get_heal(char)
elif '护盾' in power_name:
dmg = await self.get_shield(char)
else:
# 获取本次攻击的元素
dmg_type = await self.get_dmg_type(char)
dmg = await self.get_dmg(char, dmg_type, True)
# 得到结果
result[power_name] = {
'normal': dmg[0],
'avg': dmg[1],
'crit': dmg[2],
}
self.dmg_data = result
logger.debug(result)
return result
# 伤害类型
async def get_dmg_type(
self, char: Character, seq: Optional[Dict] = None
) -> Element:
# TODO 获取本次攻击的元素
dmg_type: Element = Element.Physical
char_element_dmg_type = getattr(Element, char.char_element)
# 对重复的计数
if seq:
if seq['action'] == self.seq_history:
return dmg_type
# 计算角色伤害加成应该使用什么
if char.weapon_type == '法器' or char.char_name in [
'荒泷一斗',
'刻晴',
'诺艾尔',
'胡桃',
'宵宫',
'',
'神里绫华',
]:
dmg_type = char_element_dmg_type
elif char.weapon_type == '':
if char.attack_type in ['B', 'E', 'Q']:
dmg_type = char_element_dmg_type
else:
if char.attack_type in ['E', 'Q']:
dmg_type = char_element_dmg_type
if char.power_name in [
'Q光降之剑基础伤害',
'Q光降之剑基础伤害(13层)',
'Q每层能量伤害',
'Q光降之剑基础伤害(24层)',
]:
dmg_type = Element.Physical
if '' in char.power_name and 'A' not in char.power_name:
dmg_type = char_element_dmg_type
if char.char_name == '辛焱' and char.power_name == 'Q伤害':
dmg_type = Element.Physical
return dmg_type
# 计算倍率
async def get_power(self, char: Character) -> Power:
# 按照ABCEQ等级查找倍率
power_name = char.power_name
real_prop = char.real_prop
power_list = char.power_list
power_level = int(real_prop[f'{power_name[0]}_skill_level'])
# 拿到倍率
power = power_list[power_name]['value'][power_level - 1]
# 计算是否多次伤害
power_plus = power_list[power_name]['plus']
if char.char_name == '宵宫' and power_name == 'A一段伤害':
power_plus = 1
# 拿到百分比和固定值,百分比为float,形如2.2 也就是202%
power_percent, power_value = await p2v(power, power_plus)
# 额外加成,目前有雷神和优菈
if char.extra_effect and power_name in char.extra_effect:
power_percent += char.extra_effect[power_name]
return Power(
name=power_name,
level=power_level,
percent=power_percent,
value=power_value,
plus=power_plus,
raw=power,
)
# 额外加成和抗性计算
async def get_new_fight_prop(self, char: Character) -> Dict:
# 抗性传达
if char.enemy_debuff:
for effect in char.enemy_debuff:
await self.enemy.update_resist(effect)
char.enemy_debuff = []
# 特殊buff计算
effect_list = []
if '前台' in char.power_list[char.power_name]['name']:
if char.char_name == '纳西妲':
em = char.fight_prop[f'{char.attack_type}_elementalMastery']
effect = f'''
elementalMastery+{0.25 * em if 0.25 * em <= 250 else 250}
'''.strip()
effect_list.append(effect)
if '丰穰之核' in char.power_name and char.fight_prop['hp'] >= 30000:
ex_add = ((char.fight_prop['hp'] - 30000) / 1000) * 9
if ex_add >= 400:
ex_add = 400
effect = f'a+{ex_add}'
effect_list.append(effect)
if effect_list:
char.real_prop = await char.get_effect_prop(
deepcopy(char.fight_prop), effect_list, char.char_name
)
return char.real_prop
else:
char.real_prop = char.fight_prop
return char.real_prop
# 治疗值加成
async def get_add_heal(self, char: Character) -> float:
add_heal: float = char.real_prop[f'{char.attack_type}_addHeal']
return add_heal
# 增幅反应
async def get_amplify_dmg(self, char: Character) -> float:
# 计算元素反应 增幅
em_cal = char.real_prop[f'{char.attack_type}_elementalMastery']
for reaction in ['蒸发', '融化']:
if reaction in char.power_list[char.power_name]['name']:
if reaction == '蒸发':
if char.char_element == 'Pyro':
k = 1.5
else:
k = 2
else:
if char.char_element == 'Pyro':
k = 2
else:
k = 1.5
reaction_add_dmg = k * (
1 + (2.78 * em_cal) / (em_cal + 1400) + char.real_prop['a']
)
break
else:
reaction_add_dmg = 1
return reaction_add_dmg
# 激化反应
async def get_quicken_dmg(self, char: Character) -> float:
quicken_dmg = 0
char_level = char.char_level
power_name = char.power_list[char.power_name]['name']
em_cal = char.real_prop[f'{char.attack_type}_elementalMastery']
for reaction in ['超激化', '蔓激化']:
if reaction in power_name:
if reaction == '超激化':
k = 2.3
else:
k = 2.5
power_times = 1
if '*' in power_name:
power_times = float(
(power_name.split('*')[-1].replace(')', ''))
)
quicken_dmg = (
k
* base_value_list[char_level - 1]
* (1 + (5 * em_cal) / (em_cal + 1200))
) * power_times
break
return quicken_dmg
# 有效数值
async def get_effect_prop(self, char: Character):
# 根据type计算有效属性
_type = char.power_list[char.power_name]['type']
if '攻击' in _type:
effect_prop = char.real_prop[f'{char.attack_type}_atk']
elif '生命值' in _type:
effect_prop = char.real_prop[f'{char.attack_type}_hp']
elif '防御' in _type:
effect_prop = char.real_prop[f'{char.attack_type}_def']
else:
effect_prop = char.real_prop[f'{char.attack_type}_atk']
return effect_prop
# 伤害值加成
async def get_add_dmg(self, char: Character) -> float:
# 计算直接增加的伤害
add_dmg: float = char.real_prop[f'{char.attack_type}_addDmg']
return add_dmg
# 防御值加成
async def get_extra_d(self, char: Character) -> float:
# 计算直接增加的伤害
extra_d: float = char.real_prop[f'{char.attack_type}_d']
return extra_d
# 防御值加成
async def get_base_area_plus(self, char: Character) -> float:
# 计算直接增加的伤害
base_area_plus: float = char.real_prop[f'{char.attack_type}_baseArea']
return base_area_plus
# 防御值加成
async def get_extra_ignoreD(self, char: Character) -> float:
# 计算直接增加的伤害
extra_ignoreD: float = char.real_prop[f'{char.attack_type}_ignoreDef']
return extra_ignoreD
async def get_sp_base(self, power: Power, char: Character) -> float:
power_sp = power.raw.replace('%', '').split('+')
power_sp = [float(x) / 100 for x in power_sp]
real_prop = char.real_prop
atk = real_prop['E_atk'] + char.sp.attack
em = real_prop[f'{char.attack_type}_elementalMastery']
base = (power_sp[0] * atk + power_sp[1] * em) * power.plus
return base
# 基础乘区
async def get_base_area(self, char: Character) -> float:
# 获得该次伤害的倍率信息
power = await self.get_power(char)
# 获得激化乘区的信息
reaction_power = await self.get_quicken_dmg(char)
# 获得该次伤害的有效属性
effect_prop = await self.get_effect_prop(char)
# 获得伤害提高值的信息
add_dmg = await self.get_add_dmg(char)
base_area_plus = await self.get_base_area_plus(char)
# 对草神进行特殊计算
if '灭净三业' in power.name or '业障除' in power.name:
base = await self.get_sp_base(power, char)
elif char.char_name == '艾尔海森' and power.name.startswith('E'):
base = await self.get_sp_base(power, char)
else:
base = effect_prop * power.percent + power.value
if char.char_name == '珊瑚宫心海':
hp = char.real_prop['hp']
hb = char.real_prop['healBonus']
add_dmg += 0.15 * hp * hb
# 基本乘区 = 有效数值(例如攻击力) * 倍率 + 固定值 + 激化区 + 额外加成值 + 特殊加成值
base_area = base + reaction_power + add_dmg + char.sp.addDmg
if base_area_plus != 1:
base_area_plus -= 1
base_area = base_area_plus * base_area
return base_area
# 聚变反应
async def get_transform_dmg(
self, char: Character
) -> Tuple[float, float, float]:
em = char.real_prop[f'{char.attack_type}_elementalMastery']
is_crit = False
if '绽放)' in char.power_name:
# 获取激变反应基数
if '烈绽放' in char.power_name:
dmg_type = Element.Pyro
base_time = 6
elif '超绽放' in char.power_name:
dmg_type = Element.Dendro
base_time = 6
else:
dmg_type = Element.Dendro
base_time = 4
base_area = (
base_value_list[char.char_level - 1]
* base_time
* (1 + (16.0 * em) / (em + 2000) + char.real_prop['a'])
)
is_crit = True
elif '扩散伤害' in char.power_name:
dmg_type = Element.Anemo
base_area = (
base_value_list[char.char_level - 1]
* 1.2
* (1 + (16.0 * em) / (em + 2000) + char.real_prop['a'])
* (1 + char.real_prop['g'] / 100)
)
else:
dmg_type = Element.Physical
base_area = 0
# 获得这次攻击的减伤乘区(抗性区+防御区)
logger.debug(self.enemy.__dict__)
proof = await self.enemy.get_resist(dmg_type)
normal_dmg = base_area * proof
if is_crit:
crit_dmg = normal_dmg * 2
avg_dmg = normal_dmg * 1.2
else:
crit_dmg = avg_dmg = 0
return normal_dmg, avg_dmg, crit_dmg
async def get_heal(self, char: Character) -> Tuple[float, float, float]:
# 获得治疗增加值
add_heal = await self.get_add_heal(char)
# 获得治疗倍率
power = await self.get_power(char)
# 获得该次治疗的有效属性
effect_prop = await self.get_effect_prop(char)
heal_bonus = 1 + char.real_prop['healBonus']
base_area = effect_prop * power.percent + power.value + add_heal
normal_value = base_area * heal_bonus
return normal_value, normal_value, 0
async def get_shield(self, char: Character) -> Tuple[float, float, float]:
# 获得护盾倍率
power = await self.get_power(char)
# 获得该次护盾的有效属性
effect_prop = await self.get_effect_prop(char)
shield_bonus = 1 + char.real_prop['shieldBonus']
base_area = effect_prop * power.percent + power.value
normal_value = base_area * shield_bonus
return normal_value, 0, 0
async def get_dmg(
self,
char: Character,
dmg_type: Element,
is_single: bool = False,
) -> Tuple[float, float, float]:
# 获得基础乘区(攻击区+倍率区+激化区)
base_area = await self.get_base_area(char)
# 获得这次攻击的减伤乘区(抗性区+防御区)
d = await self.get_extra_d(char)
i_d = await self.get_extra_ignoreD(char)
# logger.debug(self.enemy.__dict__)
proof = await self.enemy.get_dmg_proof(dmg_type, d, i_d)
# 获得这次攻击的增幅乘区
_char = char if is_single else None
reactio = await self.enemy.get_dmg_reaction(dmg_type, _char)
if dmg_type == Element.Physical:
_dmgBonus = char.real_prop[f'{char.attack_type}_physicalDmgBonus']
else:
_dmgBonus = char.real_prop[f'{char.attack_type}_dmgBonus']
critrate = char.real_prop[f'{char.attack_type}_critRate']
critdmg = char.real_prop[f'{char.attack_type}_critDmg']
dmgBonus = _dmgBonus + char.sp.dmgBonus
# 基础乘区 = 攻击*倍率+激化
# 普通伤害 = 基础 * 增伤区 * 增幅区 * 抗性区
normal_dmg = base_area * (1 + dmgBonus) * reactio * proof
# 暴击伤害 = 普通伤害 * 暴击区
crit_dmg = normal_dmg * (1 + critdmg)
# 平均伤害
avg_dmg = (
normal_dmg
if critrate < 0
else crit_dmg
if critrate > 1
else crit_dmg * critrate + (1 - critrate) * normal_dmg
)
self.total_normal_dmg += normal_dmg
self.total_avg_dmg += avg_dmg
self.total_crit_dmg += crit_dmg
return normal_dmg, avg_dmg, crit_dmg
async def p2v(power: str, power_plus: float) -> Tuple[float, float]:
"""
将power转换为value
"""
if '+' in power:
power_percent = (
float(power.split('+')[0].replace('%', '')) / 100
) * power_plus
power_value = power.split('+')[1]
if '%' in power_value:
power_percent += (
float(power_value.replace('%', '')) / 100 * power_plus
)
power_value = 0
else:
power_value = float(power_value)
elif '%' in power:
power_percent = float(power.replace('%', '')) / 100 * power_plus
power_value = 0
else:
power_percent = 0
power_value = float(power)
return power_percent, power_value

View File

@ -0,0 +1,16 @@
from pydantic import BaseModel
class Power(BaseModel):
name: str
level: int
raw: str
percent: float
value: float
plus: float
class sp_prop(BaseModel):
dmgBonus: float = 0
addDmg: float = 0
attack: float = 0

View File

@ -0,0 +1,28 @@
WAN_DA = [
{'char': '达达利亚', 'action': 'E状态激发伤害', 'type': '伤害'},
{'char': '达达利亚', 'action': 'E一段伤害', 'type': '伤害'},
{'char': '达达利亚', 'action': 'E重击伤害', 'type': '伤害'},
{'char': '班尼特', 'action': 'Q伤害', 'type': '伤害'},
{'char': '枫原万叶', 'action': 'Q斩击伤害', 'type': '伤害'},
{'char': '枫原万叶', 'action': 'A扩散伤害', 'type': '持续'},
{'char': '枫原万叶', 'action': 'E长按伤害', 'type': '伤害'},
{'char': '枫原万叶', 'action': 'Q持续伤害', 'type': '持续'},
{'char': '枫原万叶', 'action': 'A高空下落伤害', 'type': '伤害'},
{'char': '香菱', 'action': 'Q旋火轮伤害', 'type': '持续'},
{'char': '香菱', 'action': 'E喷火伤害', 'type': '持续'},
{'char': '达达利亚', 'action': 'E状态激发伤害', 'type': '伤害'},
{'char': '枫原万叶', 'action': 'Q持续伤害', 'type': '持续'},
{'char': '达达利亚', 'action': 'E一段伤害', 'type': '伤害'},
{'char': '达达利亚', 'action': 'Q伤害·近战', 'type': '伤害'},
{'char': '达达利亚', 'action': 'E一段伤害', 'type': '伤害'},
{'char': '达达利亚', 'action': 'E重击伤害', 'type': '伤害'},
{'char': '达达利亚', 'action': 'E一段伤害', 'type': '伤害'},
{'char': '枫原万叶', 'action': 'Q持续伤害', 'type': '持续'},
{'char': '达达利亚', 'action': 'E重击伤害', 'type': '伤害'},
{'char': '达达利亚', 'action': 'E一段伤害', 'type': '伤害'},
{'char': '达达利亚', 'action': 'E重击伤害', 'type': '伤害'},
]
ALL_SEQ = {'万达国际': WAN_DA}
SEQ_ARG = {'万达国际': ['香菱', '达达利亚', '班尼特', '枫原万叶']}

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Some files were not shown because too many files have changed in this diff Show More