diff --git a/.gitattributes b/.gitattributes index 37f2230cb41013e4afb95350e93456d0cb1f3aa2..da243a7b74fe3b5e5edd41918cac6483cc6ea756 100644 --- a/.gitattributes +++ b/.gitattributes @@ -39,3 +39,8 @@ Yunzai/plugins/ws-plugin/resources/common/font/NZBZ.ttf filter=lfs diff=lfs merg Yunzai/plugins/ws-plugin/resources/help/icon.png filter=lfs diff=lfs merge=lfs -text Yunzai/plugins/genshin/resources/font/华文中宋.TTF filter=lfs diff=lfs merge=lfs -text Yunzai/plugins/genshin/resources/font/HYWenHei-55W.ttf filter=lfs diff=lfs merge=lfs -text +Yunzai/plugins/miao-plugin/resources/admin/imgs/bg.png filter=lfs diff=lfs merge=lfs -text +Yunzai/plugins/miao-plugin/resources/common/font/HYWH-65W.ttf filter=lfs diff=lfs merge=lfs -text +Yunzai/plugins/miao-plugin/resources/common/font/HYWH-65W.woff filter=lfs diff=lfs merge=lfs -text +Yunzai/plugins/miao-plugin/resources/common/font/NZBZ.ttf filter=lfs diff=lfs merge=lfs -text +Yunzai/plugins/miao-plugin/resources/help/icon.png filter=lfs diff=lfs merge=lfs -text diff --git a/Yunzai/plugins/miao-plugin/.gitignore b/Yunzai/plugins/miao-plugin/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6b98bf79f81a57211f7beb563bc739739dbadc3e --- /dev/null +++ b/Yunzai/plugins/miao-plugin/.gitignore @@ -0,0 +1,20 @@ +*.psd +.idea +/tools/char-data-sprider.js +/components/cfg.json +/resources/miao-res-plus/ +/components/setting.json +/config.js +*.css.map +/resources/character-img/*/upload/ +/resources/help/help-list.js +/resources/help/help-cfg.js +/resources/help/theme/* +!/resources/help/theme/default +/config/character.js +/config/profile.js +/config/help.js +/config/cfg.js +/resources/profile/super-character/* +/resources/profile/normal-character/* +/node_modules/ diff --git a/Yunzai/plugins/miao-plugin/CHANGELOG.md b/Yunzai/plugins/miao-plugin/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..738d41548c5768ffc0e449a865c553b3c27b9bac --- /dev/null +++ b/Yunzai/plugins/miao-plugin/CHANGELOG.md @@ -0,0 +1,377 @@ +# 2.4.8 + +* 星铁面板支持面板变换功能 +* 面板变换支持更换圣遗物套装,例如`#甘雨换乐团`、`#镜流换快枪手封印站` +* 微调面板页面的部分样式 + +# 2.4.1 ~ 2.4.7 + +* 初步支持星铁面板数据获取与展示 + * 可使用`#星铁更新面板`来获取面板信息,通过`#希儿面板`来进行查看 + * 星铁面板展示圣遗物评分,评分功能尚未完全完成,分值与样式不为最终版本 + * 部分角色的伤害计算,以及圣遗物评分功能仍在补全中 + * 星铁面板天赋展示更新,支持展示行迹信息 +* 请配合使用Miao-Yunzai 3.1.0可达到最佳效果 + * Miao-Yunzai可使用`*`来代填`#星铁`前缀,能区分游戏使用不同UID + * 其他Yunzai版本出现原神与星铁UID混淆情况为正常情况,请手动切换UID或命令后附加UID查询 +* 角色数据及资源更新 + * 增加原神4.0~4.2的角色信息,可通过`#水神天赋`、`#水神图鉴`查看 + * 更新星铁1.2~1.3的角色数据与资源 +* 伤害计算更新 + * 增加林尼、卡夫卡、银狼的伤害计算**@Aluxes** + * 增加原神4.0相关的武器计算 **@SmallK111407** + * 增加菲米尼、符玄、玲可、三月七、娜塔莎、罗刹、黑塔的伤害计算 **@Aluxes** +* 初步增加星铁的排名功能 **@Simplxss** +* 增加`#喵喵api`命令,用于查看喵ApiToken的有效期 +* 增加`#星铁日历`功能 **@Aluxes** +* 增加`#重载面板`功能,用于手工修改面板数据后主动读取 +* 停用旧面板格式数据,非AttrIDs格式的数据不会展示,部分角色面板数据不展示是正常情况,重新更新面板数据即可 +* 一些已知问题修复 + +# 2.4.0 + +* 增加`#角色记录``#抽卡统计`功能,可在`#喵喵设置`中开启 + * `#角色记录`、`#武器记录`、`#常驻记录` 可查看对应池子的抽卡记录 + * `#角色统计`、`#武器统计` 可按卡池汇总统计抽卡记录 + * `#全部统计` 可将所有抽卡信息汇总展示 + * 其余`#抽卡帮助`等相关功能均为Yunzai原生功能 +* 面板服务增加国内专属面板服务 MiniGG-API + * 由小灰灰大佬**@MiniGrayGay**与Enka官方合作部署 + * 国内节点,免费开放,请求速度会比Enka更快 +* MiaoApi面板服务更新 + * 使用新版接口获取面板,大幅提高响应速度 + * 使用statsIds存储圣遗物数据,能够更精确的计算角色属性 +* `#喵喵设置`中可区分国服、B服、外服分别设置面板服务器,具体参见喵喵设置 +* `#面板`、`#角色`等页面使用Q版头像(@QuAn_、Misaaa),可在#喵喵设置 中关闭 +* 增加白术、卡维的角色信息,可通过`#白术天赋`、`#白术图鉴`等查看 +* 部分已知问题调整或优化 + * 圣遗物、天赋更新策略及更新逻辑优化 + * 面板更新的提醒文案逻辑优化 +* `#雷神面板` 属性部分样式调整,增加圣遗物评分权重展示 +* 圣遗物评级的分数上限微调 +* 增加3.6新圣遗物数据及资源 +* 增加绮良良的角色信息,可通过`#绮良良天赋`、`#绮良良图鉴`等查看 +* 面板服务增加由**Snap Hutao**提供的Enka转发代理,可通过`#喵喵设置面板服务4`进行选择 +* 面板详情的圣遗物词条增加词条数展示 +* 角色面板使用平均词条值作为词条数计算基础 +* 部分角色资源文件结构调整 + +# 2.3.0 + +* 重写底层面板、角色数据获取与保存逻辑 + * 底层完全兼容面板及Mys数据,对于miao-plugin的大部分场景可做到数据通用 + * 角色数据及天赋增加缓存逻辑,有缓存数据情况下可在ck失效/验证码等情况下正常使用大部分功能 + * 全量使用通过圣遗物属性计算得到的面板数据 + * 面板底层数据结构及存储逻辑优化,兼容老版本数据 + * Enka服务下使用statsIds存储圣遗物数据,能够更精确的计算角色属性 +* 增加`#角色`功能,查询并展示Mys角色信息 + * Yunzai需要跟随游戏版本升级的功能会逐步在miao-plugin中提供,以保障基础功能相对长期可用 + * 大部分功能目前默认关闭,可在`#喵喵设置`中设置并开启 +* 为`#喵喵设置`增加更多配置项 + * 允许禁用非实装角色资料,关闭可禁用非实装角色资料及面板替换 + * 允许禁用面板替换功能 + * 允许禁用获取角色或面板原图功能 + * 可选择面板服务,可选喵喵Api优先(需具备Token)或Enka优先 + * 可设置群排名人数、圣遗物列表展示数 **@SmallK111407** +* 角色信息及伤害计算更新 + * 更新迪希雅、米卡的最新天赋与命座数据 + * 增加瑶瑶伤害计算 +* 其他功能及界面优化,部分已知问题调整 + * `#上传深渊` 界面与样式调整 + * `#刷新排名`、`#禁用排名`、`#启用排名`可由群管理员进行管理 + * 增加`#删除面板`命令,目前限绑定CK用户使用删除自己UID数据,Bot主人可删除任意UID数据 + +# 2.2.0 + +* 增加面板替换功能,可通过命令更换面板的圣遗物、武器、天赋命座等,用于伤害计算 + * `#雷神面板换稻光换90级满命` / `#刻晴面板换雷神圣遗物` 等命令 + * 更多命令参见 `#面板帮助`,请根据需求吟唱。后续会提供更细致的咒语详解 +* 增加角色面板立绘图相关命令 **@cvs** + * 支持`#上传刻晴面板图`上传 + * 新增`#刻晴面板图列表` + * 可通过指令查询当前可看的面板立绘 + * 立绘支持`#原图`指令 +* 角色立绘支持随机,用于面板场景 + * 图像支持webp及png格式 + * 普通立绘:**resources/profile/normal-character/** + * 彩蛋立绘(满命/ACE/三皇冠):**resources/profile/super-character/** + * 单张立绘请放置在普通&彩蛋目录下,以**角色全名**为**文件名**,例如**刻晴.webp** + * 如需多张随机,请在普通&彩蛋目录下,以**角色全名**为**目录**名,任意文件名为文件名,例如 **刻晴/1.png** + * 较低版本的Yunzai可能无法正常使用miao-plugin +* 部分底层结构升级 + * 去除插件内自带的V2/V3兼容逻辑,使用runtime进行V2/V3兼容,如使用遇到问题请升级至最新版Yunzai + * 底层增加面板计算逻辑, 圣遗物数据底层存储格式与处理逻辑初步升级 +* 圣遗物主词条评分规则微调,可能会影响部分角色评分 + * 元素杯属性不符会触发主词缀评分惩罚 + * 充能主词条不再触发主词缀评分惩罚 +* 增加`#启用排名``#禁用排名`命令,可在全局启用排名情况下,在特定群内禁用排名功能 +* 更新迪希雅、米卡、瑶瑶、艾尔海森的信息,可通过`#瑶瑶天赋`、`#瑶瑶图鉴`等查看 +* 增加散兵、艾尔海森 **@panganqi**、珐露珊的伤害计算 +* 增加归终、米卡的角色图像 +* 其他一些已知问题修正与样式优化 + +# 2.1.0 + +* 增加群内排名功能 + * 默认关闭,如需启用可通过 `#喵喵设置排名开启`进行打开 + * 统计为bot本地统计,只统计在群内主动查看过的面板数据 + * 可通过 `#面板`、`#心海面板`、`#更新面板`等命令来触发排名数据更新 + * 增加命令 `#刷新排名`,获取群成员面板数据,刷新当前排名 **@munnks** + * `#雷神排名` 使用个人头像作为排行头像展示(首次使用可使用 `#刷新排名`以更新uid信息) +* 增加排名相关命令 + * 增加 `#最强雷神`、`#最高分甘雨`命令,查看当前统计中最高练度/最高圣遗物评分的面板数据 + * 增加 `#雷神排名`、`#甘雨圣遗物排名`命令,查看当前群中角色的排名数据 + * 增加 `#重置排名`、`#重置刻晴排名`命令,来重置当前群的排名统计 +* 面板及伤害计算升级 + * `#雷神面板`圣遗物支持展示强化次数 + * `#面板`会展示角色名命座信息 + * 底层元素反应计算逻辑更新 **@冷落** + * 增加纳西妲的伤害计算 +* `#喵喵设置` 部分配置项及功能改进 + * 删除一些无效或暂不支持的配置项 + * 配置存储位置变更为**config/cfg.js**。原设置会自动迁移 + * 喵喵设置中增加排名限制门槛,支持限制 有16个角色数据/包含御三家角色 才能参与排名,防止被非群成员uid刷榜 +* `#日历` 页面样式微调,功能升级 + * 日历中会展示角色生日 + * 日历会展示本日可刷天赋角色列表 +* 增加3.3角色信息及图片,可通过 `#散兵天赋`、`#珐露珊命座`查看 +* 一些样式及功能点优化 + * 优化character的进入判定逻辑,防止一些额外的log触发 + * 角色相关命令在V3下会联合V3的角色别名一同查询 + * `#深渊组队`使用新版胡桃API进行组队信息获取 +* 增加命令 `#最强排行`、`#最高分排行` 查看群排行 +* 增加莱依拉的伤害计算及圣遗物评分权重 + +# 2.0.0 + +* 底层架构升级,以V3为主要版本,V2做兼容处理 +* `#深渊配队`、`#戳一戳` 适配V3 +* `#喵喵帮助`配置功能升级 + * 支持自定义帮助皮肤包,皮肤目录为**resources/help/theme** + * 若有多套皮肤包,默认随机使用,可通过**config/help.js**指定 + * 支持配帮助文字颜色及容器颜色与透明度 + * 支持图片毛玻璃效果,默认开启,可通过配置关闭 + * `注意1:` 如之前更改过底图可能会在更新后失效,可将自定义底图放置在新建的皮肤包目录内 + * `注意2:` 为统一配置目录,帮助配置文件迁移至**config/help.js**,如之前自定义过配置文件,help-cfg.js仍能够识别,但建议移至新配置目录以使用后续更多功能 +* `#面板练度统计` 功能调整,样式重写 + * 样式由深色调整为浅色方案 + * 在未绑定CK时,使用本地面板数据展示练度信息 +* 重写 `#刻晴`、`#老婆`的角色卡片 + * 样式整体升级,展示信息重新排版 + * 未绑定CK时,会同时使用本地面板数据进行展示 +* `#上传深渊`队伍人数少于4人时展示样式优化 +* MysApi内部逻辑重写 + * 在未绑定CK时,会使用本地面板数据综合计算,以使信息展示更完备 + * 优化V3下获取Uid及CK的逻辑,防止一些情况下触发报错 +* 武器、圣遗物 meta数据及图像资源逻辑更新 + * 重构武器及圣遗物的底层处理逻辑,重构页面引用图像资源的逻辑 + * 图像资源更新为webp格式 +* 增加多莉的伤害计算 +* 其他已知Bug修复 + +# 1.11.0 + +* 面板圣遗物评分初步增加流派判定能力 + * 实验性,尚未完全稳定,可能会导致一些角色圣遗物评分变化,如遇问题请反馈 + * 目前实验暴力芭芭拉、血牛钟离的判定 +* `#刻晴面板`、`#芭芭拉圣遗物`支持展示角色时装 + * 如果角色装备了时装,面板的角色图会展示时装立绘 + * 需要重新 `#更新面板`以获取时装数据 +* 增加赛诺、妮露、坎蒂丝的角色信息,可以通过 `#妮露天赋`、`#妮露命座`查看角色信息了 +* 角色面板支持旅行者,暂未支持伤害计算及圣遗物评分 + * 需要重新更新旅行者的面板数据 +* `#雷主天赋`、`#草主命座`功能升级 + * 页面样式微调,内部处理逻辑升级 + * 支持旅行者天赋及命座信息查看 +* 增加 `#心海图鉴`功能,可查看突破材料及常用武器 + * 功能尚未完全稳定,信息还在继续补全中 + * 如无需使用,master可通过 `#喵喵设置图鉴关闭`关闭,防止覆盖图鉴插件等图鉴功能 +* 框架底层角色相关逻辑重构,角色图像资源迁移为webp格式 + * 若遇到图像资源无法正常展示,可联系喵喵反馈 + +# 1.10.0 + +* 新增 `#面板练度统计`功能 + * 可展示当前角色天赋及圣遗物练度信息 + * 需要用户绑定Cookie,圣遗物评分需要本地获取并查看过对应角色面板 +* `#上传深渊`使用图片渲染深渊结果,同时可被 `#喵喵深渊`触发 + * 可展示本期深渊的全部角色信息,包括组队、天赋及圣遗物 + * 数据会上传至胡桃Api进行伤害排名,并展示在页面内 + * 可在 `#喵喵设置`中启用 `#喵喵深渊`作为默认 `#深渊`,默认关闭 + * 启用后不会覆盖 `#上期深渊`以及 `#深渊12层`具体楼层的命令 +* `#面板`、`#更新面板`命令使用图片渲染结果 +* `#雷神面板`展示数据API及更新时间 +* Enka面板服务支持配置代理 **@永恒的小黑屋** + * 如需配置可在**miao-plugin/config/profile.js**文件中配置 +* `#更新面板`支持配置更新API,适配Enka新校验逻辑 + * B服角色使用Enka服务进行面板信息获取 + * 感谢Enka官方 **@Algoinde**的官方授权及UA**校**验 + * 感谢 **@MiniGrayGay**提供的Enka服务中转,若面板更新失败可尝试在**miao-plugin/config/profile.js**文件中配置切换更新API + * 更新面板增加单用户更新间隔控制,默认5分钟 +* `#深渊出场率`、`#角色持有率` 增加样本数量展示,增加数据使用授权提示 +* 部分角色的圣遗物评分增加充能的词条评分权重 +* 重构部分components、models逻辑,重构部分伤害计算逻辑 +* 伤害计算支持除旅行者外的全部角色 +* 伤害计算暂未包含3.0新元素反应,后续统一补充 + +# 1.9.0 + +* 初步适配Yunzai V3 + * 部分功能可能无法正常使用,会逐步适配 + * 部分依赖MysApi查询的功能在V3下暂时只支持查自己 +* 增加提纳里、柯莱、多莉的资料及角色图像 + * 可通过 `#柯莱天赋`、`#柯莱命座`查看资料 +* 增加 `#深渊使用率`命令,数据源自DGP-Studio胡桃API +* 新增 `#上传深渊数据`命令 + * 上传自己角色的深渊挑战数据及角色列表,并展示在本期深渊中伤害与承伤排名 + * 上传数据用于 `#角色持有率 #深渊出场率`等统计,可使统计更加及时准确 + * 数据统计及服务来自DGP-Studio胡桃API +* 增加 `#添加刻晴图像`命令,感谢 **@叶** + * 可通过命令上传添加指定角色图片,上传至 **resources/character-img/刻晴/upload** + * 请将图像与命令一同发送,后续会支持at图像及命令后发送图像 +* `#刻晴` 角色卡片功能升级 + * `#老婆设置刻晴,心海`不再检查是否具有角色或展示在米游社展柜 + * `#刻晴` 角色卡片优先使用面板数据进行展示,无面板数据时使用米游社数据 + * 在未能获取到角色数据时也会展示角色卡片 +* 支持戳一戳返回喵喵版角色卡片,暂不支持V3 Yunzai + * 需要使用喵喵分支Yunzai以支持此能力,如需切换可在Yunzai根目录输入下方命令后更新重启 + * `git remote set-url origin https://gitee.com/yoimiya-kokomi/Yunzai-Bot` + * 可通过 `#喵喵设置` 关闭戳一戳 +* 支持定义新角色及别名 + * 新增角色 派蒙、瑶瑶、白术、伐难、应达、散兵、女士、萍姥姥、仆人、少女、富人、博士、木偶、丑角、队长、妮露、纳西妲 的角色配置及图片 + * 自定义角色可使用 `#派蒙` `#派蒙图片`触发图片查看,`#女儿设置派蒙`进行设置。后续会支持更多场景 + * 如需扩展可在喵喵config/character.js中定义 +* `#喵喵帮助`增加对自定义配置文件的支持 +* 角色伤害计算增加 鹿野院平藏、烟绯 +* `#喵喵日历`现在可通过 `#日历 #日历列表`触发 + +# 1.8.0 + +* `#角色面板`、`#圣遗物列表` 使用新的圣遗物评分逻辑计算评分 + * 新的圣遗物评分规针对不同角色进行了细化,对不同角色的评分进行了拉齐 + * 不同角色基于不同词条权重进行计算。感谢 **@糖炒栗子 @秋声 @49631073**等的权重梳理 +* 增加 `#雷神圣遗物`命令 + * 展示指定角色圣遗物及评分计算详情 + * 展示新版圣遗物评分逻辑与计算规则 +* 增加 `#原图`命令,可获取喵喵角色卡片原图,感谢 **@牧星长** 提供功能 + * 对由 `#老婆 #刻晴`发出的角色卡片图回复 `#原图`可获取对应图像 +* `#角色面板`现在支持B服角色数据获取 + * 数据来自喵喵API,目前开放调用无需Token,仅限喵喵插件用户使用 + * 已知问题:角色天赋的皇冠及命座加成效果显示可能有问题,后期fix +* `#录入角色面板` 功能恢复 + * 可对已有面板数据的角色手工输入更改面板属性,用于伤害测算 + * 例如 `#录入雷神面板 暴击80,暴伤250` + * 暂不支持设置武器、圣遗物、命座、天赋。后续会增加支持 +* 部分页面样式调整及功能优化 + * `#角色持有率` 等增加提示说明 + * `#圣遗物列表` 展示个数提升至28,且根据新版圣遗物评分规则进行词条高亮 + * `#喵喵更新` 的自动重启功能适配node app方式启动的Yunzai-Bot,感谢 **@SirlyDreamer** +* 角色图像增加小清新开关,默认关闭 + * 对增量包内的角色图像进行分级,较为清凉的图像独立管理 + * 勇士们可使用 `#喵喵设置小清新开启` 启用 +* 伤害计算增加扩散、感电的计算逻辑,感谢 **@49631073**的逻辑梳理 +* `#角色面板` 伤害计算增加部分角色,目前支持 + * 长柄武器:雷神、胡桃、魈、钟离、香菱 + * 法器:神子、心海、可莉、凝光、芭芭拉、莫娜 + * 弓:甘雨、宵宫、公子,九条,迪奥娜、安柏、皇女、温迪、夜兰 + * 单手剑:绫人、绫华、刻晴、阿贝多、行秋、班尼特、七七、凯亚、琴、万叶ⁿᵉʷ、久岐忍ⁿᵉʷ + * 双手剑:一斗、优菈、迪卢克、诺艾尔、重云 + +# 1.7.0 + +* `#更新面板` 功能升级 + * 该功能可直接使用,不再需要token + * 在查询新用户时会自动使用,自动使用的CD 12小时 + * 支持国际服UID,目前暂不支持2及5开头的UID + * 服务来自enka api,部分网络可能无法请求,请科学处理,后续会增加转发服务。 + * 由于服务逻辑与之前数据不一致,部分角色的属性及伤害计算可能会不准确,如有发现请反馈给喵喵 +* `#面板`、`#更新面板`、`#角色面板`、`#角色伤害`、`#圣遗物列表`不再需要绑定cookie,支持查他人 + * 使用 `#面板`命令可查看已获取面板数据的角色列表 + * 默认查询自己UID,同时也可通过命令+uid方式指定查询对象 + * 由于整体逻辑变化,喵喵1.6.0之前更新的面板数据无法查看,需要重新更新数据 +* 增加 `#喵喵面板设置`命令,可更精细的设置是否允许好友/临时对话/群使用面板功能 +* 由 `#录入xx面板` 录入的数据暂时屏蔽 +* `#角色面板`、`#喵喵日历` 部分细节样式调整 +* `#角色面板` 伤害计算增加部分角色,目前支持 + * 长柄武器:雷神、胡桃、魈、钟离、香菱 + * 法器:神子、心海、可莉、凝光、芭芭拉、莫娜ⁿᵉʷ + * 弓:甘雨、宵宫、公子,九条,迪奥娜、安柏、皇女ⁿᵉʷ、温迪ⁿᵉʷ、夜兰ⁿᵉʷ + * 单手剑:绫人、绫华、刻晴、阿贝多、行秋、班尼特、七七、凯亚、琴ⁿᵉʷ + * 双手剑:一斗、优菈、迪卢克、诺艾尔、重云 + +# 1.6.0 + +* `#喵喵设置` 支持设置 面板查询 的功能开关 +* `#喵喵版本` 使用图片展示更新信息 +* `#喵喵日历` 升级 + * 增加 `#喵喵日历列表`命令,以列表形式展示活动信息 + * 增加从活动详情信息中解析活动日期的逻辑,使一些活动日期更加准确 +* 增加鹿野院平藏的角色信息,可通过 `#平藏天赋`、`#平藏命座`查看信息 +* 其他升级调整 + * `#深渊出场率`、`#角色持有率` 等页面功能及样式微调 + * `#角色面板` 伤害计算增加双手剑计算逻辑,增加物伤计算逻辑 + * 页面版权信息展示Yunzai及喵喵版本号 +* `#角色面板` 伤害计算增加部分角色,目前支持 + * 长柄武器:雷神、胡桃、魈、钟离、香菱 + * 法器:神子、心海、可莉ⁿᵉʷ、凝光ⁿᵉʷ、芭芭拉ⁿᵉʷ + * 弓:甘雨、宵宫、公子,九条ⁿᵉʷ,迪奥娜ⁿᵉʷ、安柏ⁿᵉʷ + * 单手剑:绫人、绫华、刻晴、阿贝多、行秋、班尼特、七七ⁿᵉʷ、凯亚ⁿᵉʷ + * 双手剑:一斗ⁿᵉʷ、优菈ⁿᵉʷ、迪卢克ⁿᵉʷ、诺艾尔ⁿᵉʷ、重云ⁿᵉʷ + +# 1.5.0 + +* 增加 `#喵喵日历` 功能 + * 【!请注意!】此功能需要安装moment库,请在Yunzai安装目录下运行 `npm install moment`后再进行升级 + * 展示当前进行中及即将开始的活动,包括深境螺旋 +* `#角色面板` 伤害计算目前支持 + * 长柄武器:雷神、胡桃、魈、钟离、香菱ⁿᵉʷ + * 法器:神子、心海 + * 弓:甘雨、宵宫、公子 + * 单手剑:绫人、绫华、刻晴、阿贝多ⁿᵉʷ、行秋ⁿᵉʷ、班尼特ⁿᵉʷ +* 底层升级:抽象了部分公共组件为tpl模板以提高复用度,css改为less处理 + +# 1.4.0 + +* 增加 `#深渊配队` 功能 + * 根据当前账号的角色练度及本期深渊出场数据,推荐较匹配的配队方案 + * 深渊出场数据来自DGP-Studio胡桃API + * 配队方案仅供参考 +* `#角色面板` 伤害计算新增部分角色 + * 目前支持:雷神、胡桃、魈、神子、甘雨、宵宫、公子、绫人、绫华、心海、钟离 +* `#角色面板` 一些功能升级与调整 + * 支持对治疗量、护盾量的计算与展示 + * 修复冰融化、少女4等buff等buff遗漏或错误导致的伤害计算偏差 +* `#老婆` 功能支持对jpeg格式的图片格式识别 + +# 1.3.0 + +* 增加 `#雷神伤害` 功能 + * 可计算圣遗物副词条置换带来的伤害变化,可用于圣遗物副词条侧重方向的参考 + * 可以查看指定角色伤害计算的Buff列表 +* `#角色面板` 伤害计算新增部分角色 + * 目前支持:雷神、胡桃、魈、神子、甘雨、宵宫、公子、绫人、绫华 +* `#角色面板` 功能升级 + * 优化无角色面板数据时的引导 + * 优化返回的图像格式及分辨率,平衡响应速度及显示效果 +* 增加 `#圣遗物列表` 功能,对已经获取面板的所有角色圣遗物进行评分,并展示高评分的圣遗物列表 +* 增加 `#角色面板列表` / `#角色面板帮助` 命令 +* 增加 `#更新胡桃面板` 命令,获取单个角色面板数据,每天可更新5次 +* 更改 `#更新全部面板` 命令,获取角色展柜全部8个角色,每天可更新3次 + +# 1.2.0 + +* `#角色面板` 增加伤害计算功能 + * 目前支持角色:雷神、胡桃、魈、神子、甘雨 + * 可通过 `#怪物等级85` 命令设定怪物等级,以获得更准确的计算结果 + * 计算伤害为满Buff情况,后续会出更详细的Buff及计算展示 +* `#获取游戏角色详情`命令在服务侧增加基于UID的天频度限制 +* 增加 `#喵喵更新` 功能 + * 感谢 @碎月 @清秋 的代码支持 + * 若更新成功会重启Yunzai,需要Yunzai以 npm run start 模式启动 + * 尚未经充分测试,请有一定容错能力的勇士尝试 + * 增加 `#喵喵版本`命令查询版本信息 + +# 1.1.0 + +* 增加 `#喵喵帮助`用于查看帮助命令 +* 增加 `#喵喵设置`用于设置喵喵相关功能 diff --git a/Yunzai/plugins/miao-plugin/LICENSE b/Yunzai/plugins/miao-plugin/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..1b5db53e5fd9486f8a2494201cb9363b1057cb8a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Yoimiya + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Yunzai/plugins/miao-plugin/README.md b/Yunzai/plugins/miao-plugin/README.md new file mode 100644 index 0000000000000000000000000000000000000000..94aea30274ec03cdfc5b1d9f5c802324529d248a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/README.md @@ -0,0 +1,106 @@ +# Miao-Plugin 说明 + +`miao-plugin`是一个`Yunzai-Bot`的升级插件,提供包括角色面板、角色查询等角色相关功能。 + +具体功能可在安装插件后 通过 `#喵喵帮助` 进行查看。如需进行设置则可通过 `#喵喵设置` 命令进行管理。 + +--- + +## 安装与更新 + +### 使用Git安装(推荐) + +请将 miao-plugin 放置在 Yunzai-Bot 的 plugins 目录下,重启 Yunzai-Bot 后即可使用。 + +请使用 git 进行安装,以方便后续升级。在 Yunzai-Bot 根目录夹打开终端,运行下述指令之一 + +``` +// 使用gitee +git clone --depth=1 https://gitee.com/yoimiya-kokomi/miao-plugin.git ./plugins/miao-plugin/ +pnpm install -P + +// 使用github +git clone --depth=1 https://github.com/yoimiya-kokomi/miao-plugin.git ./plugins/miao-plugin/ +pnpm install -P +``` + +进行安装。安装完毕后,管理员只需发送 `#喵喵更新` 即可自动更新 miao-plugin。 + +### 手工下载安装(不推荐) + +手工下载安装包,解压后将`miao-plugin-master`更名为`miao-plugin`,然后放置在Yunzai的plugins目录内 + +虽然此方式能够使用,但无法使用`#喵喵更新`进行更新,不利于后续升级,故不推荐使用 + +--- + +## Yunzai版本与支持 + +`miao-plugin` 支持V3 / V2 版本的Yunzai-Bot + +* [Miao-Yunzai](https://github.com/yoimiya-kokomi/Miao-Yunzai) : 喵版Yunzai [Gitee](https://gitee.com/yoimiya-kokomi/Miao-Yunzai) + / [Github](https://github.com/yoimiya-kokomi/Miao-Yunzai) ,本体不含签到功能,功能迭代较多,与miao-plugin打通,只建议新部署/迁移 +* [Yunzai-V3](https://github.com/yoimiya-kokomi/Yunzai-Bot) :Yunzai V3 - 喵喵维护版,icqq版本,与原版Yunza功能基本一致,会保持卡池更新,功能相对稳定,可从原版Yunzai换源直接升级 +* [Yunzai-V3](https://gitee.com/Le-niao/Yunzai-Bot) :Yunzai V3 - 乐神原版,oicq版本,可能会遇到登录问题 + +--- + +## 功能说明 + +### #雷神面板 + +使用指令 `#面板帮助` 即可了解如何使用此功能。 + +#### #更新面板 + +`#更新面板` 依赖于面板查询API,面板服务由 http://enka.network/ 提供。 + +> 查询功能经Enka官方授权([issue#63](https://github.com/yoimiya-kokomi/miao-plugin/issues/63#issuecomment-1199348789)),感谢Enka提供的面板查询服务 +> +> 如果可以的话,也请在Patreon上支持Enka,或提供闲置的原神账户,具体可在[Enka官网](http://enka.network/) Discord联系 +> +> [issue#63](https://github.com/yoimiya-kokomi/miao-plugin/issues/63#issuecomment-1199734496) + +> 可尝试使用`MiniGG-Api`面板服务 [@MiniGrayGay](https://github.com/MiniGrayGay)
+> 发送 `#喵喵设置面板服务332` 修改国服&B服的面板查询由 `MiniGG-Api` 处理 + +#### #雷神伤害 + +喵喵面板附带的伤害计算功能由喵喵本地计算。如计算有偏差 #雷神伤害 查看伤害加成信息,如确认伤害计算有误可提供伤害录屏截图及uid进行反馈 + +#### #雷神圣遗物 + +圣遗物评分为喵喵版评分规则 + +--- + +**在有一定阅读理解能力基础下,建议阅读 [CHANGELOG.md](CHANGELOG.md) 以了解更多内容。** + +其余文档咕咕咕中 + +--- + +# 免责声明 + +1. `miao-plugin`自身的UI与代码均开放,无需征得特殊同意,可任意使用。能备注来源最好,但不强求 +2. 以上声明但仅代表`miao-plugin`自身的范畴,请尊重Yunzai本体及其他插件作者的努力,勿将Yunzai及其他插件用于以盈利为目的的场景 +3. miao-plugin的图片与其他素材均来自于网络,仅供交流学习使用,如有侵权请联系,会立即删除 + +# 资源 + +* [Miao-Yunzai](https://github.com/yoimiya-kokomi/Miao-Yunzai) : 喵版Yunzai [Gitee](https://gitee.com/yoimiya-kokomi/Miao-Yunzai) + / [Github](https://github.com/yoimiya-kokomi/Miao-Yunzai) +* [Yunzai-V3](https://github.com/yoimiya-kokomi/Yunzai-Bot) :Yunzai V3 - 喵喵维护版(使用 icqq) +* [Yunzai-V3](https://gitee.com/Le-niao/Yunzai-Bot) :Yunzai V3 - 乐神原版(使用 oicq) +* [miao-plugin](https://github.com/yoimiya-kokomi/miao-plugin) : 喵喵插件 [Gitee](https://gitee.com/yoimiya-kokomi/miao-plugin) + / [Github](https://github.com/yoimiya-kokomi/miao-plugin) + +# 其他&感谢 + +* [Enka.Network](https://enka.network/): 感谢Enka提供的面板服务 +* [Snap.Hutao](https://hut.ao/) : 感谢 DGP Studio 开发的 [胡桃 API](https://github.com/DGP-Studio/Snap.Hutao.Server) +* QQ群(暂时停止新加入,请见谅) + * Yunzai-Bot 官方QQ群:213938015 + * 喵喵Miao-Plugin QQ群:607710456 +* [爱发电](https://afdian.net/@kokomi) :欢迎老板打赏,喵~ + diff --git a/Yunzai/plugins/miao-plugin/apps/admin.js b/Yunzai/plugins/miao-plugin/apps/admin.js new file mode 100644 index 0000000000000000000000000000000000000000..da30af4cb9a26fa81f287689f51dca19fde2a9de --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/admin.js @@ -0,0 +1,204 @@ +import fs from 'fs' +import lodash from 'lodash' +import { exec } from 'child_process' +import { Cfg, Common, Data, Version, App } from '#miao' +import fetch from 'node-fetch' + +let keys = lodash.map(Cfg.getCfgSchemaMap(), (i) => i.key) +let app = App.init({ + id: 'admin', + name: '喵喵设置', + desc: '喵喵设置' +}) + +let sysCfgReg = new RegExp(`^#喵喵设置\\s*(${keys.join('|')})?\\s*(.*)$`) + +app.reg({ + updateRes: { + rule: /^#喵喵(强制)?(更新图像|图像更新)$/, + fn: updateRes, + desc: '【#管理】更新素材' + }, + update: { + rule: /^#喵喵(强制)?更新$/, + fn: updateMiaoPlugin, + desc: '【#管理】喵喵更新' + }, + sysCfg: { + rule: sysCfgReg, + fn: sysCfg, + desc: '【#管理】系统设置' + }, + miaoApiInfo: { + rule: /^#喵喵api$/, + fn: miaoApiInfo, + desc: '【#管理】喵喵Api' + } +}) + +export default app + +const _path = process.cwd() +const resPath = `${_path}/plugins/miao-plugin/resources/` +const plusPath = `${resPath}/miao-res-plus/` + +const checkAuth = async function (e) { + if (!e.isMaster) { + e.reply(`只有主人才能命令喵喵哦~ + (*/ω\*)`) + return false + } + return true +} + +async function sysCfg (e) { + if (!await checkAuth(e)) { + return true + } + + let cfgReg = sysCfgReg + let regRet = cfgReg.exec(e.msg) + let cfgSchemaMap = Cfg.getCfgSchemaMap() + + if (!regRet) { + return true + } + + if (regRet[1]) { + // 设置模式 + let val = regRet[2] || '' + + let cfgSchema = cfgSchemaMap[regRet[1]] + if (cfgSchema.input) { + val = cfgSchema.input(val) + } else { + val = cfgSchema.type === 'num' ? (val * 1 || cfgSchema.def) : !/关闭/.test(val) + } + Cfg.set(cfgSchema.cfgKey, val) + } + + let schema = Cfg.getCfgSchema() + let cfg = Cfg.getCfg() + let imgPlus = fs.existsSync(plusPath) + + // 渲染图像 + return await Common.render('admin/index', { + schema, + cfg, + imgPlus, + isMiao: Version.isMiao + }, { e, scale: 1.4 }) +} + +async function updateRes (e) { + if (!await checkAuth(e)) { + return true + } + let isForce = e.msg.includes('强制') + let command = '' + if (fs.existsSync(`${resPath}/miao-res-plus/`)) { + e.reply('开始尝试更新,请耐心等待~') + command = 'git pull' + if (isForce) { + command = 'git checkout . && git pull' + } + exec(command, { cwd: `${resPath}/miao-res-plus/` }, function (error, stdout, stderr) { + console.log(stdout) + if (/(Already up[ -]to[ -]date|已经是最新的)/.test(stdout)) { + e.reply('目前所有图片都已经是最新了~') + return true + } + let numRet = /(\d*) files changed,/.exec(stdout) + if (numRet && numRet[1]) { + e.reply(`报告主人,更新成功,此次更新了${numRet[1]}个图片~`) + return true + } + if (error) { + e.reply('更新失败!\nError code: ' + error.code + '\n' + error.stack + '\n 请稍后重试。') + } else { + e.reply('图片加量包更新成功~') + } + }) + } else { + command = `git clone https://gitee.com/yoimiya-kokomi/miao-res-plus.git "${resPath}/miao-res-plus/" --depth=1` + e.reply('开始尝试安装图片加量包,可能会需要一段时间,请耐心等待~') + exec(command, function (error, stdout, stderr) { + if (error) { + e.reply('角色图片加量包安装失败!\nError code: ' + error.code + '\n' + error.stack + '\n 请稍后重试。') + } else { + e.reply('角色图片加量包安装成功!您后续也可以通过 #喵喵更新图像 命令来更新图像') + } + }) + } + return true +} + +let timer + +async function updateMiaoPlugin (e) { + if (!await checkAuth(e)) { + return true + } + let isForce = e.msg.includes('强制') + let command = 'git pull' + if (isForce) { + command = 'git checkout . && git pull' + e.reply('正在执行强制更新操作,请稍等') + } else { + e.reply('正在执行更新操作,请稍等') + } + exec(command, { cwd: `${_path}/plugins/miao-plugin/` }, function (error, stdout, stderr) { + if (/(Already up[ -]to[ -]date|已经是最新的)/.test(stdout)) { + e.reply('目前已经是最新版喵喵了~') + return true + } + if (error) { + e.reply('喵喵更新失败!\nError code: ' + error.code + '\n' + error.stack + '\n 请稍后重试。') + return true + } + e.reply('喵喵更新成功,正在尝试重新启动Yunzai以应用更新...') + timer && clearTimeout(timer) + Data.setCacheJSON('miao:restart-msg', { + msg: '重启成功,新版喵喵已经生效', + qq: e.user_id + }, 30) + timer = setTimeout(function () { + let command = 'npm run start' + if (process.argv[1].includes('pm2')) { + command = 'npm run restart' + } + exec(command, function (error, stdout, stderr) { + if (error) { + e.reply('自动重启失败,请手动重启以应用新版喵喵。\nError code: ' + error.code + '\n' + error.stack + '\n') + Bot.logger.error(`重启失败\n${error.stack}`) + return true + } else if (stdout) { + Bot.logger.mark('重启成功,运行已转为后台,查看日志请用命令:npm run log') + Bot.logger.mark('停止后台运行命令:npm stop') + process.exit() + } + }) + }, 1000) + }) + return true +} + +async function miaoApiInfo (e) { + if (!await checkAuth(e)) { + return true + } + let { diyCfg } = await Data.importCfg('profile') + let { qq, token } = (diyCfg?.miaoApi || {}) + if (!qq || !token) { + return e.reply('未正确填写miaoApi token,请检查miao-plugin/config/profile.js文件') + } + if (token.length !== 32) { + return e.reply('miaoApi token格式错误') + } + let req = await fetch(`http://miao.games/api/info?qq=${qq}&token=${token}`) + let data = await req.json() + if (data.status !== 0) { + return e.reply('token检查错误,请求失败') + } + e.reply(data.msg) +} diff --git a/Yunzai/plugins/miao-plugin/apps/character.js b/Yunzai/plugins/miao-plugin/apps/character.js new file mode 100644 index 0000000000000000000000000000000000000000..88a38a9dede0b51c9de3c61bdfda9e588dc59157 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/character.js @@ -0,0 +1,36 @@ +import { uploadCharacterImg } from './character/ImgUpload.js' +import { getOriginalPicture } from './profile/ProfileUtils.js' +import Avatar from './character/AvatarCard.js' +import Wife from './character/AvatarWife.js' +import { App } from '#miao' + +let app = App.init({ + id: 'character', + name: '角色查询' +}) + +app.reg({ + character: { + rule: /^#喵喵角色卡片$/, + fn: Avatar.render, + check: Avatar.check, + name: '角色卡片' + }, + uploadImg: { + rule: /^#*(喵喵)?(上传|添加)(.+)(照片|写真|图片|图像)\s*$/, + fn: uploadCharacterImg, + name: '上传角色写真' + }, + wife: { + rule: Wife.reg, + fn: Wife.render, + describe: '#老公 #老婆 查询' + }, + originalPic: { + rule: /^#?(获取|给我|我要|求|发|发下|发个|发一下)?原图(吧|呗)?$/, + fn: getOriginalPicture, + describe: '【#原图】 回复角色卡片,可获取原图' + } +}) + +export default app diff --git a/Yunzai/plugins/miao-plugin/apps/character/AvatarCard.js b/Yunzai/plugins/miao-plugin/apps/character/AvatarCard.js new file mode 100644 index 0000000000000000000000000000000000000000..ea94d581a4edcae7087335a2b97f5b21392e3ac9 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/character/AvatarCard.js @@ -0,0 +1,132 @@ +import { Character, MysApi, Player } from '#miao.models' +import { Cfg, Common } from '#miao' +import lodash from 'lodash' +import moment from 'moment' + +let Avatar = { + render (e) { + if (!e.char) { + return false + } + return Avatar.renderAvatar(e, e.char?.name) + }, + async renderAvatar (e, avatar, renderType = 'card') { + // 如果传递的是名字,则获取 + if (typeof (avatar) === 'string') { + // 检查角色 + let char = Character.get(avatar) + if (!char) { + return false + } + let mys = await MysApi.init(e) + if (!mys) return true + if (!char.isRelease) { + avatar = { id: char.id, name: char.name, detail: false } + } else { + let player = Player.create(e) + await player.refreshMysDetail(1) + await player.refreshTalent(char.id, 1) + avatar = player.getAvatar(char.id) + if (!avatar) { + avatar = { id: char.id, name: char.name, detail: false } + } + } + } + return await Avatar.renderCard(e, avatar, renderType) + }, + + async renderCard (e, avatar, renderType = 'card') { + let char = Character.get(avatar.id) + if (!char) { + return false + } + let bg = char.getCardImg(Cfg.get('charPicSe', false)) + if (renderType === 'photo') { + e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/${bg.img}`)) + return true + } + let uid = e.uid || (e.targetUser && e.targetUser.uid) + let data = {} + let custom = char.isCustom + let isRelease = char.isRelease + if (isRelease && avatar.hasData) { + data = avatar.getDetail() + data.imgs = char.imgs + data.source = avatar._source + data.artis = avatar.getArtisDetail() + data.updateTime = moment(new Date(avatar._time)).format('MM-DD HH:mm') + if (data.hasTalent) { + data.talent = avatar.talent + data.talentMap = ['a', 'e', 'q'] + // 计算皇冠个数 + data.crownNum = lodash.filter(lodash.map(data.talent, (d) => d.original), (d) => d >= 10).length + } + } else { + data = char.getData('id,name,sName') + } + + let width = 600 + let imgCss = '' + let scale = 1.2 + if (bg.mode === 'left') { + const height = 480 + width = height * bg.width / bg.height + imgCss = `img.bg{width:auto;height:${height}px;}` + scale = 1.45 + } + // 渲染图像 + let msgRes = await Common.render('character/character-card', { + saveId: uid, + uid, + bg, + widthStyle: ``, + mode: bg.mode, + custom, + isRelease, + data + }, { e, scale, retMsgId: true }) + if (msgRes) { + // 如果消息发送成功,就将message_id和图片路径存起来,3小时过期 + const message_id = [e.message_id] + if (Array.isArray(msgRes.message_id)) { + message_id.push(...msgRes.message_id) + } else { + message_id.push(msgRes.message_id) + } + for (const i of message_id) { + await redis.set(`miao:original-picture:${i}`, JSON.stringify({ type: 'character', img: bg.img }), { EX: 3600 * 3 }) + } + } + return true + }, + check (e) { + let msg = e.original_msg || e.msg + if (!msg || !/^#/.exec(msg)) { + return false + } + if (!Common.cfg('avatarCard')) { + return false + } + let uidRet = /[0-9]{9}/.exec(msg) + if (uidRet) { + e.uid = uidRet[0] + msg = msg.replace(uidRet[0], '') + } + let name = msg.replace(/#|老婆|老公|卡片/g, '').trim() + + // cache gsCfg + Character.gsCfg = Character.gsCfg || e?.runtime?.gsCfg + + let char = Character.get(name.trim()) + + if (!char) { + return false + } + + e.msg = '#喵喵角色卡片' + e.char = char + return true + } + +} +export default Avatar diff --git a/Yunzai/plugins/miao-plugin/apps/character/AvatarWife.js b/Yunzai/plugins/miao-plugin/apps/character/AvatarWife.js new file mode 100644 index 0000000000000000000000000000000000000000..6ac144ba2266b565647e28abd717ebf172968533 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/character/AvatarWife.js @@ -0,0 +1,188 @@ +// #老婆 +import lodash from 'lodash' +import { Common } from '#miao' +import { Character, MysApi, Player } from '#miao.models' +import Avatar from './AvatarCard.js' + +const relationMap = { + wife: { + keyword: '老婆,媳妇,妻子,娘子,宝贝'.split(','), + type: 0 + }, + husband: { + keyword: '老公,丈夫,夫君,郎君,死鬼'.split(','), + type: 1 + }, + gf: { + keyword: '女朋友,女友,女神,女王,女票'.split(','), + type: 0 + }, + bf: { + keyword: '男朋友,男友,男神,男票'.split(','), + type: 1 + }, + daughter: { + keyword: '女儿,闺女,小宝贝'.split(','), + type: 2 + }, + son: { + keyword: '儿子,犬子'.split(','), + type: 3 + } +} + +const relation = lodash.flatMap(relationMap, (d) => d.keyword) +const wifeReg = `^#?\\s*(${relation.join('|')})\\s*(设置|选择|指定|列表|查询|列表|是|是谁|照片|相片|图片|写真|图像)?\\s*([^\\d]*)\\s*(\\d*)$` + +async function getAvatarList (player, type) { + await player.refreshMysDetail() + let list = [] + player.forEachAvatar((avatar) => { + if (type !== false) { + if (!avatar.char.checkWifeType(type)) { + return true + } + } + list.push(avatar) + }) + + if (list.length <= 0) { + return false + } + let sortKey = 'level,fetter,weapon_level,rarity,weapon_rarity,cons,weapon_affix_level' + list = lodash.orderBy(list, sortKey, lodash.repeat('desc,', sortKey.length).split(',')) + return list +} + +const Wife = { + reg: wifeReg, + async render (e) { + let msg = e.msg || '' + if (!msg && !e.isPoke) return false + + if (e.isPoke) { + if (!Common.cfg('avatarPoke')) { + return false + } + } else if (!Common.cfg('avatarCard')) { + return false + } + + let msgRet = (new RegExp(wifeReg)).exec(msg) + if (e.isPoke) { + msgRet = [] + } else if (!msgRet) { + return false + } + let target = msgRet[1] + let action = msgRet[2] || '卡片' + let actionParam = msgRet[3] || '' + + if (!'设置,选择,挑选,指定'.split(',').includes(action) && actionParam) { + return false + } + + let targetCfg = lodash.find(relationMap, (cfg, key) => { + cfg.key = key + return cfg.keyword.includes(target) + }) + if (!targetCfg && !e.isPoke) return true + + let avatarList = [] + let avatar = {} + let wifeList = [] + + let mys = await MysApi.init(e) + if (!mys || !mys.uid) { + return true + } + let player = Player.create(e) + let selfUser = mys.selfUser + let isSelf = true + let renderType = (action === '卡片' ? 'card' : 'photo') + let addRet = [] + switch (action) { + case '卡片': + case '照片': + case '相片': + case '图片': + case '写真': + // 展示老婆卡片 + // 如果选择过,则进行展示 + if (!e.isPoke) { + wifeList = await selfUser.getCfg(`wife.${targetCfg.key}`, []) + // 存在设置 + if (wifeList && wifeList.length > 0 && isSelf && !e.isPoke) { + if (wifeList[0] === '随机') { + // 如果选择为全部,则从列表中随机选择一个 + avatarList = await getAvatarList(player, targetCfg.type, mys) + let avatar = lodash.sample(avatarList) + return Avatar.renderAvatar(e, avatar, renderType) + } else { + // 如果指定过,则展示指定角色 + return Avatar.renderAvatar(e, lodash.sample(wifeList), renderType) + } + } + } + // 如果未指定过,则从列表中排序并随机选择 + avatarList = await getAvatarList(player, e.isPoke ? false : targetCfg.type, mys) + if (avatarList && avatarList.length > 0) { + avatar = lodash.sample(avatarList) + return await Avatar.renderAvatar(e, avatar, renderType) + } + e.reply('在当前米游社公开展示的角色中未能找到适合展示的角色..') + return true + case '设置': + case '选择': + case '挑选': + case '指定': + if (!isSelf) { + e.reply('只能指定自己的哦~') + return true + } + // 选择老婆 + actionParam = actionParam.replace(/(,|、|;|;)/g, ',') + wifeList = actionParam.split(',') + if (lodash.intersection(['全部', '任意', '随机', '全都要'], wifeList).length > 0) { + addRet = ['随机'] + } else { + wifeList = lodash.map(wifeList, (name) => { + let char = Character.get(name) + if (char && char.checkWifeType(targetCfg.type)) { + return char.name + } + }) + wifeList = lodash.filter(lodash.uniq(wifeList), (d) => !!d) + addRet = wifeList + if (addRet.length === 0) { + e.reply(`在可选的${targetCfg.keyword[0]}列表中未能找到 ${actionParam} ~`) + return true + } + } + await selfUser.setCfg(`wife.${targetCfg.key}`, addRet) + e.reply(`${targetCfg.keyword[0]}已经设置:${addRet.join(',')}`) + return true + case '列表': + case '是': + case '是谁': + // 查看当前选择老婆 + if (!isSelf) { + e.reply('只能查看自己的哦~') + return true + } + wifeList = await selfUser.getCfg(`wife.${targetCfg.key}`, []) + if (wifeList && wifeList.length > 0) { + e.reply(`你的${targetCfg.keyword[0]}是:${wifeList.join(',')}`) + } else { + e.reply(`尚未设置,回复#${targetCfg.keyword[0]}设置+角色名 来设置,如果设置多位请用逗号间隔`) + } + break + } + return true + }, + async poke (e) { + return await Wife.render(e) + } +} + +export default Wife diff --git a/Yunzai/plugins/miao-plugin/apps/character/ImgUpload.js b/Yunzai/plugins/miao-plugin/apps/character/ImgUpload.js new file mode 100644 index 0000000000000000000000000000000000000000..68190a5ef473bc787dcc96368be9b2f3cd4be0ff --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/character/ImgUpload.js @@ -0,0 +1,258 @@ +import fs from 'fs' +import { promisify } from 'util' +import { pipeline } from 'stream' +import MD5 from 'md5' +import fetch from 'node-fetch' +import lodash from 'lodash' +import { Cfg, Data } from '#miao' +import { Character } from '#miao.models' + +const resPath = process.cwd() + '/plugins/miao-plugin/resources/' +let regex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:照片|写真|图片|图像)\s*$/ +let profileRegex = /^#?\s*(?:喵喵)?(?:上传|添加)(.+)(?:面板图)\s*$/ +let isProfile = false + +export async function uploadCharacterImg (e) { + let promise = await isAllowedToUploadCharacterImage(e) + if (!promise) { + return false + } + + let imageMessages = [] + let msg = e.msg + let regRet = regex.exec(msg) + if (msg.includes('面板')) { + isProfile = true + regRet = profileRegex.exec(msg) + } else { + isProfile = false + } + + // 通过解析正则获取消息中的角色名 + if (!regRet || !regRet[1]) { + return false + } + let char = Character.get(regRet[1]) + if (!char || !char.name) { + return false + } + let name = char.name + for (let val of e.message) { + if (val.type === 'image') { + imageMessages.push(val) + } + } + if (imageMessages.length === 0) { + let source + if (e.getReply) { + source = await e.getReply() + } else if (e.source) { + if (e.group?.getChatHistory) { + // 支持at图片添加,以及支持后发送 + source = (await e.group.getChatHistory(e.source?.seq, 1)).pop() + } else if (e.friend?.getChatHistory) { + source = (await e.friend.getChatHistory((e.source?.time + 1), 1)).pop() + } + } + if (source) { + for (let val of source.message) { + if (val.type === 'image') { + imageMessages.push(val) + } else if (val.type === 'xml' || val.type === 'forward') {// 支持合并转发消息内置的图片批量上传,喵喵 喵喵喵? 喵喵喵喵 + let resid + try { + resid = val.data.match(/m_resid="(\d|\w|\/|\+)*"/)[0].replace(/m_resid=|"/g, '') + } catch (err) { + console.log('Miao合并上传:转换id获取') + resid = val.id + } + if (!resid) break + let message = await e.bot.getForwardMsg(resid) + for (const item of message) { + for (const i of item.message) { + if (i.type === 'image') { + imageMessages.push(i) + } + } + } + } + } + } + } + if (imageMessages.length <= 0) { + e.reply('消息中未找到图片,请将要发送的图片与消息一同发送或引用要添加的图像..') + return true + } + await saveImages(e, name, imageMessages) + return true +} + +async function saveImages (e, name, imageMessages) { + let imgMaxSize = e?.groupConfig?.imgMaxSize || 5 + let pathSuffix = `character-img/${name}/upload` + if (isProfile) pathSuffix = `profile/normal-character/${name}` + let path = resPath + pathSuffix + + if (!fs.existsSync(path)) { + Data.createDir("resources/" + pathSuffix, 'miao') + } + let senderName = lodash.truncate(e.sender.card, { length: 8 }) + let imgCount = 0 + let urlMap = {} + for (let val of imageMessages) { + if (!val.url || urlMap[val.url]) { + continue + } + urlMap[val.url] = true + const response = await fetch(val.url) + if (!response.ok) { + e.reply('图片下载失败。') + return true + } + if (response.headers.get('size') > 1024 * 1024 * imgMaxSize) { + e.reply([segment.at(e.user_id, senderName), '添加失败:图片太大了。']) + return true + } + let fileName = "" + let fileType = "png" + if (val.file) { + fileName = val.file.substring(0, val.file.lastIndexOf('.')) + fileType = val.file.substring(val.file.lastIndexOf('.') + 1) + } + if (response.headers.get('content-type') === 'image/gif') { + fileType = 'gif' + } + if (isProfile) fileType = 'webp' + let imgPath = `${path}/${fileName}.${fileType}` + const streamPipeline = promisify(pipeline) + await streamPipeline(response.body, fs.createWriteStream(imgPath)) + + // 使用md5作为文件名 + let buffers = fs.readFileSync(imgPath) + let base64 = Buffer.from(buffers, 'base64').toString() + let md5 = MD5(base64) + let newImgPath = `${path}/${md5}.${fileType}` + if (fs.existsSync(newImgPath)) { + fs.unlink(newImgPath, (err) => { + console.log('unlink', err) + }) + } + fs.rename(imgPath, newImgPath, () => { + }) + imgCount++ + Bot.logger.mark(`添加成功: ${newImgPath}`) + } + e.reply([segment.at(e.user_id, senderName), `\n成功添加${imgCount}张${name}${isProfile ? '面板图' : '图片'}。`]) + return true +} + +async function isAllowedToUploadCharacterImage (e) { + let sendMsg = /上传|添加/.test(e.msg) ? '添加' : '删除' + if (!e.message) { + return false + } + if (!e.msg) { + return false + } + // master直接返回true + if (e.isMaster) { + return true + } + if (e.isPrivate) { + e.reply(`只有主人才能${sendMsg}...`) + return false + } + let groupId = e.group_id + if (!groupId) { + return false + } + const addLimit = e.groupConfig?.imgAddLimit || 2 + const isAdmin = ['owner', 'admin'].includes(e.sender.role) + if (addLimit === 2) { + e.reply(`只有主人才能${sendMsg}...`) + return false + } + if (addLimit === 1 && !isAdmin) { + e.reply(`只有管理员才能${sendMsg}...`) + return false + } + return true +} + +// 仅支持面板图删除 +export async function delProfileImg (e) { + let promise = await isAllowedToUploadCharacterImage(e) + if (!promise) { + return false + } + let char = Character.get(e.msg.replace(/#|面板图|列表|上传|删除|\d+/g, '').trim()) + if (!char || !char.name) { + return false + } + let name = char.name + let pathSuffix = `profile/normal-character/${name}` + let path = resPath + pathSuffix + let num = e.msg.match(/\d+/) + if (!num) { + e.reply(`删除哪张捏?请输入数字序列号,可输入【#${name}面板图列表】查看序列号`) + return + } + try { + let imgs = fs.readdirSync(`${path}`).filter((file) => { + return /\.(png|webp)$/.test(file) + }) + fs.unlinkSync(`${path}/${imgs[num - 1]}`) + e.reply('删除成功') + } catch (err) { + e.reply('删除失败,请检查序列号是否正确') + } + return true +} + +export async function profileImgList (e) { + let msglist = [] + let char = Character.get(e.msg.replace(/#|面板图列表/g, '')) + if (!char || !char.name) { + return false + } + if ([1, 0].includes(Cfg.get('originalPic') * 1)) { + e.reply('已禁止获取面板图列表') + return true + } + let name = char.name + let pathSuffix = `profile/normal-character/${name}` + let path = resPath + pathSuffix + if (!fs.existsSync(path)) { + e.reply(`暂无${char.name}的角色面板图`) + return true + } + try { + let imgs = fs.readdirSync(`${path}`).filter((file) => { + return /\.(png|webp)$/.test(file) + }) + msglist.push({ + message: [`当前查看的是${name}面板图,共${imgs.length}张,可输入【#删除${name}面板图(序列号)】进行删除`], + }) + for (let i = 0; i < imgs.length; i++) { + // 合并转发最多99? 但是我感觉不会有这么多先不做处理 + console.log(`${path}${imgs[i]}`) + msglist.push({ + message: [`${i + 1}.`, segment.image(`file://${path}/${imgs[i]}`)], + }) + } + let msg + if (e.group?.makeForwardMsg) { + msg = await e.group.makeForwardMsg(msglist) + } else if (e.friend?.makeForwardMsg) { + msg = await e.friend.makeForwardMsg(msglist) + } else { + msg = await Bot.makeForwardMsg(msglist) + } + let msgRsg = await e.reply(msg) + if (!msgRsg) e.reply('风控了,可私聊查看', true) + } catch (err) { + logger.error(err) + e.reply(`暂无${char.name}的角色面板图~`) + } + return true +} diff --git a/Yunzai/plugins/miao-plugin/apps/gacha.js b/Yunzai/plugins/miao-plugin/apps/gacha.js new file mode 100644 index 0000000000000000000000000000000000000000..7ae93ddc4f9b70a86af7f0106d2b581d78ae750a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/gacha.js @@ -0,0 +1,26 @@ +import Gacha from './gacha/Gacha.js' +import { App, Cfg } from '#miao' + +let app = App.init({ + id: 'gacha', + name: '抽卡统计' +}) +app.reg({ + detail: { + name: '抽卡记录', + fn: Gacha.detail, + rule: /^#*喵喵(抽卡|抽奖|角色|武器|常驻|up)+池?(记录|祈愿|分析)$/, + yzRule: /^#*(抽卡|抽奖|角色|武器|常驻|up)+池?(记录|祈愿|分析)$/, + yzCheck: () => Cfg.get('gachaStat', false) + }, + stat: { + name: '抽卡统计', + fn: Gacha.stat, + rule: /^#*喵喵(全部|抽卡|抽奖|角色|武器|常驻|up|版本)+池?统计$/, + yzRule: /^#*(全部|抽卡|抽奖|角色|武器|常驻|up|版本)+池?统计$/, + yzCheck: () => Cfg.get('gachaStat', false) + + } +}) + +export default app diff --git a/Yunzai/plugins/miao-plugin/apps/gacha/Gacha.js b/Yunzai/plugins/miao-plugin/apps/gacha/Gacha.js new file mode 100644 index 0000000000000000000000000000000000000000..d4b7f2b767581bea09efb90c87b3a51330819ba8 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/gacha/Gacha.js @@ -0,0 +1,90 @@ +import { Common } from '#miao' +import { getTargetUid } from '../profile/ProfileCommon.js' +import GachaData from './GachaData.js' +import { Character, Player } from '#miao.models' + +let Gacha = { + async detail (e) { + let msg = e.msg.replace(/#|抽卡|记录|祈愿|分析|池/g, '') + let type = 301 + switch (msg) { + case 'up': + case '抽卡': + case '角色': + case '抽奖': + type = 301 + break + case '常驻': + type = 200 + break + case '武器': + type = 302 + break + } + let uid = e.uid || await getTargetUid(e) + let qq = e.user_id + if (!uid || !qq) { + return false + } + + let gacha = GachaData.analyse(e.user_id, uid, type) + if (!gacha) { + e.reply(`UID:${uid} 本地暂无抽卡信息,请通过【#抽卡帮助】获得绑定帮助...`) + return true + } + await Common.render('gacha/gacha-detail', { + save_id: uid, + uid, + gacha, + face: Gacha.getFace(uid) + }, { e, scale: 1.4, retMsgId: true }) + }, + async stat (e) { + let msg = e.msg.replace(/#|统计|分析|池/g, '') + let type = 'up' + if (/武器/.test(msg)) { + type = 'weapon' + } else if (/角色/.test(msg)) { + type = 'char' + } else if (/常驻/.test(msg)) { + type = 'normal' + } else if (/全部/.test(msg)) { + type = 'all' + } + let uid = e.uid || await getTargetUid(e) + let qq = e.user_id + if (!uid || !qq) { + return false + } + let gacha = GachaData.stat(e.user_id, uid, type) + if (!gacha) { + e.reply(`UID:${uid} 本地暂无抽卡信息,请通过【#抽卡帮助】获得绑定帮助...`) + return true + } + await Common.render('gacha/gacha-stat', { + save_id: uid, + uid, + gacha, + face: Gacha.getFace(uid) + }, { e, scale: 1.4 }) + }, + + getFace (uid) { + let player = Player.create(uid) + + let faceChar = Character.get(player.face || 10000014) + let imgs = faceChar?.imgs + if (!imgs?.face) { + imgs = Character.get(10000079).imgs + } + return { + banner: imgs?.banner, + face: imgs?.face, + qFace: imgs?.qFace, + name: player.name || '旅行者', + sign: player.sign, + level: player.level + } + } +} +export default Gacha diff --git a/Yunzai/plugins/miao-plugin/apps/gacha/GachaData.js b/Yunzai/plugins/miao-plugin/apps/gacha/GachaData.js new file mode 100644 index 0000000000000000000000000000000000000000..55188f39bbb8cfd39ebfc0963e947df656eaa2b2 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/gacha/GachaData.js @@ -0,0 +1,444 @@ +import lodash from 'lodash' +import { Data } from '#miao' +import { Character, Weapon } from '#miao.models' +import { poolDetail } from '../../resources/meta/info/index.js' +import moment from 'moment' + +let poolVersion = [] +lodash.forEach(poolDetail, (ds) => { + poolVersion.push({ + ...ds, + start: new Date(ds.from), + end: new Date(ds.to) + }) +}) +let last = poolVersion[poolVersion.length - 1] +// 为未知卡池做兼容 +poolVersion.push({ + version: '新版本', + half: '?', + from: last.to, + to: '2025-12-31 23:59:59', + start: last.end, + end: new Date('2025-12-31 23:59:59') +}) + +let GachaData = { + + // 获取JSON数据 + readJSON (qq, uid, type) { + let logJson = [] + // 获取本地数据 进行数据合并 + logJson = Data.readJSON(`/data/gachaJson/${qq}/${uid}/${type}.json`, 'root') + let itemMap = {} + let nameMap = {} + let items = [] + let ids = {} + lodash.forEach(logJson, (ds) => { + if (!nameMap[ds.name]) { + if (ds.item_type === '武器') { + let weapon = Weapon.get(ds.name) + if (weapon) { + nameMap[ds.name] = weapon.id + itemMap[weapon.id] = { + type: 'weapon', + count: 0, + ...weapon.getData('star,name,abbr,img') + } + } else { + nameMap[ds.name] = 403 + itemMap[403] = { + type: 'weapon', + count: 0, + star: 3, + name: '未知', + abbr: '未知', + img: '' + } + } + } else if (ds.item_type === '角色') { + let char = Character.get(ds.name) + if (char) { + nameMap[ds.name] = char.id + itemMap[char.id] = { + type: 'char', + count: 0, + ...char.getData('star,name,abbr,img:face') + } + } else { + nameMap[ds.name] = 404 + itemMap[404] = { + type: 'char', + count: 0, + star: 4, + name: '未知', + abbr: '未知', + img: '' + } + } + } + } + let id = nameMap[ds.name] + if (!id || !itemMap[id] || (ds.id && ids[ds.id])) { + return true + } + ids[ds.id] = true + items.push({ + id, + logId: ds.id, + time: new Date(ds.time) + }) + }) + items = items.sort((a, b) => b.time - a.time) + return { items, itemMap } + }, + + // 卡池分析 + analyse (qq, uid, type) { + let logData = GachaData.readJSON(qq, uid, type) + let fiveLog = [] + let fourLog = [] + let fiveNum = 0 + let fourNum = 0 + let fiveLogNum = 0 + let fourLogNum = 0 + let noFiveNum = 0 + let noFourNum = 0 + let wai = 0 // 歪 + let weaponNum = 0 + let weaponFourNum = 0 + let bigNum = 0 + let allNum = 0 + + let itemMap = logData.itemMap + if (logData.items.length === 0) { + return false + } + let currVersion + lodash.forEach(logData.items, (item) => { + if (!currVersion || (item.time < currVersion.start)) { + currVersion = GachaData.getVersion(item.time) + } + + allNum++ + let ds = itemMap[item.id] + let { star, type } = ds + ds.count++ + if (star === 4) { + fourNum++ + if (noFourNum === 0) { + noFourNum = fourLogNum + } + fourLogNum = 0 + if (fourLog[ds.name]) { + fourLog[ds.name]++ + } else { + fourLog[ds.name] = 1 + } + if (type === 'weapon') { + weaponFourNum++ + } + } + fourLogNum++ + + if (star === 5) { + fiveNum++ + if (fiveLog.length > 0) { + fiveLog[fiveLog.length - 1].count = fiveLogNum + } else { + noFiveNum = fiveLogNum + } + fiveLogNum = 0 + let isUp = false + // 歪了多少个 + if (type === 'char') { + if (!currVersion.hasOwnProperty("char5") || currVersion.char5.includes(ds.name)) { + isUp = true + } else { + wai++ + } + } else { + if (currVersion.weapon5.includes(ds.name)) { + isUp = true + } else { + wai++ + } + } + + fiveLog.push({ + id: item.id, + isUp, + date: moment(item.time).format('MM-DD') + }) + } + fiveLogNum++ + }) + + if (fiveLog.length > 0) { + fiveLog[fiveLog.length - 1].count = fiveLogNum + } else { + // 没有五星 + noFiveNum = allNum + } + + // 四星最多 + let fourItem = lodash.filter(lodash.values(itemMap), (ds) => ds.star === 4) + fourItem.push({ name: '无', count: 0 }) + fourItem = fourItem.sort((a, b) => b.count - a.count) + + // 平均5星 + let fiveAvg = 0 + let fourAvg = 0 + if (fiveNum > 0) { + fiveAvg = ((allNum - noFiveNum) / fiveNum).toFixed(2) + } + // 平均四星 + if (fourNum > 0) { + fourAvg = ((allNum - noFourNum) / fourNum).toFixed(2) + } + + // 有效抽卡 + let isvalidNum = 0 + if (fiveNum > 0 && fiveNum > wai) { + if (fiveLog.length > 0 && !fiveLog[0].isUp) { + isvalidNum = (allNum - noFiveNum - fiveLog[0].count) / (fiveNum - wai) + } else { + isvalidNum = (allNum - noFiveNum) / (fiveNum - wai) + } + isvalidNum = isvalidNum.toFixed(2) + } + + let upYs = isvalidNum * 160 + if (upYs >= 10000) { + upYs = (upYs / 10000).toFixed(2) + 'w' + } else { + upYs = upYs.toFixed(0) + } + + // 小保底不歪概率 + let noWaiRate = 0 + if (fiveNum > 0) { + noWaiRate = (fiveNum - bigNum - wai) / (fiveNum - bigNum) + noWaiRate = (noWaiRate * 100).toFixed(1) + } + + if (noFiveNum > 0) { + fiveLog.unshift({ + id: 888, + isUp: true, + count: noFiveNum, + date: moment().format('MM-DD') + }) + itemMap['888'] = { + name: '已抽', + star: 5, + abbr: '已抽', + img: 'gacha/imgs/no-avatar.webp' + } + } + + return { + stat: { + allNum, + noFiveNum, + noFourNum, + fiveNum, + fourNum, + fiveAvg, + fourAvg, + wai, + isvalidNum, + weaponNum, + weaponFourNum, + upYs + }, + maxFour: fourItem[0], + fiveLog, + noWaiRate, + items: itemMap + } + }, + + // 卡池统计 + stat (qq, uid, type) { + let items = [] + let itemMap = {} + let hasVersion = true + let loadData = function (poolId) { + let gachaData = GachaData.readJSON(qq, uid, poolId) + items = items.concat(gachaData.items) + lodash.extend(itemMap, gachaData.itemMap || {}) + } + if (['up', 'char', 'all'].includes(type)) { + loadData(301) + } + if (['up', 'weapon', 'all'].includes(type)) { + loadData(302) + } + if (['all', 'normal'].includes(type)) { + hasVersion = false + loadData(200) + } + + items = items.sort((a, b) => b.time - a.time) + + let versionData = [] + let currVersion + + if (lodash.isEmpty(items)) { + return false + } + + let getCurr = function () { + if (currVersion && !lodash.isEmpty(currVersion)) { + let cv = currVersion + let temp = { + version: cv.version, + half: cv.half, + from: hasVersion ? moment(new Date(cv.from)).format('YY-MM-DD') : '', + to: hasVersion ? moment(new Date(cv.to)).format('YY-MM-DD') : '', + upIds: {} + } + let upName = {} + let items = [] + let poolNames = [] + lodash.forEach(cv.char5, (name) => { + upName[name] = true + let char = Character.get(name) + poolNames.push(char.abbr) + }) + lodash.forEach(cv.weapon5, (name) => { + upName[name] = true + }) + let w5Num = 0 + let w5UpNum = 0 + let c5Num = 0 + let c5UpNum = 0 + let c4Num = 0 + let w4Num = 0 + let w3Num = 0 + lodash.forEach(cv.items, (num, id) => { + let item = itemMap[id] + let isUp = upName[item.name] + let star = item.star + if (isUp) { + temp.upIds[id] = item.name + } + items.push({ id, num, star: item.star, isUp: temp.upIds[id] ? 1 : 0 }) + if (item.type === 'char') { + if (star === 5) { + c5Num += num + isUp && (c5UpNum += num) + } else { + c4Num += num + } + } + if (item.type === 'weapon') { + if (star === 5) { + w5Num += num + isUp && (w5UpNum += num) + } else { + star === 4 ? (w4Num += num) : (w3Num += num) + } + } + }) + temp.name = poolNames.join(' / ') + temp.items = lodash.sortBy(items, ['star', 'num', 'isUp']).reverse() + temp.stats = { + w5Num, + w5UpNum, + c5Num, + c5UpNum, + c4Num, + w4Num, + w3Num, + upNum: w5UpNum + c5UpNum, + star5Num: w5Num + c5Num, + star4Num: w4Num + c4Num, + totalNum: w5Num + w4Num + w3Num + c5Num + c4Num + } + return temp + } + } + + lodash.forEach(items, (ds) => { + if (!currVersion || (ds.time < currVersion.start && hasVersion)) { + if (currVersion) { + versionData.push(getCurr()) + } + let v = GachaData.getVersion(ds.time, hasVersion) + if (!hasVersion) { + v.version = type === 'all' ? '全部统计' : '常驻池' + } + if (!v) { + return true + } + currVersion = { + ...v, + items: {} + } + } + if (!currVersion.items[ds.id]) { + currVersion.items[ds.id] = 1 + } else { + currVersion.items[ds.id]++ + } + }) + versionData.push(getCurr()) + + let stat = {} + lodash.forEach(versionData, (ds) => { + lodash.forEach(ds.stats, (num, key) => { + if (!stat[key]) { + stat[key] = num + } else { + stat[key] += num + } + }) + }) + stat.avgUpNum = stat.upNum === 0 ? 0 : ((stat.totalNum / stat.upNum).toFixed(1)) + + return { + versionData, + itemMap, + totalStat: stat + } + }, + + getVersion (time, hasVersion = true) { + if (hasVersion) { + for (let ds of poolVersion) { + if (time > ds.start && time < ds.end) { + return ds + } + } + } + return { + version: hasVersion === false ? '全部' : '未知', + half: '', + char5: [], + char4: [], + weapon5: [], + weapon4: [] + } + }, + + getItem (ds) { + if (ds.item_type === '武器') { + let weapon = Weapon.get(ds.name) + return { + type: 'weapon', + count: 0, + ...weapon.getData('id,star,name,abbr,img') + } + } else if (ds.item_type === '角色') { + let char = Character.get(ds.name) + return { + type: 'char', + count: 0, + ...char.getData('id,star,name,abbr,face') + } + } + } +} +export default GachaData diff --git a/Yunzai/plugins/miao-plugin/apps/help.js b/Yunzai/plugins/miao-plugin/apps/help.js new file mode 100644 index 0000000000000000000000000000000000000000..7531d6ea7358f2c73439a53e000f7892a77d0650 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/help.js @@ -0,0 +1,23 @@ +import Help from './help/Help.js' +import { App } from '#miao' + +let app = App.init({ + id: 'help', + name: '喵喵帮助', + desc: '喵喵帮助' +}) + +app.reg({ + help: { + rule: /^#?(喵喵)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$/, + fn: Help.render, + desc: '【#帮助】 #喵喵帮助' + }, + version: { + rule: /^#?喵喵版本$/, + fn: Help.version, + desc: '【#帮助】 喵喵版本介绍' + } +}) + +export default app diff --git a/Yunzai/plugins/miao-plugin/apps/help/Help.js b/Yunzai/plugins/miao-plugin/apps/help/Help.js new file mode 100644 index 0000000000000000000000000000000000000000..93e04e02a5b33cc0b397f331abf10011f6742779 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/help/Help.js @@ -0,0 +1,77 @@ +import { Cfg, Common, Data, Version } from '#miao' +import fs from 'fs' +import lodash from 'lodash' +import HelpTheme from './HelpTheme.js' + +const _path = process.cwd() +const helpPath = `${_path}/plugins/miao-plugin/resources/help` + +const Help = { + async render (e) { + if (!/喵喵/.test(e.msg) && !Cfg.get('help', false)) { + return false + } + + let custom = {} + let help = {} + if (fs.existsSync(`${helpPath}/help-cfg.js`)) { + console.log('miao-plugin: 检测到存在help-cfg.js配置\n建议将help-cfg.js移为config/help.js或重新复制config/help_default.js进行配置~') + help = await import(`file://${helpPath}/help-cfg.js?version=${new Date().getTime()}`) + } else if (fs.existsSync(`${helpPath}/help-list.js`)) { + console.log('miao-plugin: 检测到存在help-list.js配置,建议将help-list.js移为config/help.js或重新复制config/help_default.js进行配置~') + help = await import(`file://${helpPath}/help-list.js?version=${new Date().getTime()}`) + } + + let { diyCfg, sysCfg } = await Data.importCfg('help') + + // 兼容一下旧字段 + if (lodash.isArray(help.helpCfg)) { + custom = { + helpList: help.helpCfg, + helpCfg: {} + } + } else { + custom = help + } + + let helpConfig = lodash.defaults(diyCfg.helpCfg || {}, custom.helpCfg, sysCfg.helpCfg) + let helpList = diyCfg.helpList || custom.helpList || sysCfg.helpList + + let helpGroup = [] + + lodash.forEach(helpList, (group) => { + if (group.auth && group.auth === 'master' && !e.isMaster) { + return true + } + + lodash.forEach(group.list, (help) => { + let icon = help.icon * 1 + if (!icon) { + help.css = 'display:none' + } else { + let x = (icon - 1) % 10 + let y = (icon - x - 1) / 10 + help.css = `background-position:-${x * 50}px -${y * 50}px` + } + }) + + helpGroup.push(group) + }) + let themeData = await HelpTheme.getThemeData(diyCfg.helpCfg || {}, sysCfg.helpCfg || {}) + return await Common.render('help/index', { + helpCfg: helpConfig, + helpGroup, + ...themeData, + element: 'default' + }, { e, scale: 1.2 }) + }, + + async version (e) { + return await Common.render('help/version-info', { + currentVersion: Version.version, + changelogs: Version.changelogs, + elem: 'cryo' + }, { e, scale: 1.2 }) + } +} +export default Help diff --git a/Yunzai/plugins/miao-plugin/apps/help/HelpTheme.js b/Yunzai/plugins/miao-plugin/apps/help/HelpTheme.js new file mode 100644 index 0000000000000000000000000000000000000000..16043481f23aceca8a1f092c0e39e903db33b02c --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/help/HelpTheme.js @@ -0,0 +1,68 @@ +import lodash from 'lodash' +import fs from 'fs' +import { Data } from '#miao' + +let HelpTheme = { + async getThemeCfg (theme, exclude) { + let dirPath = './plugins/miao-plugin/resources/help/theme/' + let ret = [] + let names = [] + let dirs = fs.readdirSync(dirPath) + lodash.forEach(dirs, (dir) => { + if (fs.existsSync(`${dirPath}${dir}/main.png`)) { + names.push(dir) + } + }) + if (lodash.isArray(theme)) { + ret = lodash.intersection(theme, names) + } else if (theme === 'all') { + ret = names + } + if (exclude && lodash.isArray(exclude)) { + ret = lodash.difference(ret, exclude) + } + if (ret.length === 0) { + ret = ['default'] + } + let name = lodash.sample(ret) + let resPath = '{{_res_path}}/help/theme/' + return { + main: `${resPath}${name}/main.png`, + bg: fs.existsSync(`${dirPath}${name}/bg.jpg`) ? `${resPath}${name}/bg.jpg` : `${resPath}default/bg.jpg`, + style: (await Data.importModule(`resources/help/theme/${name}/config.js`, 'miao')).style || {} + } + }, + async getThemeData (diyStyle, sysStyle) { + let helpConfig = lodash.extend({}, sysStyle, diyStyle) + let colCount = Math.min(5, Math.max(parseInt(helpConfig?.colCount) || 3, 2)) + let colWidth = Math.min(500, Math.max(100, parseInt(helpConfig?.colWidth) || 265)) + let width = Math.min(2500, Math.max(800, colCount * colWidth + 30)) + let theme = await HelpTheme.getThemeCfg(diyStyle.theme || sysStyle.theme, diyStyle.themeExclude || sysStyle.themeExclude) + let themeStyle = theme.style || {} + let ret = [` + body{background-image:url(${theme.bg});width:${width}px;} + .container{background-image:url(${theme.main});width:${width}px;} + .help-table .td,.help-table .th{width:${100 / colCount}%} + `] + let css = function (sel, css, key, def, fn) { + let val = Data.def(themeStyle[key], diyStyle[key], sysStyle[key], def) + if (fn) { + val = fn(val) + } + ret.push(`${sel}{${css}:${val}}`) + } + css('.help-title,.help-group', 'color', 'fontColor', '#ceb78b') + css('.help-title,.help-group', 'text-shadow', 'fontShadow', 'none') + css('.help-desc', 'color', 'descColor', '#eee') + css('.cont-box', 'background', 'contBgColor', 'rgba(43, 52, 61, 0.8)') + css('.cont-box', 'backdrop-filter', 'contBgBlur', 3, (n) => diyStyle.bgBlur === false ? 'none' : `blur(${n}px)`) + css('.help-group', 'background', 'headerBgColor', 'rgba(34, 41, 51, .4)') + css('.help-table .tr:nth-child(odd)', 'background', 'rowBgColor1', 'rgba(34, 41, 51, .2)') + css('.help-table .tr:nth-child(even)', 'background', 'rowBgColor2', 'rgba(34, 41, 51, .4)') + return { + style: ``, + colCount + } + } +} +export default HelpTheme diff --git a/Yunzai/plugins/miao-plugin/apps/index.js b/Yunzai/plugins/miao-plugin/apps/index.js new file mode 100644 index 0000000000000000000000000000000000000000..e1022f1ed2735732482b75fc0720c8becfba69b9 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/index.js @@ -0,0 +1,16 @@ +import character from './character.js' +import profile from './profile.js' +import stat from './stat.js' +import wiki from './wiki.js' +import poke from './poke.js' +import help from './help.js' +import admin from './admin.js' +import gacha from './gacha.js' + +let apps = { character, poke, profile, stat, wiki, gacha, admin, help } +let rules = {} // v3 +for (let key in apps) { + rules[`${key}`] = apps[key].v3App() +} + +export { rules as apps } diff --git a/Yunzai/plugins/miao-plugin/apps/poke.js b/Yunzai/plugins/miao-plugin/apps/poke.js new file mode 100644 index 0000000000000000000000000000000000000000..c0ff13f490463185fd8117443958fe93efbd1828 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/poke.js @@ -0,0 +1,17 @@ +import Wife from './character/AvatarWife.js' +import { App } from '#miao' + +let app = App.init({ + id: 'poke', + name: '戳一戳', + event: 'poke' +}) + +app.reg({ + pockWife: { + fn: Wife.poke, + describe: '#老公 #老婆 查询' + } +}) + +export default app diff --git a/Yunzai/plugins/miao-plugin/apps/profile.js b/Yunzai/plugins/miao-plugin/apps/profile.js new file mode 100644 index 0000000000000000000000000000000000000000..9ebc52d06040dfc49b8c09f558bf984488d3fd2a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile.js @@ -0,0 +1,143 @@ +import { profileHelp } from './profile/ProfileCommon.js' +import { profileArtisList } from './profile/ProfileArtis.js' +import ProfileDetail from './profile/ProfileDetail.js' +import ProfileStat from './profile/ProfileStat.js' +import ProfileList from './profile/ProfileList.js' +import { uploadCharacterImg, delProfileImg, profileImgList } from './character/ImgUpload.js' +import { enemyLv } from './profile/ProfileUtils.js' +import { groupRank, resetRank, refreshRank, manageRank } from './profile/ProfileRank.js' +import { App, Cfg } from '#miao' + +let app = App.init({ + id: 'profile', + name: '角色面板' +}) + +app.reg({ + profileList: { + name: '面板角色列表', + desc: '查看当前已获取面板数据的角色列表', + fn: ProfileList.render, + rule: /^#(星铁|原神)?(面板角色|角色面板|面板)(列表)?\s*(\d{9})?$/ + }, + + profileDetail: { + name: '角色面板', + fn: ProfileDetail.detail, + rule: /^#*([^#]+)\s*(详细|详情|面板|面版|圣遗物|武器[1-7]?|伤害([1-9]+\d*)?)\s*(\d{9})*(.*[换变改].*)?$/ + }, + + profileChange: { + name: '角色面板计算', + fn: ProfileDetail.detail, + rule: /^#.+换.+$/ + }, + + groupProfile: { + name: '群内最强', + fn: groupRank, + rule: /^#(群|群内)?(排名|排行)?(最强|最高|最高分|最牛|第一|极限)+.+/ + }, + + resetRank: { + name: '重置排名', + fn: resetRank, + rule: /^#(重置|重设)(.*)(排名|排行)$/ + }, + + refreshRank: { + name: '重置排名', + fn: refreshRank, + rule: /^#(刷新|更新|重新加载)(群内|群|全部)*(排名|排行)$/ + }, + + manageRank: { + name: '打开关闭', + fn: manageRank, + rule: /^#(开启|打开|启用|关闭|禁用)(群内|群|全部)*(排名|排行)$/ + }, + + rankList: { + name: '面板排名榜', + fn: groupRank, + rule: /^#(群|群内)?.+(排名|排行)(榜)?$/ + }, + + artisList: { + name: '面板圣遗物列表', + fn: profileArtisList, + rule: /^#圣遗物列表\s*(\d{9})?$/ + }, + + profileStat: { + name: '面板练度统计', + fn: ProfileStat.stat, + rule: /^#(面板|喵喵)练度统计$/, + yzRule: /^#*(我的)*(技能|天赋|武器|角色|练度|五|四|5|4|星)+(汇总|统计|列表)(force|五|四|5|4|星)*[ |0-9]*$/, + yzCheck: () => Cfg.get('profileStat', false) + }, + + avatarList: { + name: '角色查询', + fn: ProfileStat.avatarList, + rule: /^#喵喵(角色|查询)[ |0-9]*$/, + yzRule: /^(#(角色|查询|查询角色|角色查询|人物)[ |0-9]*$)|(^(#*uid|#*UID)\+*[1|2|5-9][0-9]{8}$)|(^#[\+|+]*[1|2|5-9][0-9]{8})/, + yzCheck: () => Cfg.get('avatarList', false) + }, + + profileHelp: { + name: '角色面板帮助', + fn: profileHelp, + rule: /^#(角色|换|更换)?面[板版]帮助$/ + }, + + enemyLv: { + name: '敌人等级', + fn: enemyLv, + describe: '【#角色】 设置伤害计算中目标敌人的等级', + rule: /^#(敌人|怪物)等级\s*\d{1,3}\s*$/ + }, + + profileRefresh: { + name: '面板更新', + describe: '【#角色】 获取游戏橱窗详情数据', + fn: ProfileList.refresh, + rule: /^#(星铁|原神)?(全部面板更新|更新全部面板|获取游戏角色详情|更新面板|面板更新)\s*(\d{9})?$/ + }, + + uploadImg: { + name: '上传面板图', + describe: '【#上传刻晴面板图】 上传角色面板图', + fn: uploadCharacterImg, + rule: /^#?\s*(?:上传|添加)(.+)(?:面板图)\s*$/ + }, + + delProfile: { + name: '删除面板图', + describe: '【#删除刻晴面板图1】 删除指定角色面板图(序号)', + fn: delProfileImg, + rule: /^#?\s*(?:移除|清除|删除)(.+)(?:面板图)(\d){1,}\s*$/ + }, + + profileImgList: { + name: '面板图列表', + describe: '【#刻晴面板图列表】 删除指定角色面板图(序号)', + fn: profileImgList, + rule: /^#?\s*(.+)(?:面板图列表)\s*$/ + }, + + profileDel: { + name: '删除面板', + describe: '【#角色】 删除游戏橱窗详情数据', + fn: ProfileList.del, + rule: /^#(删除全部面板|删除面板|删除面板数据)\s*(\d{9})?$/ + }, + + profileReload:{ + name: '重新加载面板', + fn:ProfileList.reload, + rule: /^#(星铁|原神)?(加载|重新加载|重载)面板\s*(\d{9})?$/ + } +}) + +export default app diff --git a/Yunzai/plugins/miao-plugin/apps/profile/ProfileArtis.js b/Yunzai/plugins/miao-plugin/apps/profile/ProfileArtis.js new file mode 100644 index 0000000000000000000000000000000000000000..94838778a834742582045b18544b45757c5ca800 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile/ProfileArtis.js @@ -0,0 +1,96 @@ +/* +* 角色圣遗物评分详情 +* +* */ +import lodash from 'lodash' +import { Cfg, Common } from '#miao' +import { getTargetUid, profileHelp, getProfileRefresh } from './ProfileCommon.js' +import { Artifact, Character, ProfileArtis, Player } from '#miao.models' + +/* +* 角色圣遗物面板 +* */ +export async function profileArtis (e) { + let { uid, avatar } = e + let profile = e._profile || await getProfileRefresh(e, avatar) + if (!profile) { + return true + } + if (!profile.hasArtis()) { + e.reply('未能获得圣遗物详情,请重新获取面板信息后查看') + return true + } + let char = profile.char + let { game } = char + let charCfg = profile.artis.getCharCfg() + + let { attrMap } = Artifact.getMeta() + + let artisDetail = profile.getArtisMark() + let artisKeyTitle = ProfileArtis.getArtisKeyTitle() + + // 渲染图像 + return await Common.render('character/artis-mark', { + uid, + elem: char.elem, + splash: profile.costumeSplash, + data: profile, + costume: profile.costume ? '2' : '', + artisDetail, + artisKeyTitle, + attrMap, + charCfg, + game, + changeProfile: e._profileMsg + }, { e, scale: 1.3 }) +} + +/* +* 圣遗物列表 +* */ +export async function profileArtisList (e) { + let uid = await getTargetUid(e) + if (!uid) { + return true + } + + let artis = [] + let player = Player.create(uid) + player.forEachAvatar((avatar) => { + let profile = avatar.getProfile() + if (!profile) { + return true + } + let name = profile.name + let char = Character.get(name) + if (!profile.hasData || !profile.hasArtis()) { + return true + } + let profileArtis = profile.getArtisMark() + lodash.forEach(profileArtis.artis, (arti, idx) => { + arti.charWeight = profileArtis.charWeight + arti.avatar = name + arti.side = char.side + artis.push(arti) + }) + }) + + if (artis.length === 0) { + e.reply('请先获取角色面板数据后再查看圣遗物列表...') + await profileHelp(e) + return true + } + artis = lodash.sortBy(artis, '_mark') + artis = artis.reverse() + let number = Cfg.get('artisNumber', 28) + artis = artis.slice(0, `${number}`) + let artisKeyTitle = ProfileArtis.getArtisKeyTitle() + + // 渲染图像 + return await Common.render('character/artis-list', { + save_id: uid, + uid, + artis, + artisKeyTitle + }, { e, scale: 1.4 }) +} diff --git a/Yunzai/plugins/miao-plugin/apps/profile/ProfileChange.js b/Yunzai/plugins/miao-plugin/apps/profile/ProfileChange.js new file mode 100644 index 0000000000000000000000000000000000000000..c70ab077f3f86173c2cd95b0793a0e52c5f7bd17 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile/ProfileChange.js @@ -0,0 +1,299 @@ +/** + * 面板数据替换相关逻辑 + */ +import lodash from 'lodash' +import { Data } from '#miao' +import { Character, ArtifactSet, ProfileData, Weapon, Player } from '#miao.models' + +// 默认武器 +let defWeapon = { + bow: '西风猎弓', + catalyst: '西风秘典', + claymore: '西风大剑', + polearm: '西风长枪', + sword: '西风剑' +} + +const ProfileChange = { + /** + * 匹配消息 + * @param msg + * @returns {{}} + */ + matchMsg (msg) { + if (!/(变|改|换)/.test(msg)) { + return false + } + msg = msg.toLowerCase().replace(/uid ?:? ?/, '').replace('', '') + let regRet = /^#*(\d{9})?(.+?)(详细|详情|面板|面版|圣遗物|伤害[1-7]?)?\s*(\d{9})?[变换改](.+)/.exec(msg) + if (!regRet || !regRet[2]) { + return false + } + let ret = {} + let change = {} + let char = Character.get(lodash.trim(regRet[2]).replace('星铁', '')) + if (!char) { + return false + } + const game = char.game + const isGs = game === 'gs' + const keyMap = isGs ? { + artis: '圣遗物', + arti1: '花,生之花', + arti2: '毛,羽,羽毛,死之羽', + arti3: '沙,沙漏,表,时之沙', + arti4: '杯,杯子,空之杯', + arti5: '头,冠,理之冠,礼冠,帽子,帽', + weapon: '武器' + } : { + artis: '圣遗物,遗器', + arti1: '头,帽子,头部', + arti2: '手,手套,手部', + arti3: '衣,衣服,甲,躯干,', + arti4: '鞋,靴,鞋子,靴子,脚,脚部', + arti5: '球,位面球', + arti6: '绳,线,链接绳,连接绳', + weapon: '武器,光锥' + } + let keyTitleMap = {} + lodash.forEach(keyMap, (val, key) => { + lodash.forEach(val.split(','), (v) => { + keyTitleMap[v] = key + }) + }) + const keyReg = new RegExp(`^(\\d{9})?\\s*(.+?)\\s*(\\d{9})?\\s*((?:${lodash.keys(keyTitleMap).join('|')}|\\+)+)$`) + + ret.char = char.id + ret.mode = regRet[3] === '换' ? '面板' : regRet[3] + ret.uid = regRet[1] || regRet[4] || '' + ret.game = char.game + msg = regRet[5] + + // 更换匹配 + msg = msg.replace(/[变改]/g, '换') + lodash.forEach(msg.split('换'), (txt) => { + txt = lodash.trim(txt) + if (!txt) { + return true + } + // 匹配圣遗物 + let keyRet = keyReg.exec(txt) + if (keyRet && keyRet[4]) { + let char = Character.get(lodash.trim(keyRet[2])) + if (char) { + if (char.game !== game) { + return true + } + lodash.forEach(keyRet[4].split('+'), (key) => { + key = lodash.trim(key) + let type = keyTitleMap[key] + change[type] = { + char: char.id || '', + uid: keyRet[1] || keyRet[3] || '', + type + } + }) + } else if (keyRet[4].length > 2) { + return true + } + } + + // 匹配圣遗物套装 + let asMap = ArtifactSet.getAliasMap(game) + let asKey = lodash.keys(asMap).sort((a, b) => b.length - a.length).join('|') + let asReg = new RegExp(`^(${asKey})套?[2,4]?\\+?(${asKey})?套?[2,4]?\\+?(${asKey})?套?[2,4]?$`) + let asRet = asReg.exec(txt) + if (asRet && asRet[1] && asMap[asRet[1]]) { + if (game === 'gs') { + change.artisSet = [asMap[asRet[1]], asMap?.[asRet[2]] || asMap[asRet[1]]] + } else if (game === 'sr') { + for (let idx = 1; idx <= 3; idx++) { + let as = ArtifactSet.get(asMap?.[asRet[idx]]) + if (as) { // 球&绳 + change.artisSet = change.artisSet || [] + let ca = change.artisSet + ca[as.sets?.[1] ? (ca[0] ? 1 : 0) : 2] = as.name + } + } + let ca = change.artisSet + if (ca && ca[0] && !ca[1]) { + ca[1] = ca[0] + } + } + return true + } + + // 匹配武器 + let wRet = /^(?:等?级?([1-9][0-9])?级?)?\s*(?:([1-5一二三四五满])?精炼?([1-5一二三四五])?)?\s*(?:等?级?([1-9][0-9])?级?)?\s*(.*)$/.exec(txt) + if (wRet && wRet[5]) { + let weaponName = lodash.trim(wRet[5]) + let weapon = Weapon.get(weaponName, game, ret.char.game) + if (weapon || weaponName === '武器' || Weapon.isWeaponSet(weaponName)) { + let affix = wRet[2] || wRet[3] + affix = { 一: 1, 二: 2, 三: 3, 四: 4, 五: 5, 满: 5 }[affix] || affix * 1 + let tmp = { + weapon: (Weapon.isWeaponSet(weaponName) ? weaponName : weapon?.name) || '', + affix: affix || '', + level: wRet[1] * 1 || wRet[4] * 1 || '' + } + if (lodash.values(tmp).join('')) { + change.weapon = tmp + } + return true + } + } + let char = change.char || {} + // 命座匹配 + let consRet = /([0-6零一二三四五六满])(命|魂|星魂)/.exec(txt) + if (consRet && consRet[1]) { + let cons = consRet[1] + char.cons = Math.max(0, Math.min(6, lodash.isNaN(cons * 1) ? '零一二三四五六满'.split('').indexOf(cons) : cons * 1)) + txt = txt.replace(consRet[0], '') + } + + // 天赋匹配 + let talentRet = (isGs ? /(?:天赋|技能|行迹)((?:[1][0-5]|[1-9])[ ,]?)((?:[1][0-5]|[1-9])[ ,]?)([1][0-5]|[1-9])/ : + /(?:天赋|技能|行迹)((?:[1][0-5]|[1-9])[ ,]?)((?:[1][0-5]|[1-9])[ ,]?)((?:[1][0-5]|[1-9])[ ,]?)([1][0-5]|[1-9])/).exec(txt) + if (talentRet) { + char.talent = {} + lodash.forEach((isGs ? 'aeq' : 'aetq').split(''), (key, idx) => { + char.talent[key] = talentRet[idx + 1] * 1 || 1 + }) + txt = txt.replace(talentRet[0], '') + } + + let lvRet = /等级([1-9][0-9]?)|([1-9][0-9]?)级/.exec(txt) + if (lvRet && (lvRet[1] || lvRet[2])) { + char.level = (lvRet[1] || lvRet[2]) * 1 + txt = txt.replace(lvRet[0], '') + } + txt = lodash.trim(txt) + if (txt) { + let chars = Character.get(txt) + if (chars && (chars.game === game)) { + char.char = chars.id + } + } + if (!lodash.isEmpty(char)) { + change.char = char + } + }) + ret.change = lodash.isEmpty(change) ? false : change + return ret + }, + + /** + * 获取面板数据 + * @param uid + * @param charid + * @param ds + * @param game + * @returns {ProfileData|boolean} + */ + getProfile (uid, charid, ds, game = 'gs') { + if (!charid) { + return false + } + + const isGs = game === 'gs' + + let player = Player.create(uid, game) + + let source = player.getProfile(charid) + let dc = ds.char || {} + if (!source || !source.hasData) { + source = {} + } + + let char = Character.get(dc?.char || source.id || charid) + if (!char) { + return false + } + let level = dc.level || source.level || 90 + let promote = level === source.level ? source.promote : undefined + + let profiles = {} + if (source && source.id) { + profiles[`${player.uid}:${source.id}`] = source + } + // 获取source + let getSource = function (cfg) { + if (!cfg || !cfg.char) { + return source + } + let cuid = cfg.uid || uid + let id = cfg.char || source.id + let key = cuid + ':' + id + if (!profiles[key]) { + let cPlayer = Player.create(cuid, game) + profiles[key] = cPlayer.getProfile(id) || {} + } + return profiles[key]?.id ? profiles[key] : source + } + // 初始化profile + let ret = new ProfileData({ + uid, + id: char.id, + level, + cons: Data.def(dc.cons, source.cons, 0), + fetter: source.fetter || 10, + elem: char.elem, + dataSource: 'change', + _source: 'change', + promote, + trees: lodash.extend([], source.trees) + }, char.game, false) + + // 设置武器 + let wCfg = ds.weapon || {} + let wSource = getSource(wCfg).weapon || {} + let weapon = Weapon.get(wCfg?.weapon || wSource?.name || defWeapon[char.weaponType], char.game, char.weaponType) + if (char.isGs) { + if (!weapon || weapon.type !== char.weaponType) { + weapon = Weapon.get(defWeapon[char.weaponType], char.game) + } + } + + let wDs = { + name: weapon.name, + star: weapon.star, + level: Math.min(weapon.maxLv || 90, wCfg.level || wSource.level || 90) + } + if (wSource.level === wDs.level) { + wDs.promote = wSource.promote + } + wDs.affix = Math.min(weapon.maxAffix || 5, wCfg.affix || ((wDs.star === 5 && wSource.star !== 5) ? 1 : (wSource.affix || 5))) + ret.setWeapon(wDs) + + // 设置天赋 + if (ds?.char?.talent) { + ret.setTalent(ds?.char?.talent, 'level') + } else { + ret.setTalent(source?.originalTalent || (isGs ? { a: 9, e: 9, q: 9 } : { a: 6, e: 8, t: 8, q: 8 }), 'original') + } + + // 设置圣遗物 + let artis = getSource(ds.artis)?.artis?.artis || {} + for (let idx = 1; idx <= (isGs ? 5 : 6); idx++) { + if (ds['arti' + idx]) { + let source = getSource(ds['arti' + idx]) + if (source && source.artis && source.artis[idx]) { + artis[idx] = source.artis[idx] + } + } + let artisIdx = (isGs ? '00111' : '001122')[idx - 1] + if (artis[idx] && ds.artisSet && ds.artisSet[artisIdx]) { + let as = ArtifactSet.get(ds.artisSet[artisIdx], game) + if (as) { + artis[idx].id = as.getArti(idx)?.getIdByStar(artis[idx].star || 5) + artis[idx]._name = artis[idx].name = as.getArtiName(idx) + artis[idx]._set = artis[idx].set = as.name + } + } + } + ret.setArtis(artis) + ret.calcAttr() + return ret + } +} +export default ProfileChange diff --git a/Yunzai/plugins/miao-plugin/apps/profile/ProfileCommon.js b/Yunzai/plugins/miao-plugin/apps/profile/ProfileCommon.js new file mode 100644 index 0000000000000000000000000000000000000000..c08378d817d4885aefcb23e78c623f9ebe11d46d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile/ProfileCommon.js @@ -0,0 +1,77 @@ +/* +* 面板公共方法及处理 +* */ +import { Version } from '#miao' +import { Character, MysApi, Player } from '#miao.models' + +/* +* 获取面板查询的 目标uid +* */ +const _getTargetUid = async function (e) { + let uidReg = /[1-9][0-9]{8}/ + + if (e.uid && uidReg.test(e.uid)) { + return e.uid + } + + let uidRet = uidReg.exec(e.msg) + if (uidRet) { + return uidRet[0] + } + let uid = false + + try { + let user = await MysApi.initUser(e) + + if (!user || !user.uid) { + return false + } + uid = user.uid + if ((!uid || !uidReg.test(uid)) && !e._replyNeedUid) { + e.reply('请先发送【#绑定+你的UID】来绑定查询目标') + e._replyNeedUid = true + return false + } + } catch (err) { + console.log(err) + } + return uid || false +} + +export async function getTargetUid (e) { + let uid = await _getTargetUid(e) + if (uid) { + e.uid = uid + } + return uid +} + +export async function getProfileRefresh (e, avatar) { + let char = Character.get(avatar) + if (!char) { + return false + } + + let player = Player.create(e) + let profile = player.getProfile(char.id) + if (!profile || !profile.hasData) { + logger.mark(`本地无UID:${player.uid}的${char.name}面板数据,尝试自动请求...`) + await player.refresh({ profile: true }) + profile = player.getProfile(char.id) + } + if (!profile || !profile.hasData) { + if (!e._isReplyed) { + e.reply(`请确认${char.name}已展示在【游戏内】的角色展柜中,并打开了“显示角色详情”。然后请使用 #更新面板\n命令来获取${char.name}的面板详情`) + } + return false + } + return profile +} + +/* +* 面板帮助 +* */ +export async function profileHelp (e) { + e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/character/imgs/help.jpg`)) + return true +} diff --git a/Yunzai/plugins/miao-plugin/apps/profile/ProfileDetail.js b/Yunzai/plugins/miao-plugin/apps/profile/ProfileDetail.js new file mode 100644 index 0000000000000000000000000000000000000000..cfc7f29f9c68139f08c6b9815c0cea9fb3199019 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile/ProfileDetail.js @@ -0,0 +1,299 @@ +import lodash from 'lodash' +import { getTargetUid, getProfileRefresh } from './ProfileCommon.js' +import ProfileList from './ProfileList.js' +import { Cfg, Common, Data, Format } from '#miao' +import { MysApi, ProfileRank, ProfileArtis, Character, Weapon } from '#miao.models' +import ProfileChange from './ProfileChange.js' +import { profileArtis } from './ProfileArtis.js' +import { ProfileWeapon } from './ProfileWeapon.js' + +let { diyCfg } = await Data.importCfg('profile') + +// 查看当前角色 +let ProfileDetail = { + async detail (e) { + let msg = e.original_msg || e.msg + if (!msg) { + return false + } + if (!/详细|详情|面板|面版|圣遗物|伤害|武器|换/.test(msg)) { + return false + } + let mode = 'profile' + let profileChange = false + let changeMsg = msg + let pc = ProfileChange.matchMsg(msg) + + if (pc && pc.char && pc.change) { + if (!Cfg.get('profileChange')) { + e.reply('面板替换功能已禁用...') + return true + } + e.game = pc.game + e.isSr = e.game === 'sr' + e.uid = '' + e.msg = '#喵喵面板变换' + e.uid = pc.uid || await getTargetUid(e) + profileChange = ProfileChange.getProfile(e.uid, pc.char, pc.change, pc.game) + if (profileChange && profileChange.char) { + msg = `#${profileChange.char?.name}${pc.mode || '面板'}` + e._profile = profileChange + e._profileMsg = changeMsg + } + } + let uidRet = /[0-9]{9}/.exec(msg) + if (uidRet) { + e.uid = uidRet[0] + msg = msg.replace(uidRet[0], '') + } + + let name = msg.replace(/#|老婆|老公|星铁|原神/g, '').trim() + msg = msg.replace('面版', '面板') + let dmgRet = /(?:伤害|武器)(\d*)$/.exec(name) + let dmgIdx = 0, idxIsInput = false + if (/(最强|最高|最高分|最牛|第一)/.test(msg)) { + mode = /(分|圣遗物|评分|ACE)/.test(msg) ? 'rank-mark' : 'rank-dmg' + name = name.replace(/(最强|最高分|第一|最高|最牛|圣遗物|评分|群)/g, '') + } + if (/(详情|详细|面板|面版)\s*$/.test(msg) && !/更新|录入|输入/.test(msg)) { + mode = 'profile' + name = name.replace(/(详情|详细|面板)/, '').trim() + } else if (dmgRet) { + // mode = /武器/.test(msg) ? 'weapon' : 'dmg' + mode = 'dmg' + name = name.replace(/(伤害|武器)+\d*/, '').trim() + if (dmgRet[1]) { + dmgIdx = dmgRet[1] * 1 + // 标识是用户指定的序号 + idxIsInput = true + } + } else if (/(详情|详细|面板)更新$/.test(msg) || (/更新/.test(msg) && /(详情|详细|面板)$/.test(msg))) { + mode = 'refresh' + name = name.replace(/详情|详细|面板|更新/g, '').trim() + } else if (/圣遗物/.test(msg)) { + mode = 'artis' + name = name.replace('圣遗物', '').trim() + } + if (!Common.cfg('avatarProfile')) { + return false // 面板开关关闭 + } + let char = Character.get(name.trim()) + if (!char) { + return false + } + if (/星铁/.test(msg) || char.isSr) { + e.isSr = true + } + + let uid = e.uid || await getTargetUid(e) + if (!uid) { + return true + } + e.uid = uid + e.avatar = char.id + + if (char.isCustom) { + e.reply('自定义角色暂不支持此功能') + return true + } + if (!char.isRelease) { + // 预设面板支持未实装角色 + if (!profileChange && Number(e.uid) > 100000006) { + e.reply('角色尚未实装') + return true + } + // 但仅在未实装开启时展示 + if (Cfg.get('notReleasedData') === false) { + e.reply('未实装角色面板已禁用...') + return true + } + } + + if (mode === 'profile' || mode === 'dmg' || mode === 'weapon') { + return ProfileDetail.render(e, char, mode, { dmgIdx, idxIsInput }) + } else if (mode === 'refresh') { + await ProfileList.refresh(e) + return true + } else if (mode === 'artis') { + return profileArtis(e) + } + return true + }, + + async render (e, char, mode = 'profile', params = {}) { + let selfUser = await MysApi.initUser(e) + + if (!selfUser) { + e.reply('尚未绑定UID') + return true + } + + let { uid } = e + + if (char.isCustom) { + e.reply(`暂不支持自定义角色${char.name}的面板信息查看`) + return true + } + + let profile = e._profile || await getProfileRefresh(e, char.id) + if (!profile) { + return true + } + char = profile.char || char + let a = profile.attr + let base = profile.base + let attr = {} + let game = char.game + let isGs = game === 'gs' + let isSr = !isGs + + lodash.forEach((isGs ? 'hp,def,atk,mastery' : 'hp,def,atk,speed').split(','), (key) => { + let fn = (n) => Format.comma(n, key === 'hp' ? 0 : 1) + attr[key] = fn(a[key]) + attr[`${key}Base`] = fn(base[key]) + attr[`${key}Plus`] = fn(a[key] - base[key]) + }) + lodash.forEach((isGs ? 'cpct,cdmg,recharge,dmg' : 'cpct,cdmg,recharge,dmg,effPct,effDef,heal,stance').split(','), (key) => { + let fn = Format.pct + let key2 = key + if (key === 'dmg') { + if (isGs) { + if (a.phy > a.dmg) { + key2 = 'phy' + } + } + } + attr[key] = fn(a[key2]) + attr[`${key}Base`] = fn(base[key2]) + attr[`${key}Plus`] = fn(a[key2] - base[key2]) + }) + + let weapon = Weapon.get(profile?.weapon?.name, game) + let w = profile.weapon + let wCfg = {} + if (mode === 'weapon') { + wCfg = weapon.calcAttr(w.level, w.promote) + wCfg.weapons = await ProfileWeapon.calc(profile) + } + + let enemyLv = isGs ? (await selfUser.getCfg('char.enemyLv', 91)) : profile.level + let dmgCalc = await ProfileDetail.getProfileDmgCalc({ profile, enemyLv, mode, params }) + + let rank = false + if (e.group_id && !e._profile) { + rank = await ProfileRank.create({ group: e.group_id, uid, qq: e.user_id }) + await rank.getRank(profile, true) + } + + let artisDetail = profile.getArtisMark() + let artisKeyTitle = ProfileArtis.getArtisKeyTitle(game) + let data = profile.getData('name,abbr,cons,level,talent,dataSource,updateTime,imgs,costumeSplash') + if (isSr) { + let treeData = [] + let treeMap = {} + // 属性 + lodash.forEach('0113355778'.split(''), (pos, idx) => { + treeData[pos] = treeData[pos] || [] + let tmp = { type: 'tree', img: `/meta-sr/public/icons/tree-cpct.webp` } + treeData[pos].push(tmp) + treeMap[idx + 201 + ''] = tmp + }) + // 能力 + lodash.forEach([2, 4, 6], (pos, idx) => { + let tmp = { type: 'talent', img: data.imgs[`tree${idx + 1}`] } + treeData[pos] = tmp + treeMap[idx + 101 + ''] = tmp + }) + lodash.forEach(profile.trees, (id) => { + let ret = /([12][01][0-9])$/.exec(id + '') + if (ret && ret[1]) { + let treeId = ret[1] + if (treeMap?.[treeId]) { + treeMap[treeId].value = 1 + } + if (treeId[0] === '2') { + treeMap[treeId].img = `/meta-sr/public/icons/tree-${char.detail?.tree?.[id]?.key}.webp` + } + } + }) + data.treeData = treeData + } + data.weapon = profile.getWeaponDetail() + let renderData = { + save_id: uid, + uid, + game, + data, + attr, + elem: char.elem, + dmgCalc, + artisDetail, + artisKeyTitle, + bodyClass: `char-${char.name}`, + mode, + wCfg, + changeProfile: e._profileMsg + } + // 渲染图像 + let msgRes = await Common.render('character/profile-detail', renderData, { e, scale: 1.6, retMsgId: true }) + if (msgRes) { + // 如果消息发送成功,就将message_id和图片路径存起来,3小时过期 + const message_id = [e.message_id] + if (Array.isArray(msgRes.message_id)) { + message_id.push(...msgRes.message_id) + } else { + message_id.push(msgRes.message_id) + } + for (const i of message_id) { + await redis.set(`miao:original-picture:${i}`, JSON.stringify({ + type: 'profile', + img: renderData?.data?.costumeSplash + }), { EX: 3600 * 3 }) + } + } + return true + }, + + async getProfileDmgCalc ({ profile, enemyLv, mode, params }) { + let dmgMsg = [] + let dmgData = [] + let dmgCalc = await profile.calcDmg({ + enemyLv, + mode, + ...params + }) + if (dmgCalc && dmgCalc.ret) { + lodash.forEach(dmgCalc.ret, (ds) => { + if (ds.type !== 'text') { + ds.dmg = Format.comma(ds.dmg, 0) + ds.avg = Format.comma(ds.avg, 0) + } + dmgData.push(ds) + }) + lodash.forEach(dmgCalc.msg, (msg) => { + msg.replace(':', ':') + dmgMsg.push(msg.split(':')) + }) + + dmgCalc.dmgMsg = dmgMsg + dmgCalc.dmgData = dmgData + } + + if (mode === 'dmg' && dmgCalc.dmgRet) { + let basic = dmgCalc?.dmgCfg?.basicRet + lodash.forEach(dmgCalc.dmgRet, (row) => { + lodash.forEach(row, (ds) => { + ds.val = (ds.avg > basic.avg ? '+' : '') + Format.comma(ds.avg - basic.avg) + ds.dmg = Format.comma(ds.dmg, 0) + ds.avg = Format.comma(ds.avg, 0) + }) + }) + basic.dmg = Format.comma(basic.dmg) + basic.avg = Format.comma(basic.avg) + } + + return dmgCalc + } +} + +export default ProfileDetail diff --git a/Yunzai/plugins/miao-plugin/apps/profile/ProfileList.js b/Yunzai/plugins/miao-plugin/apps/profile/ProfileList.js new file mode 100644 index 0000000000000000000000000000000000000000..442d4499b72b60f9316749a7146a89da1bafec3b --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile/ProfileList.js @@ -0,0 +1,184 @@ +import lodash from 'lodash' +import { getTargetUid } from './ProfileCommon.js' +import { Common, Data } from '#miao' +import { ProfileRank, Player, Character } from '#miao.models' + +const ProfileList = { + /** + * 刷新面板 + * @param e + * @returns {Promise} + */ + async refresh (e) { + let uid = await getTargetUid(e) + if (!uid) { + e._replyNeedUid || e.reply('请先发送【#绑定+你的UID】来绑定查询目标') + return true + } + + // 数据更新 + let player = Player.create(e) + await player.refreshProfile(2) + + if (!player?._update?.length) { + e._isReplyed || e.reply('获取角色面板数据失败,请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~') + e._isReplyed = true + } else { + let ret = {} + lodash.forEach(player._update, (id) => { + let char = Character.get(id) + if (char) { + ret[char.name] = true + } + }) + if (lodash.isEmpty(ret)) { + e._isReplyed || e.reply('获取角色面板数据失败,未能请求到角色数据。请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~') + e._isReplyed = true + } else { + e.newChar = ret + return await ProfileList.render(e) + } + } + return true + }, + + /** + * 渲染面板 + * @param e + * @returns {Promise} + */ + + async render (e) { + let uid = await getTargetUid(e) + if (!uid) { + e._replyNeedUid || e.reply('请先发送【#绑定+你的UID】来绑定查询目标') + return true + } + + let isSelfUid = false + if (e.runtime) { + let uids = e.runtime?.user?.ckUids || [] + isSelfUid = uids.join(',').split(',').includes(uid + '') + } + let rank = false + + let hasNew = false + let newCount = 0 + + let chars = [] + let msg = '' + let newChar = {} + if (e.newChar) { + msg = '获取角色面板数据成功' + newChar = e.newChar + } + const cfg = await Data.importCfg('cfg') + // 获取面板数据 + let player = Player.create(e) + let servName = Player.getProfileServName(uid, player.game) + if (!player.hasProfile) { + await player.refresh({ profile: true }) + } + if (!player.hasProfile) { + e.reply(`本地暂无uid${uid}[${player.game}]的面板数据...`) + return true + } + let profiles = player.getProfiles() + + // 检测标志位 + let qq = (e.at && !e.atBot) ? e.at : e.user_id + await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: isSelfUid ? 'ck' : 'bind' }) + + let groupId = e.group_id + if (groupId) { + rank = await ProfileRank.create({ groupId, uid, qq: e.user_id }) + } + const rankCfg = await ProfileRank.getGroupCfg(groupId) + const groupRank = rank && (cfg?.diyCfg?.groupRank || false) && rankCfg.status !== 1 + for (let id in profiles) { + let profile = profiles[id] + let char = profile.char + let tmp = char.getData('id,face,name,abbr,element,star') + let imgs = char.getImgs(profile.costume) + tmp.face = imgs.qFace || imgs.face + tmp.level = profile.level || 1 + tmp.cons = profile.cons + tmp.isNew = 0 + if (newChar[char.name]) { + tmp.isNew = 1 + newCount++ + } + if (rank) { + tmp.groupRank = await rank.getRank(profile, !!tmp.isNew) + } + chars.push(tmp) + } + + if (newCount > 0) { + hasNew = newCount <= 8 + } + + chars = lodash.sortBy(chars, ['isNew', 'star', 'level', 'id']) + chars = chars.reverse() + + player.save() + // 渲染图像 + return await Common.render('character/profile-list', { + save_id: uid, + uid, + chars, + servName, + hasNew, + msg, + groupRank, + updateTime: player.getUpdateTime(), + allowRank: rank && rank.allowRank, + rankCfg + }, { e, scale: 1.6 }) + }, + /** + * 删除面板数据 + * @param e + * @returns {Promise} + */ + async del (e) { + let ret = /^#(删除全部面板|删除面板|删除面板数据)\s*(\d{9})?$/.exec(e.msg) + let uid = await getTargetUid(e) + if (!uid) { + return true + } + let targetUid = ret[2] + + let user = e?.runtime?.user || {} + if (!user.hasCk && !e.isMaster) { + e.reply('为确保数据安全,目前仅允许绑定CK用户删除自己UID的面板数据,请联系Bot主人删除...') + return true + } + + if (!targetUid) { + e.reply(`你确认要删除面板数据吗? 请回复 #删除面板${uid} 以删除面板数据`) + return true + } + + let ckUids = (user?.ckUids || []).join(',').split(',') + if (!ckUids.includes(targetUid) && !e.isMaster) { + e.reply(`仅允许删除自己的UID数据[${ckUids.join(',')}]`) + return true + } + + Player.delByUid(targetUid) + e.reply(`UID${targetUid}的本地数据已删除,排名数据已清除...`) + return true + }, + + async reload (e) { + let uid = await getTargetUid(e) + if (!uid) { + return true + } + let player = Player.create(e) + player.reload() + return ProfileList.render(e) + } +} +export default ProfileList diff --git a/Yunzai/plugins/miao-plugin/apps/profile/ProfileRank.js b/Yunzai/plugins/miao-plugin/apps/profile/ProfileRank.js new file mode 100644 index 0000000000000000000000000000000000000000..d385be4137a6f2ead3e7202b65f03fdc73015149 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile/ProfileRank.js @@ -0,0 +1,280 @@ +import ProfileDetail from './ProfileDetail.js' +import { Data, Common, Format, Cfg } from '#miao' +import { Character, ProfileRank, ProfileDmg, Player } from '#miao.models' +import lodash from 'lodash' + +export async function groupRank (e) { + const groupRank = Common.cfg('groupRank') + let msg = e.original_msg || e.msg + let type = '' + if (/(排名|排行|列表)/.test(msg)) { + type = 'list' + } else if (/(最强|最高|最多|最高分|最牛|第一)/.test(msg)) { + type = 'detail' + } else if (/极限/.test(msg)) { + type = 'super' + } + let groupId = e.group_id + if (!type || (!groupId && type !== 'super')) { + return false + } + let mode = /(分|圣遗物|评分|ACE)/.test(msg) ? 'mark' : 'dmg' + mode = /(词条)/.test(msg) ? 'valid' : mode + mode = /(双爆)/.test(msg) ? 'crit' : mode + let name = msg.replace(/(#|星铁|最强|最高分|第一|词条|双爆|极限|最高|最多|最牛|圣遗物|评分|群内|群|排名|排行|面板|面版|详情|榜)/g, '') + let char = Character.get(name) + if (!char) { + // 名字不存在或不为列表模式,则返回false + if (name || type !== 'list') { + return false + } + } + if (/星铁/.test(msg) || char.isSr) { + e.isSr = true + } + // 对鲸泽佬的极限角色文件增加支持 + if (type === 'super') { + let player = Player.create(100000000) + if (player.getProfile(char.id)) { + e.uid = 100000000 + if (Cfg.get('notReleasedData') === false) { + e.reply('未实装角色面板已禁用...') + return true + } + return await ProfileDetail.render(e, char) + } else { + return true + } + } + // 正常群排名 + let groupCfg = await ProfileRank.getGroupCfg(groupId) + if (!groupRank) { + e.reply('群面板排名功能已禁用,Bot主人可通过【#喵喵设置】启用...') + return true + } + if (groupCfg.status === 1) { + e.reply('本群已关闭群排名,群管理员或Bot主人可通过【#启用排名】启用...') + return true + } + if (type === 'detail') { + let uid = await ProfileRank.getGroupMaxUid(groupId, char.id, mode) + if (uid) { + e.uid = uid + return await ProfileDetail.render(e, char) + } else { + if (mode === 'dmg' && !ProfileDmg.dmgRulePath(char.name, char.game)) { + e.reply(`暂无排名:${char.name}暂不支持伤害计算,无法进行排名..`) + } else { + e.reply('暂无排名:请通过【#面板】查看角色面板以更新排名信息...') + } + } + } else if (type === 'list') { + if (mode === 'dmg' && char && !ProfileDmg.dmgRulePath(char.name, char.game)) { + e.reply(`暂无排名:${char.name}暂不支持伤害计算,无法进行排名..`) + } else { + let uids = [] + if (char) { + uids = await ProfileRank.getGroupUidList(groupId, char ? char.id : '', mode) + } else { + uids = await ProfileRank.getGroupMaxUidList(groupId, mode) + } + if (uids.length > 0) { + return renderCharRankList({ e, uids, char, mode, groupId }) + } else { + if (e.isSr){ + e.reply('暂无排名:请通过【*面板】查看角色面板以更新排名信息...') + } else { + e.reply('暂无排名:请通过【#面板】查看角色面板以更新排名信息...') + } + } + } + return true + } +} + +export async function resetRank (e) { + let groupId = e.group_id + if (!groupId) { + return true + } + if (!e.isMaster) { + e.reply('只有管理员可重置排名') + return true + } + let msg = e.original_msg || e.msg + let name = msg.replace(/(#|重置|重设|排名|排行|群|群内|面板|详情|面版)/g, '').trim() + let charId = '' + let charName = '全部角色' + if (name) { + let char = Character.get(name) + if (!char) { + e.reply(`重置排名失败,角色:${name}不存在`) + return true + } + charId = char.id + charName = char.name + } + await ProfileRank.resetRank(groupId, charId) + e.reply(`本群${charName}排名已重置...`) +} + +/** + * 刷新群排名信息 + * @param e + * @returns {Promise} + */ +export async function refreshRank (e) { + let groupId = e.group_id || '' + if (!groupId) { + return true + } + if (!e.isMaster && !this.e.member?.is_admin) { + e.reply('只有主人及群管理员可刷新排名...') + return true + } + e.reply('面板数据刷新中,等待时间可能较长,请耐心等待...') + let game = e.isSr ? 'sr' : 'gs' + await ProfileRank.resetRank(groupId) + let uidMap = await ProfileRank.getUserUidMap(e, game) + let count = 0 + for (let uid in uidMap) { + let { qq, type } = uidMap[uid] + let player = new Player(uid, game) + let profiles = player.getProfiles() + // 刷新rankLimit + await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: type }) + let rank = await ProfileRank.create({ groupId, uid, qq }) + for (let id in profiles) { + let profile = profiles[id] + if (!profile.hasData) { + continue + } + await rank.getRank(profile, true) + } + if (rank.allowRank) { + count++ + } + } + e.reply(`本群排名已刷新,共刷新${count}个UID数据...`) +} + +export async function manageRank (e) { + let groupId = e.group_id + if (!groupId) { + return true + } + let isClose = /(关闭|禁用)/.test(e.msg) + if (!e.isMaster && !this.e.member?.is_admin) { + e.reply(`只有主人及群管理员可${isClose ? '禁用' : '启用'}排名...`) + return true + } + await ProfileRank.setGroupStatus(groupId, isClose ? 1 : 0) + if (isClose) { + e.reply('当前群排名功能已禁用...') + } else { + e.reply('当前群排名功能已启用...\n如数据有问题可通过【#刷新排名】命令来刷新当前群内排名') + } +} + +async function renderCharRankList ({ e, uids, char, mode, groupId }) { + let list = [] + for (let ds of uids) { + let uid = ds.uid || ds.value + let player = Player.create(uid, e.isSr ? 'sr' : 'gs') + let avatar = player.getAvatar(ds.charId || char.id) + if (!avatar) { + continue + } + let profile = avatar.getProfile() + + if (profile) { + let profileRank = await ProfileRank.create({ groupId, uid }) + let data = await profileRank.getRank(profile, true) + let mark = data?.mark?.data + let tmp = { + uid, + isMax: !char, + ...avatar.getData('id,star,name,sName,level,fetter,cons,weapon,elem,talent,artisSet,imgs'), + artisMark: Data.getData(mark, 'mark,markClass,valid,crit') + } + let dmg = data?.dmg?.data + if (dmg && dmg.avg) { + let title = dmg.title + // 稍微缩短下title + if (title.length > 10) { + title = title.replace(/[ ·]*/g, '') + } + title = title.length > 10 ? title.replace(/伤害$/, '') : title + tmp.dmg = { + title: title, + avg: Format.comma(dmg.avg, 1) + } + } + if (uid) { + let userInfo = await ProfileRank.getUidInfo(uid) + try { + if (userInfo?.qq && e?.group?.pickMember) { + let member = e.group.pickMember(userInfo.qq) + if (member?.getAvatarUrl) { + let img = await member.getAvatarUrl() + if (img) { + tmp.qqFace = img + } + } + } + } catch (e) { + // console.log(e) + } + } + + if (mode === 'crit') { + tmp._mark = mark?._crit * 6.6044 || 0 + } else if (mode === 'valid') { + tmp._mark = mark?._valid || 0 + } else { + tmp._mark = mark?._mark || 0 + } + tmp._formatmark = Format.comma(tmp._mark, 1) + tmp._dmg = dmg?.avg || 0 + tmp._star = 5 - tmp.star + list.push(tmp) + } + } + let title + if (char) { + let modeTitleMap = {} + if (e.isSr) { + modeTitleMap = { + dmg: '', + mark: '遗器评分', + crit: '双爆副词条', + valid: '加权有效词条' + } + } else { + modeTitleMap = { + dmg: '', + mark: '圣遗物评分', + crit: '双爆副词条', + valid: '加权有效词条' + } + } + title = `${e.isSr ? '*' : '#'}${char.name}${modeTitleMap[mode]}排行` + list = lodash.sortBy(list, mode === 'dmg' ? '_dmg' : '_mark').reverse() + } else { + title = `${e.isSr ? '*' : '#'}${mode === 'mark' ? '最高分' : '最强'}排行` + list = lodash.sortBy(list, ['uid', '_star', 'id']) + } + + const rankCfg = await ProfileRank.getGroupCfg(groupId) + // 渲染图像 + return await Common.render('character/rank-profile-list', { + save_id: char.id, + game: e.isSr ? 'sr' : 'gs', + list, + title, + elem: char.elem, + bodyClass: `char-${char.name}`, + rankCfg, + mode + }, { e, scale: 1.4 }) +} diff --git a/Yunzai/plugins/miao-plugin/apps/profile/ProfileStat.js b/Yunzai/plugins/miao-plugin/apps/profile/ProfileStat.js new file mode 100644 index 0000000000000000000000000000000000000000..f297984bcd8f88b9eeece1ed2b0412c915557b7d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile/ProfileStat.js @@ -0,0 +1,73 @@ +import { Common } from '#miao' +import { MysApi, Player, Character } from '#miao.models' + +const ProfileStat = { + async stat (e) { + return ProfileStat.render(e, false) + }, + + async avatarList (e) { + return ProfileStat.render(e, true) + }, + async render (e, isAvatarList = false) { + // 缓存时间,单位小时 + let msg = e.msg.replace('#', '').trim() + if (msg === '角色统计' || msg === '武器统计') { + // 暂时避让一下抽卡分析的关键词 + return false + } + + let mys = await MysApi.init(e) + if (!mys || !mys.uid) return false + + const uid = mys.uid + + let player = Player.create(e) + + let avatarRet = await player.refreshAndGetAvatarData({ + index: 2, + detail: 1, + talent: isAvatarList ? 0 : 1, + rank: true, + retType: 'array', + sort: true + }) + + if (avatarRet.length === 0) { + e._isReplyed || e.reply(`查询失败,暂未获得#${uid}角色数据,请绑定CK或 #更新面板`) + return true + } + + let faceChar = Character.get(player.face || avatarRet[0]?.id) + let imgs = faceChar.imgs + let face = { + banner: imgs?.banner, + face: imgs?.face, + qFace: imgs?.qFace, + name: player.name || `#${uid}`, + sign: player.sign, + level: player.level + } + + let info = player.getInfo() + info.stats = info.stats || {} + info.statMap = { + achievement: '成就', + wayPoint: '锚点', + avatar: '角色', + avatar5: '五星角色', + goldCount: '金卡总数' + } + + return await Common.render(isAvatarList ? 'character/avatar-list' : 'character/profile-stat', { + save_id: uid, + uid, + info, + updateTime: player.getUpdateTime(), + isSelfCookie: e.isSelfCookie, + face, + avatars: avatarRet + }, { e, scale: 1.4 }) + } +} +export default ProfileStat diff --git a/Yunzai/plugins/miao-plugin/apps/profile/ProfileUtils.js b/Yunzai/plugins/miao-plugin/apps/profile/ProfileUtils.js new file mode 100644 index 0000000000000000000000000000000000000000..19128fdded9963282e1e7aed7bb348e25417f79f --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile/ProfileUtils.js @@ -0,0 +1,78 @@ +import { Cfg } from '#miao' +import { MysApi } from '#miao.models' + +/** 获取角色卡片的原图 */ +export async function getOriginalPicture (e) { + let source + if (e.reply_id) { + source = { message_id: e.reply_id } + } else { + if (!e.hasReply && !e.source) { + return false + } + // 引用的消息不是自己的消息 + if (e.source.user_id !== e.self_id) { + return false + } + // 引用的消息不是纯图片 + if (!/^\[图片]$/.test(e.source.message)) { + return false + } + // 获取原消息 + if (e.group?.getChatHistory) { + source = (await e.group.getChatHistory(e.source.seq, 1)).pop() + } else if (e.friend?.getChatHistory) { + source = (await e.friend.getChatHistory(e.source.time, 1)).pop() + } + } + let originalPic = Cfg.get('originalPic') * 1 + if (source) { + let imgPath = await redis.get(`miao:original-picture:${source.message_id}`) + if (imgPath) { + try { + if (imgPath[0] === '{') { + imgPath = JSON.parse(imgPath) + } else { + imgPath = { img: imgPath, type: '' } + } + } catch (e) { + } + if (!e.isMaster) { + if (imgPath.type === 'character' && [2, 0].includes(originalPic)) { + e.reply('已禁止获取角色原图...') + return true + } + if (imgPath.type === 'profile' && [1, 0].includes(originalPic)) { + e.reply('已禁止获取面板原图...') + return true + } + } + if (imgPath && imgPath.img) { + e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/${decodeURIComponent(imgPath.img)}`), false, { recallMsg: 30 }) + } + return true + } + // 对at错图像的增加嘲讽... + e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/common/face/what.jpg`)) + return false + } + e.reply('消息太过久远了,俺也忘了原图是啥了,下次早点来吧~') + return false +} + +/* #敌人等级 */ +export async function enemyLv (e) { + let selfUser = await MysApi.initUser(e) + if (!selfUser || !e.msg) { + return true + } + let ret = /(敌人|怪物)等级\s*(\d{1,3})\s*$/.exec(e.msg) + if (ret && ret[2]) { + let lv = ret[2] * 1 + await selfUser.setCfg('char.enemyLv', lv) + lv = await selfUser.getCfg('char.enemyLv', 91) + e.reply(`敌人等级已经设置为${lv}`) + return true + } + return true +} diff --git a/Yunzai/plugins/miao-plugin/apps/profile/ProfileWeapon.js b/Yunzai/plugins/miao-plugin/apps/profile/ProfileWeapon.js new file mode 100644 index 0000000000000000000000000000000000000000..c874fe9c2f7759f6c659fed1df8752e1ee422109 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/profile/ProfileWeapon.js @@ -0,0 +1,36 @@ +import { ProfileData, Weapon } from '#miao.models' + +export const ProfileWeapon = { + async calc (profile, game = 'gs') { + let ret = [] + await Weapon.forEach(async (w) => { + let weaponRet = w.getData('name,star,abbr,icon') + weaponRet.dmgs = [] + for (let affix of [1, 5]) { + if (affix === 5 && w.maxAffix !== 5) { + continue + } + let tempProfile = new ProfileData({ + ...profile.getData('uid,id,level,cons,fetter,elem,promote,talent,artis'), + dataSource: 'change' + }, game, false) + + tempProfile.setWeapon({ + name: w.name, + star: w.star, + level: w.maxLv, + promote: w.maxPromote, + affix + }) + tempProfile.calcAttr() + weaponRet.dmgs.push({ + affix, + ...await tempProfile.calcDmg({ mode: 'single' }) + }) + } + ret.push(weaponRet) + }, profile?.weapon?.type) + return ret + } + +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/apps/stat.js b/Yunzai/plugins/miao-plugin/apps/stat.js new file mode 100644 index 0000000000000000000000000000000000000000..7a632c7a60e905ed3742531b774fb66f12834858 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/stat.js @@ -0,0 +1,37 @@ +/* +* 胡桃数据库的统计 +* +* */ +import { ConsStat, AbyssPct } from './stat/AbyssStat.js' +import { AbyssTeam } from './stat/AbyssTeam.js' +import { AbyssSummary } from './stat/AbyssSummary.js' +import { App } from '#miao' + +let app = App.init({ + id: 'stat', + name: '深渊统计' +}) + +app.reg({ + consStat: { + rule: /^#(喵喵)?角色(持有|持有率|命座|命之座|.命)(分布|统计|持有|持有率)?$/, + fn: ConsStat, + desc: '【#统计】 #角色持有率 #角色5命统计' + }, + abyssPct: { + rule: /^#(喵喵)?深渊(第?.{1,2}层)?(角色)?(出场|使用)(率|统计)*$/, + fn: AbyssPct, + desc: '【#统计】 #深渊出场率 #深渊12层出场率' + }, + abyssTeam: { + rule: /^#深渊(组队|配队)$/, + fn: AbyssTeam, + describe: '【#角色】 #深渊组队' + }, + abyssSummary: { + rule: /^#*(喵喵|上传|本期)*(深渊|深境|深境螺旋)[ |0-9]*(数据)?$/, + fn: AbyssSummary, + desc: '上传深渊' + } +}) +export default app diff --git a/Yunzai/plugins/miao-plugin/apps/stat/AbyssStat.js b/Yunzai/plugins/miao-plugin/apps/stat/AbyssStat.js new file mode 100644 index 0000000000000000000000000000000000000000..c3222d77307abdc4c47662a094ed1ec761a895e7 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/stat/AbyssStat.js @@ -0,0 +1,164 @@ +import HutaoApi from './HutaoApi.js' +import lodash from 'lodash' +import { Common } from '#miao' +import { Character } from '#miao.models' + +export async function ConsStat (e) { + let consData = await HutaoApi.getCons() + let overview = await HutaoApi.getOverview() + + if (!consData) { + e.reply('角色持有数据获取失败,请稍后重试~') + return true + } + + let msg = e.msg + + let mode = /持有/.test(msg) ? 'char' : 'cons' + + let conNum = -1 + if (mode === 'cons') { + lodash.forEach([/0|零/, /1|一/, /2|二/, /3|三/, /4|四/, /5|五/, /6|六|满/], (reg, idx) => { + if (reg.test(msg)) { + conNum = idx + return false + } + }) + } + + if (!consData && !consData.data) { + return true + } + + let data = consData.data + + let Lumine = lodash.filter(data, (ds) => ds.avatar === 10000007)[0] || {} + let Aether = lodash.filter(data, (ds) => ds.avatar === 10000005)[0] || {} + + Lumine.holdingRate = (1 - Aether.holdingRate) || Lumine.holdingRate + + let ret = [] + + lodash.forEach(data, (ds) => { + let char = Character.get(ds.avatar) + + let data = { + name: char.name || ds.avatar, + abbr: char.abbr, + star: char.star || 3, + side: char.side, + hold: ds.holdingRate + } + + if (mode === 'char') { + data.cons = lodash.map(ds.rate, (c) => { + c.value = c.value * ds.holdingRate + return c + }) + } else { + data.cons = ds.rate + } + data.cons = lodash.sortBy(data.cons, ['id']) + + ret.push(data) + }) + + if (conNum > -1) { + ret = lodash.sortBy(ret, [`cons[${conNum}].value`]) + ret.reverse() + } else { + ret = lodash.sortBy(ret, ['hold']) + } + // 渲染图像 + return await Common.render('stat/character', { + chars: ret, + mode, + conNum, + totalCount: overview?.data?.totalPlayerCount || 0, + lastUpdate: consData.lastUpdate, + pct: function (num) { + return (num * 100).toFixed(2) + } + }, { e, scale: 1.5 }) +} + +export async function AbyssPct (e) { + let mode = /使用/.test(e.msg) ? 'use' : 'pct' + let modeName + let abyssData + let modeMulti = 1 + + if (mode === 'use') { + modeName = '使用率' + abyssData = await HutaoApi.getAbyssUse() + } else { + modeName = '出场率' + abyssData = await HutaoApi.getAbyssPct() + modeMulti = 8 + } + let overview = await HutaoApi.getOverview() + + if (!abyssData) { + e.reply(`深渊${modeName}数据获取失败,请稍后重试~`) + return true + } + + let ret = [] + let chooseFloor = -1 + let msg = e.msg + + const floorName = { + 12: '十二层', + 11: '十一层', + 10: '十层', + 9: '九层' + } + + // 匹配深渊楼层信息 + lodash.forEach(floorName, (cn, num) => { + let reg = new RegExp(`${cn}|${num}`) + if (reg.test(msg)) { + chooseFloor = num + return false + } + }) + + let data = abyssData.data + data = lodash.sortBy(data, 'floor') + data = data.reverse() + + lodash.forEach(data, (floorData) => { + let avatars = [] + lodash.forEach(floorData.avatarUsage, (ds) => { + let char = Character.get(ds.id) + if (char) { + avatars.push({ + name: char.name, + star: char.star, + value: ds.value * modeMulti, + face: char.face + }) + } + }) + avatars = lodash.sortBy(avatars, 'value', ['asc']) + avatars.reverse() + if (chooseFloor === -1) { + avatars = avatars.slice(0, 14) + } + + ret.push({ + floor: floorData.floor, + avatars + }) + }) + + return await Common.render('stat/abyss-pct', { + abyss: ret, + floorName, + chooseFloor, + mode, + modeName, + totalCount: overview?.data?.collectedPlayerCount || 0, + lastUpdate: abyssData.lastUpdate + }, { e, scale: 1.5 }) +} diff --git a/Yunzai/plugins/miao-plugin/apps/stat/AbyssSummary.js b/Yunzai/plugins/miao-plugin/apps/stat/AbyssSummary.js new file mode 100644 index 0000000000000000000000000000000000000000..91d3f113479a1eb8e046c756df42f3aafb786284 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/stat/AbyssSummary.js @@ -0,0 +1,137 @@ +import lodash from 'lodash' +import HutaoApi from './HutaoApi.js' +import { Cfg, Common, Data } from '#miao' +import { Abyss, Character, MysApi, Player } from '#miao.models' + +export async function AbyssSummary (e) { + let isMatch = /^#(喵喵|上传)深渊(数据)?$/.test(e.original_msg || e.msg || '') + if (!Cfg.get('uploadAbyssData', false) && !isMatch) { + return false + } + let mys = await MysApi.init(e, 'all') + if (!mys || !mys.uid) { + if (isMatch) { + e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`) + } + return false + } + let ret = {} + let uid = mys.uid + let player = Player.create(e) + let resDetail, resAbyss + try { + resAbyss = await mys.getSpiralAbyss(1) + let lvs = Data.getVal(resAbyss, 'floors.0.levels.0') + // 检查是否查询到了深渊信息 + if (!lvs || !lvs.battles) { + e.reply('暂未获得本期深渊挑战数据...') + return true + } else if (lvs && lvs.battles && lvs.battles.length === 0) { + if (!mys.isSelfCookie) { + if (isMatch) { + e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`) + } + return false + } + } + resDetail = await mys.getCharacter() + if (!resDetail || !resAbyss || !resDetail.avatars || resDetail.avatars.length <= 3) { + e.reply('角色信息获取失败') + return true + } + delete resDetail._res + delete resAbyss._res + ret = await HutaoApi.uploadData({ + uid, + resDetail, + resAbyss + }) + } catch (err) { + // console.log(err); + } + // 更新player信息 + player.setMysCharData(resDetail) + + if (ret && ret.retcode === 0) { + let stat = [] + if (ret.data) { + if (resAbyss.floors.length === 0) { + e.reply('暂未获得本期深渊挑战数据...') + return true + } + let abyss = new Abyss(resAbyss) + let abyssData = abyss.getData() + let avatarIds = abyss.getAvatars() + let overview = ret.info || (await HutaoApi.getOverview())?.data || {} + let addMsg = function (title, ds) { + let tmp = {} + if (!ds) { + return false + } + if (!ds.avatarId && !ds.id) { + return false + } + let char = Character.get(ds.avatarId || ds.id) + tmp.title = title + tmp.id = char.id + tmp.value = `${(ds.value / 10000).toFixed(1)} W` + let msg = [] + tmp.msg = msg + let pct = (percent, name) => { + if (percent < 0.2) { + msg.push({ + title: '少于', + value: (Math.max(0.1, 100 - percent * 100)).toFixed(1), + name: name + }) + } else { + msg.push({ + title: '超过', + value: (Math.min(99.9, percent * 100)).toFixed(1), + name: name + }) + } + } + if (ds.percent) { + pct(ds.percent, char.abbr) + pct(ds.percentTotal, '总记录') + } else { + msg.push({ + txt: '暂无统计信息' + }) + } + stat.push(tmp) + } + addMsg('最强一击', ret.data?.damage || abyssData?.stat?.dmg || {}) + addMsg('最高承伤', ret.data?.takeDamage || abyssData?.stat.takeDmg || {}) + let abyssStat = abyssData?.stat || {} + lodash.forEach({ defeat: '最多击破', e: '元素战技', q: '元素爆发' }, (title, key) => { + if (abyssStat[key]) { + stat.push({ + title, + id: abyssStat[key]?.id || 0, + value: `${abyssStat[key]?.value}次` + }) + } else { + stat.push({}) + } + }) + await player.refreshTalent(avatarIds) + let avatarData = player.getAvatarData(avatarIds) + return await Common.render('stat/abyss-summary', { + abyss: abyssData, + avatars: avatarData, + stat, + save_id: uid, + totalCount: overview?.collectedPlayerCount || 0, + uid + }, { e, scale: 1.2 }) + } else { + e.reply('暂未获得本期深渊挑战数据...') + return true + } + } else { + e.reply(`${ret.message || '上传失败'},请稍后重试...`) + } + return true +} diff --git a/Yunzai/plugins/miao-plugin/apps/stat/AbyssTeam.js b/Yunzai/plugins/miao-plugin/apps/stat/AbyssTeam.js new file mode 100644 index 0000000000000000000000000000000000000000..c6e26cc38cb0ddbc8cb323d7ccea46f32b8d8f46 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/stat/AbyssTeam.js @@ -0,0 +1,190 @@ +import lodash from 'lodash' +import HutaoApi from './HutaoApi.js' +import { Common } from '#miao' +import { Character, MysApi, Player } from '#miao.models' + +export async function AbyssTeam (e) { + let mys = await MysApi.init(e, 'all') + if (!mys || !mys.uid) { + e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`) + return false + } + let player = Player.create(e) + await player.refreshMysDetail(2) + await player.refreshTalent() + + let abyssData = await HutaoApi.getAbyssTeam() + if (!abyssData || !abyssData.data) { + e.reply('深渊组队数据获取失败,请稍后重试~') + return true + } + abyssData = abyssData.data + let avatarData = player.getAvatarData() + let avatarRet = {} + let data = {} + let noAvatar = {} + lodash.forEach(avatarData, (avatar) => { + let t = avatar.originalTalent || {} + avatarRet[avatar.id] = Math.min(avatar.level, (avatar.weapon?.level || 1)) * 100 + Math.max(t?.a || 1, t?.e || 1, t?.q || 1) * 1000 + }) + + let getTeamCfg = (str) => { + let teams = str.split(',') + teams.sort() + let teamMark = 0 + lodash.forEach(teams, (a) => { + if (!avatarRet[a]) { + teamMark = -1 + noAvatar[a] = true + } + if (teamMark !== -1) { + teamMark += avatarRet[a] * 1 + } + }) + if (teamMark === -1) { + teamMark = 1 + } + return { + key: teams.join(','), + mark: teamMark + } + } + + let hasSame = function (team1, team2) { + for (let idx = 0; idx < team1.length; idx++) { + if (team2.includes(team1[idx])) { + return true + } + } + return false + } + + lodash.forEach(abyssData, (ds) => { + let floor = ds.floor + if (!data[floor]) { + data[floor] = { + up: {}, + down: {}, + teams: [] + } + } + lodash.forEach(['up', 'down'], (halfKey) => { + lodash.forEach(ds[halfKey], (ds) => { + let teamCfg = getTeamCfg(ds.item) + if (teamCfg) { + if (!data[floor][halfKey][teamCfg.key]) { + data[floor][halfKey][teamCfg.key] = { + count: 0, + mark: 0, + hasTeam: teamCfg.mark > 1 + } + } + data[floor][halfKey][teamCfg.key].count += ds.rate + data[floor][halfKey][teamCfg.key].mark += ds.rate * teamCfg.mark + } + }) + }) + + let temp = [] + lodash.forEach(['up', 'down'], (halfKey) => { + lodash.forEach(data[floor][halfKey], (ds, team) => { + temp.push({ + team, + teamArr: team.split(','), + half: halfKey, + count: ds.count, + mark: ds.mark, + mark2: 1, + hasTeam: ds.hasTeam + }) + }) + temp = lodash.sortBy(temp, 'mark') + data[floor].teams = temp.reverse() + }) + }) + + let ret = {} + + lodash.forEach(data, (floorData, floor) => { + ret[floor] = {} + let ds = ret[floor] + lodash.forEach(floorData.teams, (t1) => { + if (t1.mark2 <= 0) { + return true + } + lodash.forEach(floorData.teams, (t2) => { + if (t1.mark2 <= 0) { + return true + } + if (t1.half === t2.half || t2.mark2 <= 0) { + return true + } + + let teamKey = t1.half === 'up' ? (t1.team + '+' + t2.team) : (t2.team + '+' + t1.team) + if (ds[teamKey]) { + return true + } + if (hasSame(t1.teamArr, t2.teamArr)) { + return true + } + + ds[teamKey] = { + up: t1.half === 'up' ? t1 : t2, + down: t1.half === 'up' ? t2 : t1, + count: Math.min(t1.count, t2.count), + mark: t1.hasTeam && t2.hasTeam ? t1.mark + t2.mark : t1.count + t2.count // 如果不存在组队则进行评分惩罚 + } + t1.mark2-- + t2.mark2-- + return false + }) + if (lodash.keys(ds).length >= 20) { + return false + } + }) + }) + + lodash.forEach(ret, (ds, floor) => { + ds = lodash.sortBy(lodash.values(ds), 'mark') + ds = ds.reverse() + ds = ds.slice(0, 4) + + lodash.forEach(ds, (team) => { + team.up.teamArr = Character.sortIds(team.up.teamArr) + team.down.teamArr = Character.sortIds(team.down.teamArr) + }) + + ret[floor] = ds + }) + + let avatarMap = {} + + lodash.forEach(avatarData, (ds) => { + let char = Character.get(ds.id) + avatarMap[ds.id] = { + id: ds.id, + name: ds.name, + star: ds.star, + level: ds.level, + cons: ds.cons, + face: char.face + } + }) + + lodash.forEach(noAvatar, (d, id) => { + let char = Character.get(id) + avatarMap[id] = { + id, + name: char.name, + face: char.face, + star: char.star, + level: 0, + cons: 0 + } + }) + + return await Common.render('stat/abyss-team', { + teams: ret, + avatars: avatarMap + }, { e, scale: 1.5 }) +} diff --git a/Yunzai/plugins/miao-plugin/apps/stat/HutaoApi.js b/Yunzai/plugins/miao-plugin/apps/stat/HutaoApi.js new file mode 100644 index 0000000000000000000000000000000000000000..3e06296adaba1b6159f94824d7e653a30e701a29 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/stat/HutaoApi.js @@ -0,0 +1,73 @@ +/* +* 胡桃API Miao-Plugin 封装 +* https://github.com/DGP-Studio/DGP.Genshin.HutaoAPI +* +* */ + +import fetch from 'node-fetch' +import { Data } from '#miao' + +const host = 'http://miao.games/api/hutao' + +function getApi (api) { + return `${host}?api=${api}` +} + +let HutaoApi = { + async req (url, param = {}, EX = 3600) { + let cacheData = await Data.getCacheJSON(`miao:hutao:${url}`) + if (cacheData && cacheData.data && param.method !== 'POST') { + return cacheData + } + let response = await fetch(getApi(`${url}`), { + ...param, + method: param.method || 'GET' + }) + let retData = await response.json() + if (retData && retData.data && param.method !== 'POST') { + let d = new Date() + retData.lastUpdate = `${d.toLocaleDateString()} ${d.toTimeString().substr(0, 5)}` + await Data.setCacheJSON(`miao:hutao:${url}`, retData, EX) + } + return retData + }, + + // 角色持有及命座分布 + async getCons () { + return await HutaoApi.req('/Statistics/Constellation') + }, + + async getAbyssPct () { + return await HutaoApi.req('/Statistics/AvatarParticipation') + }, + + async getAbyssUse () { + return await HutaoApi.req('/Statistics2/AvatarParticipation') + }, + + async getAbyssTeam () { + return await HutaoApi.req('/Statistics/Team/Combination') + }, + + async getOverview () { + return await HutaoApi.req('/Statistics/Overview') + }, + + async getUsage () { + return await HutaoApi.req('/Statistics/Avatar/AvatarCollocation') + }, + + async uploadData (data = {}) { + let body = JSON.stringify(data) + return await HutaoApi.req('/Record/UploadData', { + method: 'POST', + headers: { + 'User-Agent': 'Yunzai-Bot/Miao-Plugin', + 'Content-Type': 'text/json; charset=utf-8' + }, + body + }) + } +} + +export default HutaoApi diff --git a/Yunzai/plugins/miao-plugin/apps/wiki.js b/Yunzai/plugins/miao-plugin/apps/wiki.js new file mode 100644 index 0000000000000000000000000000000000000000..333a534694280ae5538bdf55054b43979a162b0f --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/wiki.js @@ -0,0 +1,29 @@ +import { App } from '#miao' +import Calendar from './wiki/Calendar.js' +import CharWiki from './wiki/CharWiki.js' +import CalendarSr from './wiki/CalendarSr.js' + +let app = App.init({ + id: 'wiki', + name: '角色资料' +}) +app.reg({ + wiki: { + rule: '^#喵喵WIKI$', + check: CharWiki.check, + fn: CharWiki.wiki, + desc: '【#资料】 #神里天赋 #夜兰命座' + }, + calendar: { + rule: /^(#|喵喵)+(日历|日历列表)$/, + fn: Calendar.render, + desc: '【#日历】 原神活动日历' + }, + calendarSr: { + rule: /^#(星铁)+(日历|日历列表)$/, + fn: CalendarSr.render, + desc: '【#星铁日历】 星铁活动日历' + } +}) + +export default app diff --git a/Yunzai/plugins/miao-plugin/apps/wiki/Calendar.js b/Yunzai/plugins/miao-plugin/apps/wiki/Calendar.js new file mode 100644 index 0000000000000000000000000000000000000000..c9b84cb33e48eebbf73c8eb49ef5b1f0af8fb833 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/wiki/Calendar.js @@ -0,0 +1,414 @@ +import lodash from 'lodash' +import fetch from 'node-fetch' +import moment from 'moment' +import { Common, Data, Cfg } from '#miao' +import { Character, Material } from '#miao.models' + +const ignoreIds = [495, // 有奖问卷调查开启! + 1263, // 米游社《原神》专属工具一览 + 423, // 《原神》玩家社区一览 + 422, // 《原神》防沉迷系统说明 + 762 // 《原神》公平运营声明 +] + +const ignoreReg = /(内容专题页|版本更新说明|调研|防沉迷|米游社|专项意见|更新修复与优化|问卷调查|版本更新通知|更新时间说明|预下载功能|周边限时|周边上新|角色演示)/ +const fulltimeReg = /(魔神任务)/ + +let Cal = { + async reqCalData () { + let listApi = 'https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api/getAnnList?game=hk4e&game_biz=hk4e_cn&lang=zh-cn&bundle_id=hk4e_cn&platform=pc®ion=cn_gf01&level=55&uid=100000000' + + let request = await fetch(listApi) + let listData = await request.json() + + let timeMap + let timeMapCache = await redis.get('miao:calendar:detail') + if (timeMapCache) { + timeMap = JSON.parse(timeMapCache) || {} + } else { + let detailApi = 'https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api/getAnnContent?game=hk4e&game_biz=hk4e_cn&lang=zh-cn&bundle_id=hk4e_cn&platform=pc®ion=cn_gf01&level=55&uid=100000000' + let request2 = await fetch(detailApi) + let detailData = await request2.json() + timeMap = {} + if (detailData && detailData.data && detailData.data.list) { + let versionTime = { + 2.7: '2022-05-31 11:00:00', + 2.8: '2022-07-13 11:00:00', + 3.0: '2022-08-24 11:00:00', + 3.1: '2022-09-28 11:00:00', + 3.2: '2022-11-02 11:00:00', + 3.3: '2022-12-07 11:00:00' + } + lodash.forEach(detailData.data.list, (ds) => { + let vRet = /(\d\.\d)版本更新通知/.exec(ds.title) + if (vRet && vRet[1]) { + let content = /(?:更新时间)\s*〓([^〓]+)(?:〓|$)/.exec(ds.content) + if (content && content[1]) { + let tRet = /([0-9\\/\\: ]){9,}/.exec(content[1]) + if (tRet && tRet[0]) { + versionTime[vRet[1]] = versionTime[vRet[1]] || tRet[0].replace('06:00', '11:00') + } + } + } + }) + lodash.forEach(detailData.data.list, (ds) => { + let { ann_id: annId, content, title } = ds + if (ignoreReg.test(title)) { + return true + } + content = content.replace(/(<|<)[\w "%:;=\-\\/\\(\\),\\.]+(>|>)/g, '') + content = /(?:活动时间|祈愿介绍|任务开放时间|冒险....包|折扣时间)\s*〓([^〓]+)(〓|$)/.exec(content) + if (!content || !content[1]) { + return true + } + content = content[1] + let annTime = [] + + // 第一种简单格式 + let timeRet = /(?:活动时间)?(?:〓|\s)*([0-9\\/\\: ~]{6,})/.exec(content) + if (timeRet && timeRet[1]) { + annTime = timeRet[1].split('~') + } else if (/\d\.\d版本更新后/.test(content)) { + let vRet = /(\d\.\d)版本更新后/.exec(content) + let vTime = '' + if (vRet && vRet[1] && versionTime[vRet[1]]) { + vTime = versionTime[vRet[1]] + } + if (!vTime) { + return true + } + if (/永久开放/.test(content)) { + annTime = [vTime, '2099/01/01 00:00:00'] + } else { + timeRet = /([0-9\\/\\: ]){9,}/.exec(content) + if (timeRet && timeRet[0]) { + annTime = [vTime, timeRet[0]] + } + } + } + if (annTime.length === 2) { + timeMap[annId] = { + start: annTime[0].trim().replace(/\//g, '-'), + end: annTime[1].trim().replace(/\//g, '-') + } + } + }) + } + let miaoApi = 'http://miao.games/api/calendar' + try { + request2 = await fetch(miaoApi) + let data = await request2.json() + if (data && data.status === 0 && data.data) { + lodash.forEach(data.data, (ds, id) => { + timeMap[id] = ds + }) + } + } catch (e) { + } + await Data.setCacheJSON('miao:calendar:detail', timeMap, 60 * 10) + } + return { listData, timeMap } + }, + + getDateList () { + let today = moment() + let temp = today.add(-7, 'days') + let dateList = [] + let month = 0 + let date = [] + let week = [] + + let startDate, endDate + + for (let idx = 0; idx < 13; idx++) { + temp = today.add(1, 'days') + let m = temp.month() + 1 + let d = temp.date() + if (month === 0) { + startDate = temp.format('YYYY-MM-DD') + month = m + } + if (month !== m && date.length > 0) { + dateList.push({ + month, + date, + week + }) + date = [] + week = [] + month = m + } + date.push(d) + week.push(temp.weekday()) + if (idx === 12) { + dateList.push({ + month, + date, + week + }) + endDate = temp.format('YYYY-MM-DD') + } + } + + let startTime = moment(startDate + ' 00:00:00') + let endTime = moment(endDate + ' 23:59:59') + + let totalRange = endTime - startTime + return { + dateList, + startTime, + endTime, + totalRange, + nowLeft: (moment() - startTime) / totalRange * 100 + } + }, + + // 深渊日历信息 + getAbyssCal (s1, e1) { + let now = moment() + let check = [] + let f = 'YYYY-MM' + let last = now.add(-1, 'M').format(f) + let lastM = now.format('MMMM') + let curr = now.add(1, 'M').format(f) + let currM = now.format('MMMM') + let next = now.add(1, 'M').format(f) + let nextM = now.format('MMMM') + + check.push([moment(`${last}-16 04:00:00`), moment(`${curr}-01 03:59:59`), lastM + '下半']) + check.push([moment(`${curr}-01 04:00:00`), moment(`${curr}-16 03:59:59`), currM + '上半']) + check.push([moment(`${curr}-16 04:00:00`), moment(`${next}-01 03:59:59`), currM + '下半']) + check.push([moment(`${next}-01 04:00:00`), moment(`${next}-16 03:59:59`), nextM + '上半']) + + let ret = [] + lodash.forEach(check, (ds) => { + let [s2, e2] = ds + if ((s2 <= s1 && s1 <= e2) || (s2 <= e1 && e1 <= e2)) { + ret.push(ds) + } + }) + return ret + }, + + /** + * 获取角色数据 + * @param dateList + * @returns {{charBirth: {}, charNum: number, charTalent: (*|{})}} + */ + getCharData (dateList) { + let charBirth = {} + let charTalent = {} + // 初始化生日数据 + lodash.forEach(dateList, (m) => { + lodash.forEach(m.date, (d) => { + charBirth[`${m.month}-${d}`] = [] + }) + }) + // 初始化天赋数据 + let now = moment(new Date()) + if (now.hour() < 4) { + now = now.add(-1, 'days') + } + let week = now.weekday() + Material.forEach('talent', (material) => { + let data = material.getData('name,abbr,city,icon,week,cid') + data.chars = [] + charTalent[material.name] = data + }, (ds) => ds.star === 4 && (week === 6 || ds.week === week % 3 + 1)) + // 遍历角色数据 + Character.forEach((char) => { + if (charBirth[char.birth] && (char.isRelease || char.birth !== '1-1')) { + charBirth[char.birth].push(char.getData('id,name:sName,star,face')) + } + let t = char.materials?.talent + if (t && charTalent[t] && !char.isTraveler) { + let data = char.getData('id,name:sName,star,face') + data.weekly = char.getMaterials('weekly')?.icon + charTalent[t].chars.push(data) + } + }, Cfg.get('notReleasedData') ? 'official' : 'release') + let charNum = 0 + lodash.forEach(charBirth, (charList) => { + charNum = Math.max(charNum, charList.length) + }) + charTalent = lodash.values(charTalent) + charTalent = lodash.sortBy(charTalent, 'cid') + lodash.forEach(charTalent, (ds) => { + ds.chars = lodash.sortBy(ds.chars, ['star', 'id']).reverse() + }) + return { charBirth, charNum, charTalent } + }, + + /** + * 获取日历列表 + * @param ds + * @param target + * @param startTime + * @param endTime + * @param totalRange + * @param now + * @param timeMap + * @param isAct + * @returns {boolean} + */ + getList (ds, target, { startTime, endTime, totalRange, now, timeMap = {} }, isAct = false) { + let type = isAct ? 'activity' : 'normal' + let id = ds.ann_id + let title = ds.title + let banner = isAct ? ds.banner : '' + let extra = { sort: isAct ? 5 : 10 } + let detail = timeMap[id] || {} + + if (ignoreIds.includes(id) || ignoreReg.test(title) || detail.display === false) { + return false + } + + if (/神铸赋形/.test(title)) { + type = 'weapon' + title = title.replace(/(单手剑|双手剑|长柄武器|弓|法器|·)/g, '') + extra.sort = 2 + } else if (/祈愿/.test(title)) { + type = 'character' + let regRet = /·(.*)\(/.exec(title) + if (regRet[1]) { + let char = Character.get(regRet[1]) + extra.banner2 = char.getImgs()?.card + extra.face = char.face + extra.character = regRet[1] + extra.elem = char.elem + extra.sort = 1 + } + } else if (/纪行/.test(title)) { + type = 'pass' + } + + let getDate = (d1, d2) => moment(d1 && d1.length > 6 ? d1 : d2) + let sDate = getDate(detail.start, ds.start_time) + let eDate = getDate(detail.end, ds.end_time) + let sTime = moment.max(sDate, startTime) + let eTime = moment.min(eDate, endTime) + + let sRange = sTime - startTime + let eRange = eTime - startTime + + let left = sRange / totalRange * 100 + let width = eRange / totalRange * 100 - left + + let label = '' + if (fulltimeReg.test(title) || eDate - sDate > 365 * 24 * 3600 * 1000) { + if (sDate < now) { + label = sDate.format('MM-DD HH:mm') + ' 后永久有效' + } else { + label = '永久有效' + } + } else if (now > sDate && eDate > now) { + label = eDate.format('MM-DD HH:mm') + ' (' + moment.duration(eDate - now).humanize() + '后结束)' + if (width > (isAct ? 38 : 55)) { + label = sDate.format('MM-DD HH:mm') + ' ~ ' + label + } + } else if (sDate > now) { + label = sDate.format('MM-DD HH:mm') + ' (' + moment.duration(sDate - now).humanize() + '后开始)' + } else if (isAct) { + label = sDate.format('MM-DD HH:mm') + ' ~ ' + eDate.format('MM-DD HH:mm') + } + if (sDate <= endTime && eDate >= startTime) { + target.push({ + ...extra, + id, + title, + type, + mergeStatus: ['activity', 'normal'].includes(type) ? 1 : 0, + banner, + icon: ds.tag_icon, + left, + width, + label, + duration: eTime - sTime, + start: sDate.format('MM-DD HH:mm'), + end: eDate.format('MM-DD HH:mm') + }) + } + }, + + async get () { + moment.locale('zh-cn') + let now = moment() + + let { listData, timeMap } = await Cal.reqCalData() + + let dl = Cal.getDateList() + + let list = [] + let abyss = [] + + lodash.forEach(listData.data.list[1].list, (ds) => Cal.getList(ds, list, { ...dl, now, timeMap }, true)) + lodash.forEach(listData.data.list[0].list, (ds) => Cal.getList(ds, list, { ...dl, now, timeMap }, false)) + + let abyssCal = Cal.getAbyssCal(dl.startTime, dl.endTime) + lodash.forEach(abyssCal, (t) => { + Cal.getList({ + title: `「深境螺旋」· ${t[2]}`, + start_time: t[0].format('YYYY-MM-DD HH:mm'), + end_time: t[1].format('YYYY-MM-DD HH:mm') + }, abyss, { ...dl, now }, true) + }) + + list = lodash.sortBy(list, ['sort', 'start', 'duration']) + + let charCount = 0 + let charOld = 0 + let weaponCount = 0 + let ret = [] + lodash.forEach(list, (li) => { + if (li.type === 'character') { + charCount++ + li.left === 0 && charOld++ + li.idx = charCount + } + if (li.type === 'weapon') { + weaponCount++ + li.idx = weaponCount + } + if (li.mergeStatus === 1) { + lodash.forEach(list, (li2) => { + if (li2.mergeStatus === 1 && li.left + li.width <= li2.left) { + li.mergeStatus = 2 + li2.mergeStatus = 2 + ret.push([li, li2]) + return false + } + }) + } + if (li.mergeStatus !== 2) { + li.mergeStatus = 2 + ret.push([li]) + } + }) + + return { + game: 'gs', + ...dl, + ...Cal.getCharData(dl.dateList), + list: ret, + abyss, + charMode: `char-${charCount}-${charOld}`, + nowTime: now.format('YYYY-MM-DD HH:mm'), + nowDate: now.date() + } + }, + + async render (e) { + let calData = await Cal.get() + let mode = 'calendar' + if (/(日历列表|活动)$/.test(e.msg)) { + mode = 'list' + } + + return await Common.render('wiki/calendar', { + ...calData, + displayMode: mode + }, { e, scale: 1.1 }) + } +} + +export default Cal diff --git a/Yunzai/plugins/miao-plugin/apps/wiki/CalendarSr.js b/Yunzai/plugins/miao-plugin/apps/wiki/CalendarSr.js new file mode 100644 index 0000000000000000000000000000000000000000..f90a320b3b19ad69e291a3b0901b1e7fb665c3e1 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/wiki/CalendarSr.js @@ -0,0 +1,303 @@ +import lodash from 'lodash' +import fetch from 'node-fetch' +import moment from 'moment' +import Calendar from './Calendar.js' +import { Common, Data } from '#miao' +import { Character } from '#miao.models' + +const ignoreIds = [ + 257, // 保密测试参与意愿调研 + 194, // 有奖问卷 + 203, // 《崩坏:星穹铁道》社媒聚合页上线 + 183, // 官方社群一览 + 187, // 《崩坏:星穹铁道》防沉迷系统公告 + 185, // 《崩坏:星穹铁道》公平运营声明 + 171 // 《崩坏:星穹铁道》社区专属工具一览 +] + +const ignoreReg = /(更新概览|游戏优化|优化说明|内容专题页|版本更新说明|循星归程|调研|防沉迷|米游社|专项意见|更新修复与优化|问卷调查|版本更新通知|更新时间说明|预下载功能|周边限时|周边上新|角色演示|角色PV|版本PV|动画短片|bilibili|激励计划|调整说明|攻略征集)/ + +let CalSr = { + async reqCalData () { + let listApi = 'https://hkrpg-api.mihoyo.com/common/hkrpg_cn/announcement/api/getAnnList?game=hkrpg&game_biz=hkrpg_cn&lang=zh-cn&auth_appid=announcement&authkey_ver=1&bundle_id=hkrpg_cn&channel_id=1&level=65&platform=pc®ion=prod_gf_cn&sdk_presentation_style=fullscreen&sdk_screen_transparent=true&sign_type=2&uid=100000000' + + let request = await fetch(listApi) + let listData = await request.json() + + let timeMap + let timeMapCache = await redis.get('miao:calendarSr:detail') + if (timeMapCache) { + timeMap = JSON.parse(timeMapCache) || {} + } else { + let detailApi = 'https://hkrpg-api-static.mihoyo.com/common/hkrpg_cn/announcement/api/getAnnContent?game=hkrpg&game_biz=hkrpg_cn&lang=zh-cn&bundle_id=hkrpg_cn&platform=pc®ion=prod_gf_cn&level=65&channel_id=1' + let request2 = await fetch(detailApi) + let detailData = await request2.json() + timeMap = {} + if (detailData && detailData.data && detailData.data.list) { + let versionTime = { + 1.1: '2022-06-07 11:00:00' + } + lodash.forEach(detailData.data.list, (ds) => { + let vRet = /(\d\.\d)版本\S*更新(概览|说明)/.exec(ds.title) + if (vRet && vRet[1]) { + let content = /■(?:更新时间)\s*([^■]+)(?:■|$)/.exec(ds.content) + if (content && content[1]) { + let tRet = /([0-9\\/\\: ]){9,}/.exec(content[1]) + if (tRet && tRet[0]) { + versionTime[vRet[1]] = versionTime[vRet[1]] || tRet[0].replace('06:00', '11:00') + } + } + } + }) + let ret = function (ds) { + let { ann_id: annId, content, title } = ds + if (ignoreReg.test(title)) { + return true + } + content = content.replaceAll('\u003ch1 style=\"\"\u003e', '※') + content = content.replaceAll('\u003c/h1\u003e', '※') + content = content.replace(/(<|<)[\w "%:;=\-\\/\\(\\),\\.]+(>|>)/g, '') + content = /(?:活动时间|活动跃迁|开放时间|开启时间|折扣时间|上架时间)\s*※([^※]+)(※|$)/.exec(content) + if (!content || !content[1]) { + return true + } + content = content[1] + let annTime = [] + + // 第一种简单格式 + let timeRet = /(?:活动时间)?(?:※|\s)*([0-9\\/\\: -]{6,})/.exec(content) + if (/\d\.\d版本更新后/.test(content)) { + let vRet = /(\d\.\d)版本更新后/.exec(content) + let vTime = '' + if (vRet && vRet[1] && versionTime[vRet[1]]) { + vTime = versionTime[vRet[1]] + } + if (!vTime) { + return true + } + if (/永久开放/.test(content)) { + annTime = [vTime, '2099/01/01 00:00:00'] + } else { + timeRet = /([0-9\\/\\: ]){9,}/.exec(content) + if (timeRet && timeRet[0]) { + annTime = [vTime, timeRet[0]] + } + } + } else if (timeRet && timeRet[1]) { + annTime = timeRet[1].split('-') + } + + if (annTime.length === 2) { + timeMap[annId] = { + start: annTime[0].trim().replace(/\//g, '-'), + end: annTime[1].trim().replace(/\//g, '-') + } + } + } + lodash.forEach(detailData.data.list, (ds) => ret(ds)) + lodash.forEach(detailData.data.pic_list, (ds) => ret(ds)) + } + await Data.setCacheJSON('miao:calendarSr:detail', timeMap, 60 * 10) + } + return { listData, timeMap } + }, + + // 深渊日历信息 + getAbyssCal (s1, e1, versionStartTime) { + let check = [] + let f = 'YYYY-MM-DD HH:mm:ss' + + let abyss1Start = moment(versionStartTime, 'YYYY-MM-DD HH:mm:ss').add(5, 'days').subtract(3, 'hours').format(f) + let abyss1End = moment(abyss1Start).add(14, 'days').format(f) + let abyss2Start = abyss1End + let abyss2End = moment(abyss2Start).add(14, 'days').format(f) + let abyss3Start = abyss2End + let abyss3End = moment(abyss3Start).add(14, 'days').format(f) + let abyss4Start = abyss3End + let abyss4End = moment(abyss4Start).add(14, 'days').format(f) + let abyss0End = abyss1Start + let abyss0Start = moment(abyss0End).subtract(14, 'days').format(f) + + check.push([moment(abyss0Start), moment(abyss0End)]) + check.push([moment(abyss1Start), moment(abyss1End)]) + check.push([moment(abyss2Start), moment(abyss2End)]) + check.push([moment(abyss3Start), moment(abyss3End)]) + check.push([moment(abyss4Start), moment(abyss4End)]) + + let ret = [] + lodash.forEach(check, (ds) => { + let [s2, e2] = ds + if ((s2 <= s1 && s1 <= e2) || (s2 <= e1 && e1 <= e2)) { + ret.push(ds) + } + }) + return ret + }, + + getList (ds, target, { startTime, endTime, totalRange, now, timeMap = {} }) { + let type = 'activity' + let id = ds.ann_id + let title = ds.title + let subTitle = ds.subtitle + let banner = ds.banner + let extra = { sort: 5 } + let detail = timeMap[id] || {} + + if (ignoreIds.includes(id) || ignoreReg.test(title)) { + return true + } + + if (/流光定影/.test(title)) { + type = 'weapon' + title = title.replace(/(限定5星光锥)/g, '') + extra.sort = 2 + } else if (/跃迁/.test(subTitle)) { + type = 'character' + let regRet = /角色「(.*)((|\()/.exec(title) + if (regRet[1]) { + let char = Character.get(regRet[1]) + extra.banner2 = char.getImgs()?.card + extra.face = char.face + extra.character = regRet[1] + extra.elem = char.elem + extra.sort = 1 + } + } else if (/无名勋礼/.test(title)) { + type = 'pass' + } + + let getDate = (d1, d2) => moment(d1 && d1.length > 6 ? d1 : d2) + let sDate = getDate(detail.start, ds.start_time) + let eDate = getDate(detail.end, ds.end_time) + let sTime = moment.max(sDate, startTime) + let eTime = moment.min(eDate, endTime) + + let sRange = sTime - startTime + let eRange = eTime - startTime + + let left = sRange / totalRange * 100 + let width = eRange / totalRange * 100 - left + + let label = '' + if (eDate - sDate > 365 * 24 * 3600 * 1000) { + if (sDate < now) { + label = sDate.format('MM-DD HH:mm') + ' 后永久有效' + } else { + label = '永久有效' + } + } else if (now > sDate && eDate > now) { + label = eDate.format('MM-DD HH:mm') + ' (' + moment.duration(eDate - now).humanize() + '后结束)' + if (width > 38) { + label = sDate.format('MM-DD HH:mm') + ' ~ ' + label + } + } else if (sDate > now) { + label = sDate.format('MM-DD HH:mm') + ' (' + moment.duration(sDate - now).humanize() + '后开始)' + } else { + label = sDate.format('MM-DD HH:mm') + ' ~ ' + eDate.format('MM-DD HH:mm') + } + if (sDate <= endTime && eDate >= startTime) { + target.push({ + ...extra, + id, + title, + type, + mergeStatus: ['activity'].includes(type) ? 1 : 0, + banner, + icon: ds.tag_icon, + left, + width, + label, + duration: eTime - sTime, + start: sDate.format('MM-DD HH:mm'), + end: eDate.format('MM-DD HH:mm') + }) + } + }, + + async get () { + moment.locale('zh-cn') + let now = moment() + + let { listData, timeMap } = await CalSr.reqCalData() + let dateList = Calendar.getDateList() + + let resultList = [] + let abyss = [] + + lodash.forEach(listData.data.list[0].list, (ds) => CalSr.getList(ds, resultList, { ...dateList, now, timeMap })) + lodash.forEach(listData.data.pic_list[0].type_list[0].list, (ds) => CalSr.getList(ds, resultList, { ...dateList, now, timeMap })) + + let versionStartTime + lodash.forEach(listData.data.list[0].list, (ds) => { + if (/版本更新(概览|说明)/.test(ds.title)) { + versionStartTime = ds.start_time + } + }) + + let abyssCal = CalSr.getAbyssCal(dateList.startTime, dateList.endTime, versionStartTime) + lodash.forEach(abyssCal, (t) => { + CalSr.getList({ + title: '「混沌回忆」', + start_time: t[0].format('YYYY-MM-DD HH:mm'), + end_time: t[1].format('YYYY-MM-DD HH:mm') + }, abyss, { ...dateList, now }) + }) + + resultList = lodash.sortBy(resultList, ['sort', 'start', 'duration']) + + let charCount = 0 + let charOld = 0 + let weaponCount = 0 + let ret = [] + lodash.forEach(resultList, (li) => { + if (li.type === 'character') { + charCount++ + li.left === 0 && charOld++ + li.idx = charCount + } + if (li.type === 'weapon') { + weaponCount++ + li.idx = weaponCount + } + if (li.mergeStatus === 1) { + lodash.forEach(resultList, (li2) => { + if (li2.mergeStatus === 1 && li.left + li.width <= li2.left) { + li.mergeStatus = 2 + li2.mergeStatus = 2 + ret.push([li, li2]) + return false + } + }) + } + if (li.mergeStatus !== 2) { + li.mergeStatus = 2 + ret.push([li]) + } + }) + + return { + game: 'sr', + ...dateList, + list: ret, + abyss, + charMode: `char-${charCount}-${charOld}`, + nowTime: now.format('YYYY-MM-DD HH:mm'), + nowDate: now.date() + } + }, + + async render (e) { + let calData = await CalSr.get() + let mode = 'calendar' + if (/(日历列表|活动)$/.test(e.msg)) { + mode = 'list' + } + + return await Common.render('wiki/calendar', { + ...calData, + displayMode: mode + }, { e, scale: 1.1 }) + } +} + +export default CalSr diff --git a/Yunzai/plugins/miao-plugin/apps/wiki/CharMaterial.js b/Yunzai/plugins/miao-plugin/apps/wiki/CharMaterial.js new file mode 100644 index 0000000000000000000000000000000000000000..26cccb5883cc4f26e65670f938d92426645308e6 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/wiki/CharMaterial.js @@ -0,0 +1,18 @@ +import { Common } from '#miao' + +const CharMaterial = { + async render ({ e, char }) { + let data = char.getData() + return await Common.render('wiki/character-material', { + // saveId: `info-${char.id}`, + data, + attr: char.getAttrList(), + detail: char.getDetail(), + imgs: char.getImgs(), + materials: char.getMaterials(), + elem: char.elem + }, { e, scale: 1.4 }) + } +} + +export default CharMaterial diff --git a/Yunzai/plugins/miao-plugin/apps/wiki/CharTalent.js b/Yunzai/plugins/miao-plugin/apps/wiki/CharTalent.js new file mode 100644 index 0000000000000000000000000000000000000000..c093ef38fb48de82b08544a5de24b427bba3993a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/wiki/CharTalent.js @@ -0,0 +1,114 @@ +import lodash from 'lodash' +import { Common, Format } from '#miao' + +const CharTalent = { + async render (e, mode, char) { + let lvs = [] + for (let i = 1; i <= 15; i++) { + lvs.push('Lv' + i) + } + let detail = lodash.extend({}, char.getDetail()) + if (char.game === 'sr') { + lodash.forEach(['cons', 'talent', 'treeData'], (key) => { + lodash.forEach(detail[key], (ds, idx) => { + if (ds.desc) { + if (key === 'talent' && ds.desc.split) { + let desc = CharTalent.getDesc(ds.desc, ds.tables, idx === 'a' || idx === 'a2' ? 5 : 8) + ds.desc = desc.desc + ds.tables = desc.tables + } else if (ds.desc.split) { + ds.desc = ds.desc.split('
') + } + } + }) + }) + } + return await Common.render('wiki/character-talent', { + saveId: `${mode}-${char.id}`, + ...char.getData(), + game: char.game, + detail: char.getDetail(), + imgs: char.getImgs(), + mode, + lvs, + line: CharTalent.getLineData(char) + }, { e, scale: 1.1 }) + }, + getLineData (char) { + let ret = [] + if (char.isSr) { + lodash.forEach({ hp: '基础生命', atk: '基础攻击', def: '基础防御', speed: '速度' }, (label, key) => { + ret.push({ + num: Format.comma(char.getDetail().baseAttr[key], 1), + label + }) + }) + return ret + } + const attrMap = { + atkPct: '大攻击', + hpPct: '大生命', + defPct: '大防御', + cpct: '暴击', + cdmg: '爆伤', + recharge: '充能', + mastery: '精通', + heal: '治疗', + dmg: char.elemName + '伤', + phy: '物伤' + } + lodash.forEach({ hp: '基础生命', atk: '基础攻击', def: '基础防御' }, (label, key) => { + ret.push({ + num: Format.comma(char.baseAttr[key], 1), + label + }) + }) + let ga = char.growAttr + ret.push({ + num: ga.key === 'mastery' ? Format.comma(ga.value, 1) : ga.value, + label: `成长·${attrMap[ga.key]}` + }) + return ret + }, + // 获取精炼描述 + getDesc (desc, tables, lv = 5) { + let reg = /\$(\d)\[[i|f1]\](\%?)/g + let ret + + let idxFormat = {} + while ((ret = reg.exec(desc)) !== null) { + let idx = ret[1] + let pct = ret[2] + let value = tables?.[idx]?.values[lv - 1] + if (value) { + if (pct === '%') { + idxFormat[idx] = 'percent' + value = Format.percent(value) + } else { + idxFormat[idx] = 'comma' + value = Format.comma(value) + } + value = value + ` (lv${lv})` + desc = desc.replaceAll(ret[0], value) + } + } + let tableRet = [] + lodash.forEach(tables, (ds, idx) => { + let values = [] + lodash.forEach(ds.values, (v) => { + values.push(Format[idxFormat[idx] || 'comma'](v)) + }) + tableRet.push({ + name: ds.name, + isSame: ds.isSame, + values + }) + }) + return { + desc: desc.split('
'), + tables: tableRet + } + } +} + +export default CharTalent diff --git a/Yunzai/plugins/miao-plugin/apps/wiki/CharWiki.js b/Yunzai/plugins/miao-plugin/apps/wiki/CharWiki.js new file mode 100644 index 0000000000000000000000000000000000000000..c17fb2f16ab54a5c72efd951ddaaf640d5e14d54 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/wiki/CharWiki.js @@ -0,0 +1,105 @@ +import lodash from 'lodash' +import CharTalent from './CharTalent.js' +import CharWikiData from './CharWikiData.js' +import CharMaterial from './CharMaterial.js' +import { Cfg, Common } from '#miao' +import { Character } from '#miao.models' + +const wikiReg = /^(?:#|喵喵)?(.*)(天赋|技能|命座|命之座|资料|图鉴|照片|写真|图片|图像)$/ + +const CharWiki = { + check (e) { + let msg = e.original_msg || e.msg + if (!e.msg) { + return false + } + let ret = wikiReg.exec(msg) + if (!ret || !ret[1] || !ret[2]) { + return false + } + let mode = 'talent' + if (/命/.test(ret[2])) { + mode = 'cons' + } else if (/(图鉴|资料)/.test(ret[2])) { + mode = 'wiki' + if (!Common.cfg('charWiki')) { + return false + } + } else if (/图|画|写真|照片/.test(ret[2])) { + mode = 'pic' + if (!Common.cfg('charPic')) { + return false + } + } else if (/(材料|养成|成长)/.test(ret[2])) { + mode = 'material' + } + if (['cons', 'talent'].includes(mode) && !Common.cfg('charWikiTalent')) { + return false + } + let char = Character.get(ret[1]) + if (!char || (char.isCustom && mode !== 'pic')) { + return false + } + e.wikiMode = mode + e.msg = '#喵喵WIKI' + e.char = char + return true + }, + + async wiki (e) { + let mode = e.wikiMode + let char = e.char + + if (mode === 'pic') { + let img = char.getCardImg(Cfg.get('charPicSe', false), false) + if (img && img.img) { + e.reply(segment.image(`file://${process.cwd()}/plugins/miao-plugin/resources/${img.img}`)) + } else { + e.reply('暂无图片') + } + return true + } + if (char.isCustom) { + if (mode === 'wiki') { + return false + } + e.reply('暂不支持自定义角色') + return true + } + if (!char.isRelease && Cfg.get('notReleasedData') === false) { + e.reply('未实装角色资料已禁用...') + return true + } + + if (mode === 'wiki') { + if (char.source === 'amber') { + e.reply('暂不支持该角色图鉴展示') + return true + } + return await CharWiki.render({ e, char }) + } else if (mode === 'material') { + return CharMaterial.render({ e, char }) + } + return await CharTalent.render(e, mode, char) + }, + + async render ({ e, char }) { + let data = char.getData() + lodash.extend(data, char.getData('weaponTypeName,elemName')) + // 命座持有 + let holding = await CharWikiData.getHolding(char.id) + let usage = await CharWikiData.getUsage(char.id) + return await Common.render('wiki/character-wiki', { + data, + attr: char.getAttrList(), + detail: char.getDetail(), + imgs: char.getImgs(), + holding, + usage, + materials: char.getMaterials(), + elem: char.elem + }, { e, scale: 1.4 }) + } +} + +export default CharWiki diff --git a/Yunzai/plugins/miao-plugin/apps/wiki/CharWikiData.js b/Yunzai/plugins/miao-plugin/apps/wiki/CharWikiData.js new file mode 100644 index 0000000000000000000000000000000000000000..fad1a7e871c3407f114eb10ce34802006a3258f4 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/apps/wiki/CharWikiData.js @@ -0,0 +1,108 @@ +import HutaoApi from '../stat/HutaoApi.js' +import lodash from 'lodash' +import { Format } from '#miao' +import { ArtifactSet, Weapon } from '#miao.models' + +let CharWikiData = { + /** + * 角色命座持有 + * @param id + * @returns {Promise<{}>} + */ + async getHolding (id) { + let consData = (await HutaoApi.getCons()).data || {} + consData = lodash.find(consData, (ds) => ds.avatar === id) + let holding = {} + if (consData) { + let { holdingRate, rate } = consData + rate = lodash.sortBy(rate, 'id') + holding.num = Format.percent(holdingRate) + holding.cons = [] + lodash.forEach(rate, (ds) => { + holding.cons.push({ + cons: ds.id, + num: Format.percent(ds.value) + }) + }) + } + return holding + }, + + /** + * 角色武器、圣遗物使用 + * @param id + * @returns {Promise<{}|{artis: *[], weapons: *[]}>} + */ + async getUsage (id) { + let ud = (await HutaoApi.getUsage()).data || {} + if (!ud[id]) { + return {} + } + ud = ud[id] + return { + weapons: CharWikiData.getWeaponsData(ud.weapons), + artis: CharWikiData.getArtisData(ud.artis) + } + }, + + /** + * 武器使用 + * @param data + * @returns {*[]} + */ + getWeaponsData (data = []) { + let weapons = [] + + lodash.forEach(data, (ds) => { + let weapon = Weapon.get(ds.item) || {} + weapons.push({ + ...weapon.getData('name,abbr,img,star'), + value: ds.rate + }) + }) + + weapons = lodash.sortBy(weapons, 'value') + weapons = weapons.reverse() + lodash.forEach(weapons, (ds) => { + ds.value = Format.percent(ds.value, 1) + }) + return weapons + }, + + /** + * 圣遗物使用 + * @param data + * @returns {*[]} + */ + getArtisData (data = []) { + let artis = [] + + lodash.forEach(data, (ds) => { + let imgs = [] + let abbrs = [] + let ss = ds.item.split(',') + lodash.forEach(ss, (t) => { + t = t.split(':') + let artiSet = ArtifactSet.get(t[0]) + if (artiSet) { + imgs.push(artiSet.img) + abbrs.push(artiSet.abbr + (ss.length === 1 ? t[1] : '')) + } + }) + + artis.push({ + imgs, + title: abbrs.join('+'), + value: ds.rate + }) + }) + + artis = lodash.sortBy(artis, 'value') + artis = artis.reverse() + artis.forEach((ds) => { + ds.value = Format.percent(ds.value) + }) + return artis + } +} +export default CharWikiData diff --git a/Yunzai/plugins/miao-plugin/components/App.js b/Yunzai/plugins/miao-plugin/components/App.js new file mode 100644 index 0000000000000000000000000000000000000000..c5c02e0478e724ea3dab4d47d37e409bac7c4bdf --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/App.js @@ -0,0 +1,133 @@ +import lodash from 'lodash' +import Plugin from './common/Plugin.js' +import { Version, MiaoError } from '#miao' + +class App { + constructor (cfg) { + this.id = cfg.id + this.cfg = cfg + this.apps = {} + } + + reg (key, fn, cfg = {}) { + if (lodash.isPlainObject(key)) { + lodash.forEach(key, (cfg, k) => { + this.reg(k, cfg.fn, cfg) + }) + } else { + this.apps[key] = { + fn, + ...cfg + } + } + } + + // 获取v3执行方法 + v3App () { + let cfg = this.cfg || {} + let rules = [] + let check = [] + let event = cfg.event + let cls = class extends Plugin { + constructor () { + super({ + name: `喵喵:${cfg.name || cfg.id}`, + dsc: cfg.desc || cfg.name || '喵喵插件', + event: event === 'poke' ? 'notice.*.poke' : 'message', + priority: cfg.priority || 50, + rule: rules + }) + } + + accept (e) { + e.original_msg = e.original_msg || e.msg + for (let idx = 0; idx < check.length; idx++) { + if (check[idx](e, e.original_msg) === true) { + return true + } + } + } + } + + for (let key in this.apps) { + let app = this.apps[key] + key = lodash.camelCase(key) + let rule = app.rule || app.reg || 'noCheck' + if (event !== 'poke') { + if (typeof (rule) === 'string') { + if (rule === 'noCheck') { + rule = '.*' + } + } else { + rule = lodash.trim(rule.toString(), '/') + } + } else { + rule = '.*' + } + + rules.push({ + reg: rule, + fnc: key + }) + + if (app.check) { + check.push(app.check) + } + + cls.prototype[key] = async function (e) { + e = this.e || e + const self_id = e.self_id || e.bot?.uin || Bot.uin + if (event === 'poke') { + if (e.notice_type === 'group') { + if (e.target_id !== self_id && !e.isPoke) { + return false + } + // group状态下,戳一戳的发起人是operator + if (e.user_id === self_id) { + e.user_id = e.operator_id + } + } + e.isPoke = true + // 随便指定一个不太常见的msg以触发msg的正则 + e.msg = '#poke#' + } + e.original_msg = e.original_msg || e.msg + try { + return await app.fn.call(this, e) + } catch (err) { + if (err?.message && (err instanceof MiaoError)) { + // 处理 MiaoError + return e.reply(err.message) + } else { + // 其他错误抛出 + throw err + } + } + } + + if (app.yzRule && app.yzCheck) { + let yzKey = `Yz${key}` + let yzRule = lodash.trim(app.yzRule.toString(), '/') + rules.push({ + reg: yzRule, + fnc: yzKey + }) + cls.prototype[yzKey] = async function (e) { + if (!Version.isMiao && !app.yzCheck()) { + return false + } + e = this.e || e + e.original_msg = e.original_msg || e.msg + return await app.fn.call(this, e) + } + } + } + return cls + } +} + +App.init = function (cfg) { + return new App(cfg) +} + +export default App diff --git a/Yunzai/plugins/miao-plugin/components/Cfg.js b/Yunzai/plugins/miao-plugin/components/Cfg.js new file mode 100644 index 0000000000000000000000000000000000000000..a6573ef32c6784ea0f14366dff081d4ea75ad03f --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/Cfg.js @@ -0,0 +1,56 @@ +import fs from 'fs' +import lodash from 'lodash' +import cfgData from './cfg/CfgData.js' +import { Version } from '#miao' + +const _path = process.cwd() +const _cfgPath = `${_path}/plugins/miao-plugin/components/` +let cfg = {} +let miaoCfg = {} + + +try { + cfg = await cfgData.getCfg() + cfgData.saveCfg(cfg) + lodash.forEach(cfgData.getCfgSchemaMap(), (cm) => { + if (cm.miao) { + miaoCfg[cm.cfgKey] = true + } + }) +} catch (e) { + // do nth +} + +let Cfg = { + get (rote) { + if (Version.isMiao && miaoCfg[rote]) { + return true + } + return lodash.get(cfg, rote) + }, + set (rote, val) { + cfg[rote] = val + cfgData.saveCfg(cfg) + }, + del (rote) { + lodash.set(cfg, rote, undefined) + fs.writeFileSync(_cfgPath + 'cfg.json', JSON.stringify(cfg, null, '\t')) + }, + getCfg () { + return cfg + }, + getCfgSchema () { + return cfgData.getCfgSchema() + }, + getCfgSchemaMap () { + return cfgData.getCfgSchemaMap() + }, + scale (pct = 1) { + let scale = Cfg.get('renderScale', 100) + scale = Math.min(2, Math.max(0.5, scale / 100)) + pct = pct * scale + return `style=transform:scale(${pct})` + } +} + +export default Cfg diff --git a/Yunzai/plugins/miao-plugin/components/Common.js b/Yunzai/plugins/miao-plugin/components/Common.js new file mode 100644 index 0000000000000000000000000000000000000000..23efc80c4145e77930c7369385029480565f1d7a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/Common.js @@ -0,0 +1,17 @@ +import Cfg from './Cfg.js' +import Render from './common/Render.js' + +const Common = { + render: Render.render, + cfg: Cfg.get, + sleep (ms) { + return new Promise((resolve) => setTimeout(resolve, ms)) + }, + + async downFile () { + console.log('down file') + } + +} + +export default Common diff --git a/Yunzai/plugins/miao-plugin/components/Data.js b/Yunzai/plugins/miao-plugin/components/Data.js new file mode 100644 index 0000000000000000000000000000000000000000..9a7cdfa8454ee66e6ee9e4e37920bdd2bc275b8b --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/Data.js @@ -0,0 +1,292 @@ +import lodash from 'lodash' +import fs from 'fs' + +const _path = process.cwd() +const getRoot = (root = '') => { + if (!root) { + root = `${_path}/` + } else if (root === 'root' || root === 'yunzai') { + root = `${_path}/` + } else if (root === 'miao') { + root = `${_path}/plugins/miao-plugin/` + } else { + root = `${_path}/plugins/${root}/` + } + return root +} + +let Data = { + + getRoot, + + /* + * 根据指定的path依次检查与创建目录 + * */ + createDir (path = '', root = '', includeFile = false) { + root = getRoot(root) + let pathList = path.split('/') + let nowPath = root + pathList.forEach((name, idx) => { + name = name.trim() + if (!includeFile && idx <= pathList.length - 1) { + nowPath += name + '/' + if (name) { + if (!fs.existsSync(nowPath)) { + fs.mkdirSync(nowPath) + } + } + } + }) + }, + + /* + * 读取json + * */ + readJSON (file = '', root = '') { + root = getRoot(root) + if (fs.existsSync(`${root}/${file}`)) { + try { + return JSON.parse(fs.readFileSync(`${root}/${file}`, 'utf8')) + } catch (e) { + console.log(e) + } + } + return {} + }, + + /* + * 写JSON + * */ + writeJSON (cfg, data, root = '', space = 2) { + if (arguments.length > 1) { + return Data.writeJSON({ + name: cfg, + data, + space, + root + }) + } + // 检查并创建目录 + let name = cfg.path ? (cfg.path + '/' + cfg.name) : cfg.name + Data.createDir(name, cfg.root, true) + root = getRoot(cfg.root) + data = cfg.data + delete data._res + data = JSON.stringify(data, null, cfg.space || 2) + if (cfg.rn) { + data = data.replaceAll('\n', '\r\n') + } + return fs.writeFileSync(`${root}/${name}`, data) + }, + + delFile (file, root = '') { + root = getRoot(root) + try { + if (fs.existsSync(`${root}/${file}`)) { + fs.unlinkSync(`${root}/${file}`) + } + return true + } catch (error) { + logger.error(`文件删除失败:${error}`) + } + return false + }, + + async getCacheJSON (key) { + try { + let txt = await redis.get(key) + if (txt) { + return JSON.parse(txt) + } + } catch (e) { + console.log(e) + } + return {} + }, + + async setCacheJSON (key, data, EX = 3600 * 24 * 90) { + await redis.set(key, JSON.stringify(data), { EX }) + }, + + async redisGet (key, def = {}) { + try { + let txt = await redis.get(key) + if (txt) { + return JSON.parse(txt) + } + } catch (e) { + console.log(e) + } + return def + }, + + async redisSet (key, data, EX = 3600 * 24 * 90) { + await redis.set(key, JSON.stringify(data), { EX }) + }, + + async importModule (file, root = '') { + root = getRoot(root) + if (!/\.js$/.test(file)) { + file = file + '.js' + } + if (fs.existsSync(`${root}/${file}`)) { + try { + let data = await import(`file://${root}/${file}?t=${new Date() * 1}`) + return data || {} + } catch (e) { + console.log(e) + } + } + return {} + }, + + async importDefault (file, root) { + let ret = await Data.importModule(file, root) + return ret.default || {} + }, + + async importCfg (key) { + let sysCfg = await Data.importModule(`config/system/${key}_system.js`, 'miao') + let diyCfg = await Data.importModule(`config/${key}.js`, 'miao') + if (diyCfg.isSys) { + console.error(`miao-plugin: config/${key}.js无效,已忽略`) + console.error(`如需配置请复制config/${key}_default.js为config/${key}.js,请勿复制config/system下的系统文件`) + diyCfg = {} + } + return { + sysCfg, + diyCfg + } + }, + + /* + * 返回一个从 target 中选中的属性的对象 + * + * keyList : 获取字段列表,逗号分割字符串 + * key1, key2, toKey1:fromKey1, toKey2:fromObj.key + * + * defaultData: 当某个字段为空时会选取defaultData的对应内容 + * toKeyPrefix:返回数据的字段前缀,默认为空。defaultData中的键值无需包含toKeyPrefix + * + * */ + + getData (target, keyList = '', cfg = {}) { + target = target || {} + let defaultData = cfg.defaultData || {} + let ret = {} + // 分割逗号 + if (typeof (keyList) === 'string') { + keyList = keyList.split(',') + } + + lodash.forEach(keyList, (keyCfg) => { + // 处理通过:指定 toKey & fromKey + let _keyCfg = keyCfg.split(':') + let keyTo = _keyCfg[0].trim() + let keyFrom = (_keyCfg[1] || _keyCfg[0]).trim() + let keyRet = keyTo + if (cfg.lowerFirstKey) { + keyRet = lodash.lowerFirst(keyRet) + } + if (cfg.keyPrefix) { + keyRet = cfg.keyPrefix + keyRet + } + // 通过Data.getVal获取数据 + ret[keyRet] = Data.getVal(target, keyFrom, defaultData[keyTo], cfg) + }) + return ret + }, + + getVal (target, keyFrom, defaultValue) { + return lodash.get(target, keyFrom, defaultValue) + }, + + // 异步池,聚合请求 + async asyncPool (poolLimit, array, iteratorFn) { + const ret = [] // 存储所有的异步任务 + const executing = [] // 存储正在执行的异步任务 + for (const item of array) { + // 调用iteratorFn函数创建异步任务 + const p = Promise.resolve().then(() => iteratorFn(item, array)) + // 保存新的异步任务 + ret.push(p) + + // 当poolLimit值小于或等于总任务个数时,进行并发控制 + if (poolLimit <= array.length) { + // 当任务完成后,从正在执行的任务数组中移除已完成的任务 + const e = p.then(() => executing.splice(executing.indexOf(e), 1)) + executing.push(e) // 保存正在执行的异步任务 + if (executing.length >= poolLimit) { + // 等待较快的任务执行完成 + await Promise.race(executing) + } + } + } + return Promise.all(ret) + }, + + // sleep + sleep (ms) { + return new Promise((resolve) => setTimeout(resolve, ms)) + }, + + // 获取默认值 + def () { + for (let idx in arguments) { + if (!lodash.isUndefined(arguments[idx])) { + return arguments[idx] + } + } + }, + + async forEach (data, fn) { + if (lodash.isArray(data)) { + for (let idx = 0; idx < data.length; idx++) { + let ret = fn(data[idx], idx) + if (ret instanceof Promise) { + ret = await ret + } + if (ret === false) { + break + } + } + } else if (lodash.isPlainObject(data)) { + for (const idx in data) { + let ret = fn(data[idx], idx) + if (ret instanceof Promise) { + ret = await ret + } + if (ret === false) { + break + } + } + } + }, + + // 循环字符串回调 + eachStr: (arr, fn) => { + if (lodash.isString(arr)) { + arr = arr.replace(/\s*(;|;|、|,)\s*/, ',') + arr = arr.split(',') + } else if (lodash.isNumber(arr)) { + arr = [arr.toString()] + } + lodash.forEach(arr, (str, idx) => { + if (!lodash.isUndefined(str)) { + fn(str.trim ? str.trim() : str, idx) + } + }) + }, + + regRet (reg, txt, idx) { + if (reg && txt) { + let ret = reg.exec(txt) + if (ret && ret[idx]) { + return ret[idx] + } + } + return false + } +} + +export default Data diff --git a/Yunzai/plugins/miao-plugin/components/Format.js b/Yunzai/plugins/miao-plugin/components/Format.js new file mode 100644 index 0000000000000000000000000000000000000000..3ebc439d5a5e0e145eb923b01b96def80fbbf656 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/Format.js @@ -0,0 +1,25 @@ +import lodash from 'lodash' +import Elem from './common/Elem.js' +import { Cfg } from '#miao' + +let Format = { + ...Elem, + int: function (d) { + return parseInt(d) + }, + comma: function (num, fix = 0) { + num = parseFloat((num * 1).toFixed(fix)) + let [integer, decimal] = String.prototype.split.call(num, '.') + let re = new RegExp(`\\d(?=(\\d{${Cfg.get('commaGroup', 3)}})+$)`, 'g') + integer = integer.replace(re, '$&,') // 正则先行断言 = /\d(?=(\d{3})+$)/g + return `${integer}${fix > 0 ? '.' + (decimal || lodash.repeat('0', fix)) : ''}` + }, + pct: function (num, fix = 1) { + return (num * 1).toFixed(fix) + '%' + }, + percent: function (num, fix = 1) { + return Format.pct(num * 100, fix) + } +} + +export default Format diff --git a/Yunzai/plugins/miao-plugin/components/MiaoError.js b/Yunzai/plugins/miao-plugin/components/MiaoError.js new file mode 100644 index 0000000000000000000000000000000000000000..0baff7a6dd2dbe3e5a75c9485eabea722049bdc4 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/MiaoError.js @@ -0,0 +1,17 @@ +export default class MiaoError extends Error { + + constructor(message) { + // 允许返回特殊消息,需传递数组,例如 [segment.image()] + if (Array.isArray(message)) { + super() + this._message = message + } else { + super(message); + } + } + + get message() { + return this._message ? this._message : super.message; + } + +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/components/Version.js b/Yunzai/plugins/miao-plugin/components/Version.js new file mode 100644 index 0000000000000000000000000000000000000000..d4222a537fc82542f9755f1342a643c323aa2136 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/Version.js @@ -0,0 +1,109 @@ +import fs from 'fs' +import lodash from 'lodash' +import { Data } from '#miao' + +let packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')) + +const getLine = function (line) { + line = line.replace(/(^\s*\*|\r)/g, '') + line = line.replace(/\s*`([^`]+`)/g, '$1') + line = line.replace(/`\s*/g, '') + line = line.replace(/\s*\*\*([^\*]+\*\*)/g, '$1') + line = line.replace(/\*\*\s*/g, '') + line = line.replace(/ⁿᵉʷ/g, '') + return line +} + +const readLogFile = function (root, versionCount = 4) { + root = Data.getRoot(root) + let logPath = `${root}/CHANGELOG.md` + let logs = {} + let changelogs = [] + let currentVersion + + try { + if (fs.existsSync(logPath)) { + logs = fs.readFileSync(logPath, 'utf8') || '' + logs = logs.split('\n') + + let temp = {} + let lastLine = {} + lodash.forEach(logs, (line) => { + if (versionCount <= -1) { + return false + } + let versionRet = /^#\s*([0-9a-zA-Z\\.~\s]+?)\s*$/.exec(line) + if (versionRet && versionRet[1]) { + let v = versionRet[1].trim() + if (!currentVersion) { + currentVersion = v + } else { + changelogs.push(temp) + if (/0\s*$/.test(v) && versionCount > 0) { + versionCount = 0 + } else { + versionCount-- + } + } + + temp = { + version: v, + logs: [] + } + } else { + if (!line.trim()) { + return + } + if (/^\*/.test(line)) { + lastLine = { + title: getLine(line), + logs: [] + } + temp.logs.push(lastLine) + } else if (/^\s{2,}\*/.test(line)) { + lastLine.logs.push(getLine(line)) + } + } + }) + } + } catch (e) { + // do nth + } + return { changelogs, currentVersion } +} + +const { changelogs, currentVersion } = readLogFile('miao') + + +const yunzaiVersion = packageJson.version +const isV3 = yunzaiVersion[0] === '3' +let isMiao = false +let name = "Yunzai-Bot" +if (packageJson.name === 'miao-yunzai') { + isMiao = true + name = "Miao-Yunzai" +} else if (packageJson.name === 'trss-yunzai') { + isMiao = true + name = "TRSS-Yunzai" +} + +let Version = { + isV3, + isMiao, + name, + get version () { + return currentVersion + }, + get yunzai () { + return yunzaiVersion + }, + get changelogs () { + return changelogs + }, + runtime () { + console.log(`未能找到e.runtime,请升级至最新版${isV3 ? 'V3' : 'V2'}-Yunzai以使用miao-plugin`) + }, + readLogFile +} + +export default Version diff --git a/Yunzai/plugins/miao-plugin/components/cfg/CfgData.js b/Yunzai/plugins/miao-plugin/components/cfg/CfgData.js new file mode 100644 index 0000000000000000000000000000000000000000..a5dbd2e66b1b6114b2505bb16169fc64c9a2d120 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/cfg/CfgData.js @@ -0,0 +1,47 @@ +import { cfgSchema } from '../../config/system/cfg_system.js' +import lodash from 'lodash' +import { Data } from '../index.js' +import fs from 'node:fs' + +let cfgData = { + saveCfg (cfg) { + let ret = [] + lodash.forEach(cfgSchema, (cfgGroup) => { + ret.push(`/** ************ 【${cfgGroup.title}】 ************* */`) + lodash.forEach(cfgGroup.cfg, (cfgItem, cfgKey) => { + ret.push(`// ${cfgItem.desc || cfgItem.title}`) + let val = Data.def(cfg[cfgKey], cfgItem.def) + if (cfgItem.input) { + val = cfgItem.input(val) + } + ret.push(`export const ${cfgKey} = ${val.toString()}`, '') + }) + }) + fs.writeFileSync(`${process.cwd()}/plugins/miao-plugin/config/cfg.js`, ret.join('\n'), 'utf8') + }, + + async getCfg () { + let ret = lodash.toPlainObject(await Data.importModule('/config/cfg.js', 'miao')) + lodash.forEach(cfgSchema, (cfgGroup) => { + lodash.forEach(cfgGroup.cfg, (cfgItem, cfgKey) => { + ret[cfgKey] = Data.def(ret[cfgKey], cfgItem.def) + }) + }) + return ret + }, + + getCfgSchemaMap () { + let ret = {} + lodash.forEach(cfgSchema, (cfgGroup) => { + lodash.forEach(cfgGroup.cfg, (cfgItem, cfgKey) => { + ret[cfgItem.key] = cfgItem + cfgItem.cfgKey = cfgKey + }) + }) + return ret + }, + getCfgSchema () { + return cfgSchema + } +} +export default cfgData diff --git a/Yunzai/plugins/miao-plugin/components/common/Elem.js b/Yunzai/plugins/miao-plugin/components/common/Elem.js new file mode 100644 index 0000000000000000000000000000000000000000..5489927214800bc5e2804bbe0447c8071c540db5 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/common/Elem.js @@ -0,0 +1,86 @@ +import { Data } from '../index.js' +import lodash from 'lodash' + +const elemAlias = { + anemo: '风,蒙德', + geo: '岩,璃月', + electro: '雷,电,雷电,稻妻', + dendro: '草,须弥', + pyro: '火,纳塔', + hydro: '水,枫丹', + cryo: '冰,至冬' +} + +const elemAliasSR = { + fire: '火', + ice: '冰', + wind: '风', + elec: '雷', + phy: '物理', + quantum: '量子', + imaginary: '虚数' +} + +// 元素属性映射, 名称=>elem +let elemMap = {} +let elemMapSR = {} + +// 标准元素名 +let elemTitleMap = {} +let elemTitleMapSR = elemAliasSR + +lodash.forEach(elemAlias, (txt, key) => { + elemMap[key] = key + elemTitleMap[key] = txt[0] + Data.eachStr(txt, (t) => (elemMap[t] = key)) +}) +lodash.forEach(elemAliasSR, (txt, key) => { + elemMapSR[key] = key + elemMapSR[txt] = key +}) + +const Elem = { + // 根据名称获取元素key + elem (elem = '', defElem = '', game = 'gs') { + elem = elem.toLowerCase() + return (game === 'gs' ? elemMap : elemMapSR)[elem] || defElem + }, + + // 根据key获取元素名 + elemName (elem = '', defName = '') { + return elemTitleMap[Elem.elem(elem)] || defName + }, + + // 从字符串中匹配元素 + matchElem (name = '', defElem = '', withName = false) { + const elemReg = new RegExp(`^(${lodash.keys(elemMap).join('|')})`) + let elemRet = elemReg.exec(name) + let elem = (elemRet && elemRet[1]) ? Elem.elem(elemRet[1]) : defElem + if (elem) { + if (withName) { + return { + elem, + name: name.replace(elemReg, '') + } + } + return elem + } + return '' + }, + + eachElem (fn, game = 'gs') { + lodash.forEach(game === 'gs' ? elemTitleMap : elemTitleMapSR, (title, key) => { + fn(key, title) + }) + }, + + isElem (elem = '', game = 'gs') { + return !!(game === 'gs' ? elemMap : elemMapSR)[elem] + }, + + sameElem (key1, key2, game = 'gs') { + let map = (game === 'gs' ? elemMap : elemMapSR) + return map[key1] === map[key2] + } +} +export default Elem diff --git a/Yunzai/plugins/miao-plugin/components/common/Plugin.js b/Yunzai/plugins/miao-plugin/components/common/Plugin.js new file mode 100644 index 0000000000000000000000000000000000000000..7dec3776ef4d887d2cd52cbb503cb2b74c12cc77 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/common/Plugin.js @@ -0,0 +1,103 @@ +/* +* V3版Yunzai plugin +* */ +let stateArr = {} + +export default class plugin { + /** + * @param name 插件名称 + * @param dsc 插件描述 + * @param event 执行事件,默认message + * @param priority 优先级,数字越小优先级越高 + * @param rule.reg 命令正则 + * @param rule.fnc 命令执行方法 + * @param rule.event 执行事件,默认message + * @param rule.log false时不显示执行日志 + * @param rule.permission 权限 master,owner,admin,all + * @param task.name 定时任务名称 + * @param task.cron 定时任务cron表达式 + * @param task.fnc 定时任务方法名 + * @param task.log false时不显示执行日志 + */ + constructor (data) { + /** 插件名称 */ + this.name = data.name + /** 插件描述 */ + this.dsc = data.dsc + /** 监听事件,默认message https://oicqjs.github.io/oicq/#events */ + this.event = data.event || 'message' + /** 优先级 */ + this.priority = data.priority || 5000 + /** 定时任务,可以是数组 */ + this.task = { + /** 任务名 */ + name: '', + /** 任务方法名 */ + fnc: data.task?.fnc || '', + /** 任务cron表达式 */ + cron: data.task?.cron || '' + } + + /** 命令规则 */ + this.rule = data.rule || [] + } + + /** + * @param msg 发送的消息 + * @param quote 是否引用回复 + * @param data.recallMsg 群聊是否撤回消息,0-120秒,0不撤回 + * @param data.at 是否at用户 + */ + reply (msg = '', quote = false, data = {}) { + if (!this.e.reply || !msg) return false + return this.e.reply(msg, quote, data) + } + + conKey (isGroup = false) { + if (isGroup) { + return `${this.name}.${this.e.group_id}` + } else { + return `${this.name}.${this.userId || this.e.user_id}` + } + } + + /** + * @param type 执行方法 + * @param isGroup 是否群聊 + * @param time 操作时间,默认120秒 + */ + setContext (type, isGroup = false, time = 120) { + let key = this.conKey(isGroup) + if (!stateArr[key]) stateArr[key] = {} + stateArr[key][type] = this.e + if (time) { + /** 操作时间 */ + setTimeout(() => { + if (stateArr[key][type]) { + delete stateArr[key][type] + this.e.reply('操作超时已取消', true) + } + }, time * 1000) + } + } + + getContext () { + let key = this.conKey() + return stateArr[key] + } + + getContextGroup () { + let key = this.conKey(true) + return stateArr[key] + } + + /** + * @param type 执行方法 + * @param isGroup 是否群聊 + */ + finish (type, isGroup = false) { + if (stateArr[this.conKey(isGroup)] && stateArr[this.conKey(isGroup)][type]) { + delete stateArr[this.conKey(isGroup)][type] + } + } +} diff --git a/Yunzai/plugins/miao-plugin/components/common/Render.js b/Yunzai/plugins/miao-plugin/components/common/Render.js new file mode 100644 index 0000000000000000000000000000000000000000..3171602c86de0e965eb6ee75c65faaed02d32c27 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/common/Render.js @@ -0,0 +1,42 @@ +import { Version, Cfg } from '#miao' + +const Render = { + async render (path, params, cfg) { + let { e } = cfg + if (!e.runtime) { + console.log('未找到e.runtime,请升级至最新版Yunzai') + } + return e.runtime.render('miao-plugin', path, params, { + retType: cfg.retMsgId ? 'msgId' : 'default', + beforeRender ({ data }) { + let pluginName = '' + if (data.pluginName !== false) { + pluginName = ` & ${data.pluginName || 'Miao-Plugin'}` + if (data.pluginVersion !== false) { + pluginName += `${data.pluginVersion || Version.version}` + } + } + let resPath = data.pluResPath + const layoutPath = process.cwd() + '/plugins/miao-plugin/resources/common/layout/' + return { + ...data, + _res_path: resPath, + _miao_path: resPath, + _layout_path: layoutPath, + _tpl_path: process.cwd() + '/plugins/miao-plugin/resources/common/tpl/', + defaultLayout: layoutPath + 'default.html', + elemLayout: layoutPath + 'elem.html', + sys: { + scale: Cfg.scale(cfg.scale || 1) + }, + copyright: `Created By ${Version.name}${Version.yunzai}${pluginName}`, + pageGotoParams: { + waitUntil: 'networkidle2' + } + } + } + }) + } +} + +export default Render \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/components/index.js b/Yunzai/plugins/miao-plugin/components/index.js new file mode 100644 index 0000000000000000000000000000000000000000..1fc0a3578884a8ec213ad44d91910560aeb79b4c --- /dev/null +++ b/Yunzai/plugins/miao-plugin/components/index.js @@ -0,0 +1,9 @@ +import Data from './Data.js' +import Format from './Format.js' +import Common from './Common.js' +import Cfg from './Cfg.js' +import Version from './Version.js' +import App from './App.js' +import MiaoError from './MiaoError.js' + +export { Data, Cfg, Format, Common, Version, App, MiaoError } diff --git a/Yunzai/plugins/miao-plugin/config/character_default.js b/Yunzai/plugins/miao-plugin/config/character_default.js new file mode 100644 index 0000000000000000000000000000000000000000..9de9fce41f083e31f770ddf7ddee36178df74f7d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/config/character_default.js @@ -0,0 +1,38 @@ +/** +* 如需新增自定义角色可【复制】此文件,改名为character.js +* 复制的character.js中可按格式及自己需求进行配置 +* +* 暂未做热更新,修改完毕请重启yunzai +* */ + +/** +* 角色列表,别名的第一个是标准名字,后面的为别名 +* 实装的角色需要以数字roleid为key,自定义的角色及非实装角色请以英文为key +* */ +export const customCharacters = { + + // 已有角色添加别名示例:为魈增加新的别名 + // roleid请参见Yunzai config/genshin/roleId.js + 10000026: ['魈', '风夜叉'], + + // 自定义角色,角色id请以小写英文定义 + paimon: ['派蒙', '应急食物'] +} + +/** +* 追加设置每个关系的可选角色,会与原有设置同时起作用 +* 一个角色可以在多个关系中 +* */ +export const wifeData = { + // 老婆&女朋友:成女、少女 + girlfriend: '雷神', + + // 老公&男朋友:成男、少男 + boyfriend: '散兵, 魈', + + // 女儿:萝莉 + daughter: '派蒙, 瑶瑶', + + // 儿子:正太 + son: '' +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/config/help_default.js b/Yunzai/plugins/miao-plugin/config/help_default.js new file mode 100644 index 0000000000000000000000000000000000000000..406ff77e903e5c9787ff4398579edb1d689b41fe --- /dev/null +++ b/Yunzai/plugins/miao-plugin/config/help_default.js @@ -0,0 +1,191 @@ +/** +* 请注意,系统不会读取help_default.js !!!! +* 【请勿直接修改此文件,且可能导致后续冲突】 +* +* 如需自定义可将文件【复制】一份,并重命名为 help.js +* +* */ + +// 帮助配置 +export const helpCfg = { + // 帮助标题 + title: '喵喵帮助', + + // 帮助副标题 + subTitle: 'Yunzai-Bot & Miao-Plugin', + + // 帮助表格列数,可选:2-5,默认3 + // 注意:设置列数过多可能导致阅读困难,请参考实际效果进行设置 + colCount: 3, + + // 单列宽度,默认265 + // 注意:过窄可能导致文字有较多换行,请根据实际帮助项设定 + colWidth: 265, + + // 皮肤选择,可多选,或设置为all + // 皮肤包放置于 resources/help/theme + // 皮肤名为对应文件夹名 + // theme: 'all', // 设置为全部皮肤 + // theme: ['default','theme2'], // 设置为指定皮肤 + theme: 'all', + + // 排除皮肤:在存在其他皮肤时会忽略该项内设置的皮肤 + // 默认忽略default:即存在其他皮肤时会忽略自带的default皮肤 + // 如希望default皮肤也加入随机池可删除default项 + themeExclude: ['default'], + + // 是否启用背景毛玻璃效果,若渲染遇到问题可设置为false关闭 + bgBlur: true +} + +// 帮助菜单内容 +export const helpList = [{ + group: '游戏面板与信息查询', + list: [{ + icon: 61, + title: '#角色 #角色卡片 #探索', + desc: '你的原神角色数据,数据来自米游社' + }, { + icon: 63, + title: '#面板 #更新面板', + desc: '查看已经获取面板信息的角色列表' + }, { + icon: 66, + title: '#雷神面板 #雷神伤害', + desc: '查看角色详细面板及伤害信息' + }, { + icon: 65, + title: '#圣遗物列表 #雷神圣遗物', + desc: '查看圣遗物列表 / 评分详情' + }, { + icon: 79, + title: '#面板帮助', + desc: '面板替换及其他帮助信息' + }, { + icon: 64, + title: '#深渊 #深渊12层', + desc: '深渊数据,打完请2小时后查询' + }, { + icon: 67, + title: '#五星 #武器 #今日素材', + desc: '你的原神角色详情数据' + }, { + icon: 62, + title: '#五星列表 #练度统计', + desc: '角色列表数据' + }, { + icon: 77, + title: '#上传深渊数据', + desc: '上传您的深渊数据用于数据统计' + }] +}, { + group: '资料及图片', + list: [{ + icon: 58, + title: '#刻晴 #心海', + desc: '你的原神角色卡片' + }, { + icon: 59, + title: '#老婆 #老公', + desc: '查看老婆、老公' + }, { + icon: 60, + title: '#老婆设置心海,雷神', + desc: '设置老婆列表,也可设置随机' + }, { + icon: 88, + title: '#老婆照片 #甘雨照片', + desc: '查看指定角色的图片' + }, { + icon: 53, + title: '#夜兰天赋 #胡桃命座', + desc: '查看角色的天赋与命座资料' + }, { + icon: 56, + title: '#深渊配队', + desc: '根据你的角色池推荐组队' + }, { + icon: 78, + title: '#角色持有 #角色0命', + desc: '查看角色的持有率、0命统计' + }, { + icon: 77, + title: '#深渊使用率 #深渊出场率', + desc: '查看本期深渊使用或出场统计' + }, { + icon: 20, + title: '#刻晴攻略', + desc: '西风驿站攻略' + }, { + icon: 60, + title: '#心海图鉴 #护摩', + desc: '角色武器图鉴' + }] +}, { + group: '个人信息查询及签到', + desc: '需要绑定cookie', + list: [{ + icon: 15, + title: '#体力 #体力帮助', + desc: '查询体力,绑定Cookie帮助' + }, { + icon: 5, + title: '#原石 #原石统计', + desc: '札记数据,需要绑定Cookie' + }, { + icon: 10, + title: '#uid #绑定123456789', + desc: '查看绑定的uid 绑定uid' + }, { + icon: 22, + title: '#我的ck #删除ck', + desc: '查看绑定的cookie 删除cookie' + }, { + icon: 86, + title: '#签到', + desc: '米游社原神签到' + }] +}, { + group: '其他查询指令', + list: [{ + icon: 83, + title: '#日历 #日历列表', + desc: '查看活动日历' + }, { + icon: 6, + title: '#抽卡记录 #记录帮助', + desc: '统计游戏抽卡数据' + }, { + icon: 21, + title: '#角色统计 #武器统计', + desc: '按卡池统计抽卡数据' + }, { + icon: 8, + title: '十连 十连2 定轨', + desc: '真实模拟抽卡' + }, { + icon: 74, + title: '添加哈哈 删除哈哈', + desc: '添加表情,回复哈哈触发' + }, { + icon: 79, + title: '#帮助 #版本 #喵喵版本', + desc: '其他命令' + }] +}, { + group: '管理命令,仅管理员可用', + auth: 'master', + list: [{ + icon: 85, + title: '#用户统计', + desc: '查看用户CK-UID列表' + }, { + icon: 32, + title: '#喵喵设置', + desc: '配置喵喵功能' + }, { + icon: 35, + title: '#喵喵更新图像', + desc: '更新喵喵的增量角色图像素材' + }] +}] diff --git a/Yunzai/plugins/miao-plugin/config/profile_default.js b/Yunzai/plugins/miao-plugin/config/profile_default.js new file mode 100644 index 0000000000000000000000000000000000000000..59e192c1895f5e220678d59e969a23f498e4deba --- /dev/null +++ b/Yunzai/plugins/miao-plugin/config/profile_default.js @@ -0,0 +1,45 @@ +/** + * 如需配置【复制】此文件,改名为profile.js + * 暂未做热更新,修改完毕请重启yunzai + * */ + +/** + * Enka面板服务API配置 + * + * 【Enka官网】:https://enka.network/ + * 感谢Enka提供的面板查询服务,如果可以的话,也可考虑在Patreon上支持Enka + * 【Patreon】:https://www.patreon.com/algoinde + * + * 目前使用Miao-Plugin的默认UA请求国服UID时 + * 会默认重定向 https://enka.network/ 到 https://profile.microgg.cn/ + * 感谢@MiniGrayGay 大佬提供的服务(Github: https://github.com/MiniGrayGay) + * + * 使用代理(科学上网)可以配置proxyAgent + * 例如: http://127.0.0.1:1080 + * + * */ +export const enkaApi = { + url: 'https://enka.network/', // 请求API地址,可从上方提供的API地址中进行选择 + proxyAgent: '' // 请求的proxy配置,如无需proxy则留空 +} + +/** + * 喵喵Api 私有的面板更新服务 + * 供Yunzai开发者及有投喂的老板们小范围使用 + * + * 喵喵API承载能力有限,Enka可用的情况下建议使用Enka,token有有效期限制,请勿强行投喂 + * token请勿外传,一个token仅供一个bot使用,多bot复用的话可能导致token失效 + * */ +export const miaoApi = { + qq: '在此处填写主人QQ', + token: '在此处填写QQ对应Token' +} + +/** + * 单个用户请求面板的间隔时间,单位分钟 + * 不同用户的计时独立 + * + * 部分服务会同时返回服务侧更新冷却时间,若服务侧查询冷却大于更新间隔 + * 会以服务侧查询冷却为准(在服务侧冷却时间内,即使请求也不会返回更新数据) + * */ +export const requestInterval = 5 diff --git a/Yunzai/plugins/miao-plugin/config/system/cfg_system.js b/Yunzai/plugins/miao-plugin/config/system/cfg_system.js new file mode 100644 index 0000000000000000000000000000000000000000..cdd5563527b4482554a89dfa9489bd9be4669a28 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/config/system/cfg_system.js @@ -0,0 +1,191 @@ +export const cfgSchema = { + apps: { + title: 'Yunzai功能(开启使用喵喵版功能)', + cfg: { + avatarList: { + title: '#角色 #UID', + key: '角色列表', + def: false, + miao: true + }, + avatarCard: { + title: '#刻晴 #老婆', + key: '角色卡片', + def: true, + miao: true + }, + uploadAbyssData: { + title: '#深渊', + key: '深渊', + def: false, + miao: true + }, + profileStat: { + title: '#练度统计', + key: '练度统计', + def: false, + miao: true + }, + help: { + title: '#帮助 #菜单', + key: '帮助', + def: false, + miao: true + }, + gachaStat: { + title: '#抽卡分析 #抽卡统计', + key: '抽卡', + def: false, + miao: true + }, + avatarPoke: { + title: '戳一戳展示角色卡片', + key: '戳一戳', + def: true + } + } + }, + profile: { + title: '角色面板相关设置', + cfg: { + avatarProfile: { + title: '面板查询', + key: '面板查询', + def: true + }, + profileChange: { + title: '面板替换', + key: '面板替换', + def: true + }, + groupRank: { + title: '群面板排名', + key: '排名', + def: false, + desc: '群内的面板伤害及圣遗物排名与查看功能,默认关闭。请根据群友心理素质自行决定是否开启' + }, + groupRankLimit: { + title: '排名限制', + key: '限制', + def: 1, + type: 'num', + desc: '参与排名的限制条件:1:无限制 2:有CK 3:有16个角色或有CK 4:有御三家(安柏&凯亚&丽莎)或有CK 5:有16个角色+御三家或有CK。 若改变设置请根据情况决定是否需要【#重置排名】' + }, + rankNumber: { + title: '排行人数', + key: '排行人数', + type: 'num', + def: 15, + input: (n) => Math.min(30, Math.max(5, (n * 1 || 15))), + desc: '可选值5~30,建议15。设置高排名人数会提高图片的长度,图片较大可能会影响渲染与发送速度' + }, + profileServer: { + title: '面板服务', + key: '面板服务', + type: 'num', + def: 0, + input: (n) => /[0-4]{1,3}/.test(n) ? n : 0, + desc: '面板服务选择:0:自动,1:喵Api(需具备Token), 2:Enka-API, 3:MiniGG-Api, 4:Hutao-Enka代理。如设置三位数字则为分服务器设置,按顺序分别为 国服/B服/外服,例如112代表国服B服Miao,国外Enka' + }, + srProfileServer: { + title: '星铁面板服务', + key: '星铁面板服务', + type: 'num', + def: 0, + input: (n) => /[0-4]{1,3}/.test(n) ? n : 0, + desc: '星铁面板服务选择:0:自动,1:喵Api(需具备Token), 2:Mihomo, 3:Avocado(鳄梨), 4:EnkaHSR。如设置三位数字则为分服务器设置,按顺序分别为 国服/B服/外服,例如114代表国服B服Miao,国外Enka' + }, + costumeSplash: { + title: '使用自定义面板插图', + key: '面板图', + def: true, + desc: '开启彩蛋图(三皇冠/ACE/满命)及自定义面板图,关闭使用官方立绘' + }, + teamCalc: { + title: '组队加成伤害', + key: '组队', + def: false, + desc: '伤害计算包含组队Buff。目前为测试阶段,数据可能不准确,请慎重开启。数据为固定Buff而非真实面板数据,最终计算数值可能有偏差。开启后请重启喵喵' + }, + artisNumber: { + title: '圣遗物列表数量', + key: '圣遗物数量', + type: 'num', + def: 28, + input: (n) => Math.min(100, Math.max(4, (n * 1 || 28))), + desc: '可选值4~100,建议28,最终圣遗物数量取决于面板内圣遗物数量。设置高圣遗物数量会提高图片的长度,图片较大可能会影响渲染与发送速度' + } + } + }, + wiki: { + title: '角色资料与信息查询', + cfg: { + charWiki: { + title: '角色图鉴-图鉴', + key: '图鉴', + def: true, + showDesc: false, + desc: '#刻晴图鉴 的图鉴信息' + }, + charWikiTalent: { + title: '角色图鉴-天赋', + key: '天赋', + def: true, + showDesc: false, + desc: '#刻晴天赋/#刻晴命座 的天赋信息' + }, + notReleasedData: { + title: '未实装角色数据', + key: '未实装', + def: true, + showDesc: true, + desc: '开启时才能查看未实装角色信息。数据仅供参考,请以游戏正式实装内容为准' + }, + charPic: { + title: '角色图片', + key: '图片', + def: true + }, + qFace: { + title: 'Q版角色头像', + key: '卡通头像', + def: true + }, + charPicSe: { + title: '小清新角色图', + key: '小清新', + def: false, + desc: '启用后会启用角色图及增量包中的小清新图像,勇士啊,你准备好了吗' + } + } + }, + sys: { + title: '系统设置', + cfg: { + renderScale: { + title: '渲染精度', + key: '渲染', + type: 'num', + def: 100, + input: (n) => Math.min(200, Math.max(50, (n * 1 || 100))), + desc: '可选值50~200,建议100。设置高精度会提高图片的精细度,但因图片较大可能会影响渲染与发送速度' + }, + originalPic: { + title: '原图', + key: '原图', + type: 'num', + def: 3, + input: (n) => Math.min(3, Math.max(n * 1 || 0, 0)), + desc: '允许获取原图,0:不允许, 1:仅允许角色图, 2:仅允许面板图, 3:开启' + }, + commaGroup: { + title: '数字逗号分组', + key: '逗号', + def: 3, + type: 'num', + desc: '根据语言习惯设置数字分组,如千位组设为3,万位组设为4' + } + } + } + +} diff --git a/Yunzai/plugins/miao-plugin/config/system/character_system.js b/Yunzai/plugins/miao-plugin/config/system/character_system.js new file mode 100644 index 0000000000000000000000000000000000000000..49196a3eb3fdc9ddb99cf23e46e73bbcd1471f55 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/config/system/character_system.js @@ -0,0 +1,119 @@ +/** + * 请不要直接修改此或删除此文件,防止后续更新冲突 + * 如需新增自定义角色可【复制】config/character_default.js,改名为config/character.js + */ +export const characters = { + 10000003: ['琴', 'Jean', '团长', '代理团长', '琴团长', '蒲公英骑士'], + 10000006: ['丽莎', 'Lisa', '图书管理员', '图书馆管理员', '蔷薇魔女', '阿姨'], + 10000005: ['空', '男主', '男主角', '龙哥', '空哥', '男爷'], + 10000007: ['荧', '女主', '女主角', '莹', '萤', '黄毛阿姨', '荧妹', '女爷', '包包', '宴宁'], + 20000000: ['旅行者', '主角', '卑鄙的外乡人', '荣誉骑士', '爷', '主', '履刑者', '抽卡不歪真君'], + 10000014: ['芭芭拉', 'Barbara', '巴巴拉', '内鬼', '加湿器', '肉身解咒', '肉身解咒真君', '闪耀偶像', '偶像'], + 10000015: ['凯亚', 'Kaeya', '盖亚', '凯子哥', '凯鸭', '矿工', '矿工头子', '骑兵队长', '凯子', '凝冰渡海真君'], + 10000016: ['迪卢克', 'Diluc', '卢姥爷', '姥爷', '卢老爷', '卢锅巴', '正义人', '正e人', '正E人', '卢本伟', '暗夜英雄', '卢卢伯爵', '落魄了', '落魄了家人们'], + 10000020: ['雷泽', 'Razor', '狼少年', '狼崽子', '狼崽', '卢皮卡', '小狼', '小狼狗', '狼孩'], + 10000021: ['安柏', 'Amber', '安伯', '兔兔伯爵', '飞行冠军', '侦查骑士', '点火姬', '点火机', '打火机', '打火姬'], + 10000022: ['温迪', 'Venti', '温蒂', '风神', '卖唱的', '巴巴托斯', '巴巴脱丝', '芭芭托斯', '芭芭脱丝', '干点正事', '不干正事', '吟游诗人', '诶嘿', '唉嘿', '摸鱼'], + 10000023: ['香菱', 'Xiangling', '香玲', '锅巴', '厨师', '万民堂厨师', '香师傅'], + 10000024: ['北斗', 'Beidou', '大姐头', '大姐', '无冕的龙王'], + 10000025: ['行秋', 'Xingqiu', '秋秋人', '秋妹妹', '书呆子', '枕玉', '飞云商会二少爷'], + 10000026: ['魈', 'Xiao', '打桩机', '插秧', '三眼五显仙人', '三眼五显真人', '降魔大圣', '护法夜叉', '快乐风男', '无聊', '靖妖傩舞', '矮子仙人', '三点五尺仙人', '跳跳虎', '风夜叉'], + 10000027: ['凝光', 'Ningguang', '富婆', '天权星', '天权'], + 10000029: ['可莉', '逃跑的太阳', 'Klee', '嘟嘟可', '火花骑士', '蹦蹦炸弹', '炸鱼', '放火烧山', '放火烧山真君', '蒙德最强战力', '逃跑的太阳', '啦啦啦', '哒哒哒', '炸弹人', '禁闭室', '太阳', '小太阳'], + 10000030: ['钟离', 'Zhongli', '摩拉克斯', '岩王爷', '岩神', '钟师傅', '天动万象', '岩王帝君', '未来可期', '帝君', '拒收病婿'], + 10000031: ['菲谢尔', 'Fischl', '皇女', '小艾米', '小艾咪', '奥兹', '断罪皇女', '中二病', '中二少女', '中二皇女', '奥兹发射器'], + 10000032: ['班尼特', 'Bennett', '点赞哥', '点赞', '倒霉少年', '倒霉蛋', '霹雳闪雷真君', '班神', '班爷', '倒霉', '火神', '六星真神'], + 10000033: ['达达利亚', 'Tartaglia', 'Childe', 'Ajax', '达达鸭', '达达利鸭', '公子', '玩具销售员', '玩具推销员', '钱包', '鸭鸭', '愚人众末席'], + 10000034: ['诺艾尔', 'Noelle', '女仆', '高达', '岩王帝姬'], + 10000035: ['七七', 'Qiqi', '僵尸', '肚饿真君', '度厄真君', '77'], + 10000036: ['重云', 'Chongyun', '纯阳之体', '冰棍'], + 10000037: ['甘雨', 'Ganyu', '椰羊', '椰奶', '王小美'], + 10000038: ['阿贝多', 'Albedo', '可莉哥哥', '升降机', '升降台', '电梯', '白垩之子', '贝爷', '白垩', '阿贝少', '花呗多', '阿贝夕', '阿师傅'], + 10000039: ['迪奥娜', 'Diona', '迪欧娜', 'dio娜', '冰猫', '猫猫', '猫娘', '喵喵', '调酒师'], + 10000041: ['莫娜', 'Mona', '穷鬼', '穷光蛋', '穷', '莫纳', '占星术士', '占星师', '讨龙真君', '半部讨龙真君', '阿斯托洛吉斯·莫娜·梅姬斯图斯', '梅姬斯图斯', '梅姬斯图斯姬'], + 10000042: ['刻晴', 'Keqing', '刻情', '氪晴', '刻师傅', '刻师父', '牛杂', '牛杂师傅', '斩尽牛杂', '免疫', '免疫免疫', '屁斜剑法', '玉衡星', '阿晴', '啊晴', '璃月雷神'], + 10000043: ['砂糖', 'Sucrose', 'sucrose'], + 10000044: ['辛焱', 'Xinyan', '辛炎', '黑妹', '摇滚'], + 10000045: ['罗莎莉亚', 'Rosaria', '罗莎莉娅', '白色史莱姆', '白史莱姆', '修女', '罗莎利亚', '罗莎利娅', '罗沙莉亚', '罗沙莉娅', '罗沙利亚', '罗沙利娅', '萝莎莉亚', '萝莎莉娅', '萝莎利亚', '萝莎利娅', '萝沙莉亚', '萝沙莉娅', '萝沙利亚', '萝沙利娅'], + 10000046: ['胡桃', 'Hu Tao', 'HuTao', 'Hutao', '胡淘', '往生堂堂主', '火化', '抬棺的', '蝴蝶', '核桃', '堂主', '胡堂主', '雪霁梅香', '桃子', '桃'], + 10000047: ['枫原万叶', 'Kaedehara Kazuha', 'Kazuha', '万叶', '叶天帝', '天帝', '叶师傅'], + 10000048: ['烟绯', 'Yanfei', '烟老师', '律师', '罗翔'], + 10000051: ['优菈', 'Eula', '优拉', '尤拉', '尤菈', '浪花骑士', '记仇', '劳伦斯'], + + // 2.0 + 10000002: ['神里绫华', 'Kamisato Ayaka', 'Ayaka', '神里', '绫华', '神里凌华', '凌华', '白鹭公主', '神里大小姐', '龟', '龟龟', '乌龟'], + 10000049: ['宵宫', 'Yoimiya', '霄宫', '烟花', '肖宫', '肖工', '绷带女孩'], + 10000052: ['雷电将军', 'Raiden Shogun', 'Raiden', '雷神', '将军', '雷军', '巴尔', '阿影', '影', '巴尔泽布', '煮饭婆', '奶香一刀', '无想一刀', '宅女'], + 10000053: ['早柚', 'Sayu', '小狸猫', '狸猫', '忍者', '貉'], + 10000054: ['珊瑚宫心海', 'Sangonomiya Kokomi', 'Kokomi', '心海', '军师', '珊瑚宫', '书记', '观赏鱼', '水母', '鱼', '美人鱼'], + 10000056: ['九条裟罗', 'Kujou Sara', 'Sara', '九条', '九条沙罗', '裟罗', '沙罗', '天狗'], + 10000062: ['埃洛伊', 'Aloy'], + 10000050: ['托马', 'Thoma', '家政官', '太郎丸', '地头蛇', '男仆', '拖马'], + 10000055: ['五郎', 'Gorou', '柴犬', '土狗', '希娜', '希娜小姐'], + 10000057: ['荒泷一斗', 'Arataki Itto', 'Itto', '荒龙一斗', '荒泷天下第一斗', '一斗', '一抖', '荒泷', '1斗', '牛牛', '斗子哥', '牛子哥', '牛子', '孩子王', '斗虫', '巧乐兹', '放牛的'], + 10000058: ['八重神子', 'Yae Miko', 'Miko', '八重', '神子', '狐狸', '想得美哦', '巫女', '屑狐狸', '骚狐狸', '八重宫司', '婶子', '小八', '八重寄子', '寄子', '八神虫子', '八神重子'], + 10000059: ['鹿野院平藏', 'shikanoin heizou', 'Heizou', '鹿野苑', '鹿野院', '平藏', '鹿野苑平藏', '小鹿'], + 10000060: ['夜兰', 'Yelan', '夜阑', '叶澜', '腋兰', '夜天后'], + 10000063: ['申鹤', 'Shenhe', '神鹤', '小姨', '小姨子', '审鹤'], + 10000064: ['云堇', 'Yun Jin', 'yun jin', '云瑾', '云先生', '云锦', '神女劈观'], + 10000065: ['久岐忍', 'Kuki Shinobu', 'Kuki', 'Shinobu', '97忍', '小忍', '久歧忍', '97', '茄忍', '茄子', '紫茄子', '阿忍', '忍姐'], + 10000066: ['神里绫人', 'Kamisato Ayato', 'Ayato', '绫人', '神里凌人', '凌人', '0人', '神人', '零人', '大舅哥'], + + // 3.0 + 10000061: ['绮良良', 'Kirara', '大猫猫', '大喵喵', '稻妻猫猫', '绮娘娘', '琦良良', '良良', '快递员', '草猫', '草猫猫', '草喵', '草喵喵', '猫又'], + 10000069: ['提纳里', 'Tighnari', '提那里', '小提', '驴'], + 10000067: ['柯莱', 'Collei', '柯来', '科莱', '科来', '小天使', '须弥安柏', '草安柏', '须弥飞行冠军'], + 10000068: ['多莉', 'Dori', '多利', '多力', '奸商'], + 10000070: ['妮露', 'Nilou', '尼露', '妮璐', '舞娘', '红牛'], + 10000071: ['赛诺', 'Cyno', '塞诺', '胡狼', '大风纪官', '大风机关'], + 10000072: ['坎蒂丝', 'Candace', '坎迪斯'], + 10000073: ['纳西妲', 'Nahida', '草神', '小吉祥', '大吉祥', '小草神', '大慈树王', '小吉祥草王', '草萝莉', '羽毛球', '摩诃善法大吉祥智慧主', '智慧主', '智慧之神', '布耶尔'], + 10000074: ['莱依拉', 'Layla', '莱依菈', '来依菈', '来依拉'], + 10000075: ['流浪者', 'Wanderer', '散兵', '国崩', '雷电国崩', '大炮', '雷电大炮', '雷大炮', '伞兵', '斯卡拉姆齐'], + 10000076: ['珐露珊', 'Faruzan', '法露珊', '法璐珊', '法露姗', '法璐姗', '珐露姗', '珐璐姗', '百岁珊', '百岁山', '前辈', '仙贝'], + 10000077: ['瑶瑶', 'Yaoyao', '遥遥', '萝卜', '月桂'], + 10000078: ['艾尔海森', 'Alhaitham', '海哥', '埃尔海森', '海森', '海参', '书记官'], + 10000079: ['迪希雅', 'Dehya', '迪希亚', '迪希娅', '迪西雅', '迪西亚'], + 10000080: ['米卡', 'Mika', '鹦鹉', '凤头', '凤头鹦鹉'], + 10000081: ['卡维', 'Kaveh', '艾尔海森室友'], + 10000082: ['白术', 'Baizhu', '长生'], + + // 4.0 + 10000083: ['琳妮特', 'Lynette', '林妮特', '林尼特', '琳尼特', '女魔术师', '魔术猫', '魔术喵', '登登'], + 10000084: ['林尼', 'Lyney', '林妮', '琳尼', '琳妮', '男魔术师', '魔术师'], + 10000085: ['菲米尼', 'Freminet', '非米尼', '潜水员'], + 10000086: ['莱欧斯利', 'Wriothesley', '莱欧', '枫丹桑博', '欧拉欧拉', '来欧', '来欧斯利'], + 10000087: ['那维莱特', 'Neuvillette', '那维', '水龙王', '水龙', '审判官', '海獭'], + 10000088: ['夏洛蒂', 'Charlotte', '夏洛', '夏洛帝', '记者', '小记者'], + 10000089: ['芙宁娜', 'Furina', 'Focalors', '水神', '芙芙', '芙卡洛斯'], + + // 自定义角色 + paimon: ['派蒙', '应急食物', '应急食品', '吉祥物', '宠物', '外置器官', '会说话的动物', '矮堇瓜', '飞行矮堇瓜', '最好的伙伴'], + nvshi: ['女士', '炽热的炎之魔女', '炎之魔女', '罗莎琳'], + fanan: ['伐难', '水夜叉'], + yingda: ['应达', '火夜叉', '火鼠大将'], + guizhong: ['归终', '哈艮图斯', '哈根达斯', '尘之魔神', '尘神'], + ping: ['萍姥姥', '歌尘浪市真君', '歌尘浪市', '萍儿'], + puren: ['阿蕾奇诺', '仆人', '黑优菈', '黑暗优菈'], + shaonv: ['哥伦比娅', '少女'], + furen: ['潘塔罗涅', '富人', '黑白术', '黑术'], + boshi: ['多托雷', '博士'], + muou: ['桑多涅', '木偶', '人偶'], + choujue: ['皮耶罗', '丑角', '老爷子'], + gongji: ['普契涅拉', '公鸡', '鸽子'], + duizhang: ['卡皮塔诺', '队长'], + daiyin: ['戴因斯雷布', '戴因', '男派蒙', '大派蒙', '末光之剑', '拾枝者'], + tianli: ['天理', '天理维系者', '维系者'] +} + +export const wifeData = { + girlfriend: `琴, 丽莎, 荧, 芭芭拉, 安柏, 香菱, 北斗, 凝光, 菲谢尔, 诺艾尔, 甘雨, 莫娜, 刻晴, 砂糖, 辛焱, 罗莎莉亚, 胡桃, + 烟绯, 优菈, 神里绫华, 宵宫, 雷电将军, 珊瑚宫心海, 九条裟罗, 八重神子, 埃洛伊, 申鹤, 云堇, 夜兰, 久岐忍, 柯莱, 多莉, 伐难, + 女士, 萍姥姥, 归终, 仆人, 少女, 妮露, 坎蒂丝, 天理, 迪希雅, 莱依拉, 珐露珊, 绮良良`, + boyfriend: `空, 凯亚, 迪卢克, 雷泽, 温迪, 行秋, 魈, 钟离, 班尼特, 达达利亚, 重云, 阿贝多, 枫原万叶, 托马, 五郎, 荒泷一斗, + 鹿野院平藏, 神里绫人, 提纳里, 流浪者, 富人, 博士, 丑角, 公鸡, 队长, 赛诺, 戴因, 卡维, 艾尔海森, 米卡, 白术`, + daughter: '可莉, 七七, 迪奥娜, 早柚, 派蒙, 瑶瑶, 纳西妲', + son: '' +} + +export const isSys = true diff --git a/Yunzai/plugins/miao-plugin/config/system/help_system.js b/Yunzai/plugins/miao-plugin/config/system/help_system.js new file mode 100644 index 0000000000000000000000000000000000000000..9a63b4ffa4b2e5a687da00741ca5be492143772b --- /dev/null +++ b/Yunzai/plugins/miao-plugin/config/system/help_system.js @@ -0,0 +1,177 @@ +/* +* 此配置文件为系统使用,请勿修改,否则可能无法正常使用 +* +* 如需自定义配置请复制修改上一级help_default.js +* +* */ + +export const helpCfg = { + title: '喵喵帮助', + subTitle: 'Yunzai-Bot & Miao-Plugin', + columnCount: 3, + colWidth: 265, + theme: 'all', + themeExclude: ['default'], + style: { + fontColor: '#ceb78b', + descColor: '#eee', + contBgColor: 'rgba(6, 21, 31, .5)', + contBgBlur: 3, + headerBgColor: 'rgba(6, 21, 31, .4)', + rowBgColor1: 'rgba(6, 21, 31, .2)', + rowBgColor2: 'rgba(6, 21, 31, .35)' + } +} + +export const helpList = [{ + group: '游戏面板与信息查询', + list: [{ + icon: 61, + title: '#角色 #角色卡片 #探索', + desc: '你的原神角色数据,数据来自米游社' + }, { + icon: 63, + title: '#面板 #更新面板', + desc: '查看已经获取面板信息的角色列表' + }, { + icon: 66, + title: '#雷神面板 #雷神伤害', + desc: '查看角色详细面板及伤害信息' + }, { + icon: 65, + title: '#圣遗物列表 #雷神圣遗物', + desc: '查看圣遗物列表 / 评分详情' + }, { + icon: 79, + title: '#面板帮助', + desc: '面板替换及其他帮助信息' + }, { + icon: 64, + title: '#深渊 #深渊12层', + desc: '深渊数据,打完请2小时后查询' + }, { + icon: 67, + title: '#五星 #武器 #今日素材', + desc: '你的原神角色详情数据' + }, { + icon: 62, + title: '#五星列表 #练度统计', + desc: '角色列表数据' + }, { + icon: 77, + title: '#上传深渊数据', + desc: '上传您的深渊数据用于数据统计' + }] +}, { + group: '资料及图片', + list: [{ + icon: 58, + title: '#刻晴 #心海', + desc: '你的原神角色卡片' + }, { + icon: 59, + title: '#老婆 #老公', + desc: '查看老婆、老公' + }, { + icon: 60, + title: '#老婆设置心海,雷神', + desc: '设置老婆列表,也可设置随机' + }, { + icon: 88, + title: '#老婆照片 #甘雨照片', + desc: '查看指定角色的图片' + }, { + icon: 53, + title: '#夜兰天赋 #胡桃命座', + desc: '查看角色的天赋与命座资料' + }, { + icon: 56, + title: '#深渊配队', + desc: '根据你的角色池推荐组队' + }, { + icon: 78, + title: '#角色持有 #角色0命', + desc: '查看角色的持有率、0命统计' + }, { + icon: 77, + title: '#深渊使用率 #深渊出场率', + desc: '查看本期深渊使用或出场统计' + }, { + icon: 20, + title: '#刻晴攻略', + desc: '西风驿站攻略' + }, { + icon: 60, + title: '#心海图鉴 #护摩', + desc: '角色武器图鉴' + }] +}, { + group: '个人信息查询及签到', + desc: '需要绑定cookie', + list: [{ + icon: 15, + title: '#体力 #体力帮助', + desc: '查询体力,绑定Cookie帮助' + }, { + icon: 5, + title: '#原石 #原石统计', + desc: '札记数据,需要绑定Cookie' + }, { + icon: 10, + title: '#uid #绑定123456789', + desc: '查看绑定的uid 绑定uid' + }, { + icon: 22, + title: '#我的ck #删除ck', + desc: '查看绑定的cookie 删除cookie' + }, { + icon: 86, + title: '#签到', + desc: '米游社原神签到' + }] +}, { + group: '其他查询指令', + list: [{ + icon: 83, + title: '#日历 #日历列表', + desc: '查看活动日历' + }, { + icon: 6, + title: '#抽卡记录 #记录帮助', + desc: '统计游戏抽卡数据' + }, { + icon: 21, + title: '#角色统计 #武器统计', + desc: '按卡池统计抽卡数据' + }, { + icon: 8, + title: '十连 十连2 定轨', + desc: '真实模拟抽卡' + }, { + icon: 74, + title: '添加哈哈 删除哈哈', + desc: '添加表情,回复哈哈触发' + }, { + icon: 79, + title: '#帮助 #版本 #喵喵版本', + desc: '其他命令' + }] +}, { + group: '管理命令,仅管理员可用', + auth: 'master', + list: [{ + icon: 85, + title: '#用户统计', + desc: '查看用户CK-UID列表' + }, { + icon: 32, + title: '#喵喵设置', + desc: '配置喵喵功能' + }, { + icon: 35, + title: '#喵喵更新图像', + desc: '更新喵喵的增量角色图像素材' + }] +}] + +export const isSys = true diff --git a/Yunzai/plugins/miao-plugin/config/system/profile_system.js b/Yunzai/plugins/miao-plugin/config/system/profile_system.js new file mode 100644 index 0000000000000000000000000000000000000000..867a5901364b10e0c70638e721772c320c65ed84 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/config/system/profile_system.js @@ -0,0 +1,64 @@ +/* +* 此配置文件为系统使用,请勿修改,否则可能无法正常使用 +* 如需自定义配置请复制修改上一级profile_default.js +* */ + +export const miaoApi = { + listApi: ({ url, uid, diyCfg, game = 'gs' }) => { + let qq = /\d{5,12}/.test(diyCfg.qq) ? diyCfg.qq : 'none' + let token = diyCfg.token + url = url || 'http://miao.games/' + return `${url}profile/data?uid=${uid}&qq=${qq}&token=${token}&version=2&game=${game}` + } +} + +export const enkaApi = { + url: 'https://enka.network/', + userAgent: 'Miao-Plugin/3.1', + listApi: ({ url, uid, diyCfg }) => { + return `${url}api/uid/${uid}/` + } +} + +export const mggApi = { + url: 'http://profile.microgg.cn/', + userAgent: 'Miao-Plugin/3.1', + listApi: ({ url, uid, diyCfg }) => { + return `${url}api/uid/${uid}/` + } +} + +export const hutaoApi = { + url: 'http://enka-api.hut.ao/', + userAgent: 'Snap Hutao/miao', + listApi: ({ url, uid, diyCfg }) => { + return `${url}/${uid}/` + } +} + +export const homoApi = { + url: 'https://api.mihomo.me/sr_info', + // userAgent: 'Miao-Plugin/3.1', + listApi: ({ url, uid, diyCfg }) => { + return `${url}/${uid}` + } +} + +export const avocadoApi = { + url: 'https://avocado.wiki/v1/raw/info', + userAgent: 'Miao-Plugin/3.1', + listApi: ({ url, uid, diyCfg }) => { + return `${url}/${uid}` + } +} + +export const enkaHSRApi = { + url: 'https://enka.network/', + userAgent: 'Miao-Plugin/3.1', + listApi: ({ url, uid, diyCfg }) => { + return `${url}api/hsr/uid/${uid}/` + } +} +export const requestInterval = 3 + +export const isSys = true diff --git "a/Yunzai/plugins/miao-plugin/config/system/\350\257\267\345\213\277\344\277\256\346\224\271\346\255\244\347\233\256\345\275\225\344\270\213\347\232\204\346\226\207\344\273\266.txt" "b/Yunzai/plugins/miao-plugin/config/system/\350\257\267\345\213\277\344\277\256\346\224\271\346\255\244\347\233\256\345\275\225\344\270\213\347\232\204\346\226\207\344\273\266.txt" new file mode 100644 index 0000000000000000000000000000000000000000..e67fd6eb9b23b9cd6761f1ef048d1e43dd04e2ec --- /dev/null +++ "b/Yunzai/plugins/miao-plugin/config/system/\350\257\267\345\213\277\344\277\256\346\224\271\346\255\244\347\233\256\345\275\225\344\270\213\347\232\204\346\226\207\344\273\266.txt" @@ -0,0 +1,3 @@ +此目录为系统配置目录 +请勿修改此目录下的文件,否则可能导致工作不正常 +如需配置,可配置上级目录,复制对应_default.js 文件进行配置 \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/index.js b/Yunzai/plugins/miao-plugin/index.js new file mode 100644 index 0000000000000000000000000000000000000000..585b9ef666fb1423620e505fe455038f66c40f3e --- /dev/null +++ b/Yunzai/plugins/miao-plugin/index.js @@ -0,0 +1,44 @@ +import { Data, Version } from '#miao' +import fs from 'fs' + +if (!global.segment) { + global.segment = (await import('oicq')).segment +} + +export * from './apps/index.js' + +if (Bot?.logger?.info) { + Bot.logger.info('---------^_^---------') + Bot.logger.info(`喵喵插件${Version.version}初始化~`) +} else { + console.log(`喵喵插件${Version.version}初始化~`) +} + +setTimeout(async function () { + let msgStr = await redis.get('miao:restart-msg') + let relpyPrivate = async function () { + } + let common = await Data.importModule('lib/common/common.js', 'root') + if (common && common.default && common.default.relpyPrivate) { + relpyPrivate = common.default.relpyPrivate + } + if (msgStr) { + let msg = JSON.parse(msgStr) + await relpyPrivate(msg.qq, msg.msg) + await redis.del('miao:restart-msg') + let msgs = [`当前喵喵版本: ${Version.version}`, '您可使用 #喵喵版本 命令查看更新信息'] + await relpyPrivate(msg.qq, msgs.join('\n')) + } + if (!Version.isV3) { + console.log('警告:miao-plugin需要V3 Yunzai,请升级至最新版Miao-Yunzai以使用miao-plugin') + } + if (!fs.existsSync(process.cwd() + '/lib/plugins/runtime.js')) { + let msg = '警告:未检测到runtime,miao-plugin可能无法正常工作。请升级至最新版Miao-Yunzai以使用miao-plugin' + if (!await redis.get('miao:runtime-warning')) { + await relpyPrivate(msg.qq, msg) + await redis.set('miao:runtime-warning', 'true', { EX: 3600 * 24 }) + } else { + console.log(msg) + } + } +}, 1000) diff --git a/Yunzai/plugins/miao-plugin/index.ts b/Yunzai/plugins/miao-plugin/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..2544e9ead8109fd966d2df092b1f3f485bc6c21b --- /dev/null +++ b/Yunzai/plugins/miao-plugin/index.ts @@ -0,0 +1,8 @@ +import { createApp, getAppName } from 'alemonjs' +const AppName = getAppName(import.meta.url) +const { apps } = await import('./apps/index.js').finally(() => { + console.log('[APP] 喵喵插件 启动') +}) +const app = createApp(AppName) +app.component(apps) +app.mount() \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/models/Abyss.js b/Yunzai/plugins/miao-plugin/models/Abyss.js new file mode 100644 index 0000000000000000000000000000000000000000..8e96731d2ab111a4451c5772f28132a92f384595 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/Abyss.js @@ -0,0 +1,100 @@ +/* +* Mys深渊数据处理 +* */ + +import lodash from 'lodash' +import moment from 'moment' +import Base from '../models/Base.js' +import { Data } from '#miao' + +moment.locale('zh-cn') + +export default class Abyss extends Base { + constructor (data) { + super() + this.floors = {} + let floors = this.floors + lodash.forEach(data.floors, (floor) => { + let levels = {} + let floorData = { + star: floor.star, + index: floor.index, + levels + } + lodash.forEach(floor.levels, (level) => { + let ds = { + star: level.star + } + levels[level.index] = ds + + lodash.forEach(level.battles, (battle) => { + let key = battle.index === 1 ? 'up' : 'down' + let tmp = {} + tmp.timestamp = battle.timestamp + let time = moment(new Date(battle.timestamp * 1000)) + tmp.time = time.format('MM-DD HH:mm:ss') + let avatars = [] + lodash.forEach(battle.avatars, (avatar) => { + avatars.push(avatar.id) + }) + tmp.avatars = avatars + ds[key] = tmp + }) + }) + floorData.display = levels['3'] || levels['2'] || levels['1'] + floors[floor.index] = floorData + }) + let keys = 'id:avatar_id,value' + this.reveral = lodash.map(data.reveal_rank, (ds) => Data.getData(ds, keys)) + let stat = {} + this.stat = stat + lodash.forEach({ + defeat: 'defeat_rank', + dmg: 'damage_rank', + takeDmg: 'take_damage_rank', + e: 'normal_skill_rank', + q: 'energy_skill_rank' + }, (key, dst) => { + stat[dst] = Data.getData(data[key] ? data[key][0] : [], keys) + }) + let st = moment(new Date(data.start_time * 1000)) + this.schedule = st.format('M') + '月' + (st.format('D') * 1 > 1 ? '下半' : '上半') + this.maxFloor = data.max_floor + this.total = data.total_battle_times + this.time = moment().format('MM-DD HH:mm:ss') + } + + getData (floor) { + return Data.getData(this, 'reveral,stat,floors,time,schedule,maxFloor,total') + } + + getAvatars () { + let ret = {} + lodash.forEach(this.reveral, (ds) => { + if (ds.id) { + ret[ds.id] = true + } + }) + lodash.forEach(this.stat, (ds) => { + if (ds.id) { + ret[ds.id] = true + } + }) + lodash.forEach(this.floors, (floor) => { + let levels = floor?.levels || {} + lodash.forEach(levels, (level) => { + lodash.forEach(level.up?.avatars || [], (id) => { + if (id) { + ret[id] = true + } + }) + lodash.forEach(level.down?.avatars || [], (id) => { + if (id) { + ret[id] = true + } + }) + }) + }) + return lodash.keys(ret) + } +} diff --git a/Yunzai/plugins/miao-plugin/models/Artifact.js b/Yunzai/plugins/miao-plugin/models/Artifact.js new file mode 100644 index 0000000000000000000000000000000000000000..e7a4a6cc5e33d000ddeaa4ce59f55b76f9379fb1 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/Artifact.js @@ -0,0 +1,167 @@ +/* +* 圣遗物 +* */ +import Base from './Base.js' +import { Format } from '#miao' +import { ArtifactSet } from './index.js' +import { artiMap, attrMap, mainIdMap, attrIdMap } from '../resources/meta/artifact/index.js' +import { idMap as idMapSR, artiMap as artiMapSR, metaData as metaDataSR, abbr as abbrSR } from '../resources/meta-sr/artifact/index.js' +import lodash from 'lodash' + +class Artifact extends Base { + static getAttrs + + constructor (name, game = 'gs') { + super() + let cache = this._getCache(`arti:${game}:${name}`) + if (cache) { + return cache + } + this.game = game + let data = (this.isGs ? artiMap : artiMapSR)[name] + if (!data) { + return false + } + this.id = data.id || '' + this.name = data.name + this.meta = data + return this._cache() + } + + get artiSet () { + return ArtifactSet.get(this.set, this.game) + } + + get setName () { + return this.set + } + + get abbr () { + return (abbrSR && abbrSR[this.name]) || this.name + } + + get img () { + return this.isGs ? `meta/artifact/imgs/${this.setName}/${this.idx}.webp` : `meta-sr/artifact/${this.setName}/arti-${this.idx}.webp` + } + + static get (name, game = 'gs') { + if (!name) { + return false + } + if (game === 'sr') { + name = idMapSR[name]?.name || name + } + if ((game === 'gs' ? artiMap : artiMapSR)[name]) { + return new Artifact(name, game) + } + return false + } + + static getSetNameByArti (name) { + let arti = Artifact.get(name) + if (arti) { + return arti.setName + } + return '' + } + + static getMeta () { + return { + attrMap + } + } + + static getMainById (id, level = 20, star = 5) { + let key = mainIdMap[id] + if (!key) { + return false + } + let attrCfg = attrMap[Format.isElem(key) ? 'dmg' : key] + let posEff = ['hpPlus', 'atkPlus', 'defPlus'].includes(key) ? 2 : 1 + let starEff = { 1: 0.21, 2: 0.36, 3: 0.6, 4: 0.9, 5: 1 } + return { + key, + value: attrCfg.value * (1.2 + 0.34 * level) * posEff * (starEff[star || 5]) + } + } + + static getAttrsByIds (ids, star = 5) { + let ret = [] + let tmp = {} + lodash.forEach(ids, (id) => { + let cfg = attrIdMap[id] + if (!cfg) { + return true + } + let { key, value } = cfg + if (!tmp[key]) { + tmp[key] = { + key, + upNum: 0, + eff: 0, + value: 0 + } + ret.push(tmp[key]) + } + tmp[key].value += value * (attrMap[key].format === 'pct' ? 100 : 1) + tmp[key].upNum++ + tmp[key].eff += value / attrMap[key].value * (attrMap[key].format === 'pct' ? 100 : 1) + }) + return ret + } + + getStarById (id) { + return this.meta.ids[id] || '' + } + + getIdByStar (star = 5) { + let ids = this.meta.ids || {} + for (let key in ids) { + if (ids[key] * 1 === star) { + return key + } + } + } + + getAttrData (mainId, attrData, level = 1, star = 5, idx = 1) { + let mainKey = metaDataSR.mainIdx[idx][mainId] + let starCfg = metaDataSR.starData[star] + let mainCfg = starCfg.main[mainKey] + if (!mainId || !mainCfg) { + return false + } + let main = { + id: mainId, + key: mainKey, + value: mainCfg.base + mainCfg.step * level + } + let attrs = [] + lodash.forEach(attrData, (ds) => { + let _ds = ds + if (lodash.isString(ds)) { + let [id, count, step] = ds.split(',') + ds = { id, count, step } + } + let attrCfg = starCfg.sub[ds.id] + if (!attrCfg) { + console.log('not found attr', ds, _ds) + return true + } + let value = attrCfg?.base * ds.count + attrCfg.step * ds.step + attrs.push({ + ...ds, + key: attrCfg?.key, + upNum: ds.count, + eff: value / (attrCfg.base + attrCfg.step * 2), + value + }) + }) + return { + main, + attrs + } + } + +} + +export default Artifact diff --git a/Yunzai/plugins/miao-plugin/models/ArtifactSet.js b/Yunzai/plugins/miao-plugin/models/ArtifactSet.js new file mode 100644 index 0000000000000000000000000000000000000000..836c27d47ce51529f7efbda72f3e23294ecbe273 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/ArtifactSet.js @@ -0,0 +1,96 @@ +/* +* 圣遗物套装 +* */ +import lodash from 'lodash' +import Base from './Base.js' +import { abbr, aliasMap, artiMap, artiSetMap, calc as artisBuffs } from '../resources/meta/artifact/index.js' +import { + abbr as abbrSR, + aliasMap as aliasMapSR, + artiMap as artiMapSR, + artisBuffs as artisBuffsSR, + artiSetMap as artiSetMapSR +} from '../resources/meta-sr/artifact/index.js' + +import { Artifact } from './index.js' + +class ArtifactSet extends Base { + constructor (name, game = 'gs') { + super() + let cache = this._getCache(`arti-set:${game}:${name}`) + if (cache) { + return cache + } + let data = (game === 'gs' ? artiSetMap : artiSetMapSR)[name] + if (!data) { + if (artiSetMapSR[name]) { + data = artiSetMapSR[name] + game = 'sr' + } else { + return false + } + } + this.game = game + this.meta = data + return this._cache() + } + + get img () { + let arti = Artifact.get(this.sets[1] || this.sets[5], this.game) + return arti ? arti.img : '' + } + + get abbr () { + return this.game === 'gs' ? (abbr[this.name] || this.name) : (abbrSR[this.name] || this.name) + } + + static getByArti (name) { + if (artiMap[name]) { + return ArtifactSet.get(artiMap[name].set) + } + if (artiMapSR[name]) { + return ArtifactSet.get(artiMap[name].set, 'sr') + } + return false + } + + static get (name) { + if (artiSetMap[name]) { + return new ArtifactSet(name, 'gs') + } + if (artiSetMapSR[name]) { + return new ArtifactSet(name, 'sr') + } + return false + } + + static getArtiNameBySet (set, idx = 1) { + let artiSet = ArtifactSet.get(set) + if (artiSet) { + return artiSet.getArtiName(idx) + } + return '' + } + + static getArtisSetBuff (name, num, game = 'gs') { + let artiBuffsMap = game === 'sr' ? artisBuffsSR : artisBuffs + let ret = (artiBuffsMap[name] && artiBuffsMap[name][num]) || artiBuffsMap[name + num] + if (!ret) return false + if (lodash.isPlainObject(ret)) return [ret] + return ret + } + + getArtiName (idx = 1) { + return this.sets[idx] + } + + getArti (idx = 1) { + return Artifact.get(this.getArtiName(idx), this.game) + } + + static getAliasMap (game = 'gs') { + return game === 'gs' ? aliasMap : aliasMapSR + } +} + +export default ArtifactSet diff --git a/Yunzai/plugins/miao-plugin/models/AvatarArtis.js b/Yunzai/plugins/miao-plugin/models/AvatarArtis.js new file mode 100644 index 0000000000000000000000000000000000000000..38c75aeeebbc62c025817abb270b7774b2a2e89f --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/AvatarArtis.js @@ -0,0 +1,313 @@ +/** + * 面板圣遗物 + */ +import lodash from 'lodash' +import Base from './Base.js' +import { Artifact, ArtifactSet } from './index.js' +import { Format, Data } from '#miao' +import ArtisMark from './profile/ArtisMark.js' + +export default class AvatarArtis extends Base { + constructor (charid = 0, game = 'gs') { + super() + this.game = game + this.charid = charid + this.artis = {} + } + + get sets () { + return this.getSetData().sets || {} + } + + get names () { + return this.getSetData().names || [] + } + + get hasArtis () { + return !lodash.isEmpty(this.artis) + } + + get hasAttr () { + if (this.isSr) { + return true + } + return ArtisMark.hasAttr(this.artis) + } + + static _eachArtisSet (sets, fn, game = 'gs') { + lodash.forEach(sets || [], (v, k) => { + let artisSet = ArtifactSet.get(k, game) + if (artisSet) { + if (v >= 4) { + fn(artisSet, 2) + } + fn(artisSet, v) + } + }) + } + + static getArtisKeyTitle (game = 'gs') { + return ArtisMark.getKeyTitleMap(game) + } + + setArtisData (ds = {}, isProfile = false) { + if (!isProfile || (isProfile && ArtisMark.hasAttr(ds))) { + for (let idx = 1; idx <= (this.isGs ? 5 : 6); idx++) { + if (ds[idx] || ds[`arti${idx}`]) { + this.setArtis(idx, ds[idx] || ds[`arti${idx}`], isProfile) + } + } + } + } + + setArtis (idx = 1, ds = {}, isProfile = false) { + idx = idx.toString().replace('arti', '') + this.artis[idx] = this.artis[idx] || {} + let arti = this.artis[idx] + let artiObj + if (this.isSr) { + artiObj = Artifact.get(ds.id, this.game) + if (!artiObj) { + return false + } + arti.id = artiObj.id || ds.id || arti.id || '' + arti.name = artiObj.name || arti.name || '' + arti.set = artiObj.setName || arti.set || '' + arti.level = ds.level || arti.level || 1 + arti.star = artiObj.getStarById(ds.id) || arti.star || 5 + let attrIds = ds.attrIds || ds.attrs + if (ds.mainId && attrIds) { + let attr = artiObj.getAttrData(ds.mainId, attrIds, arti.level, arti.star, idx) + if (attr) { + arti.mainId = ds.mainId + arti.attrIds = attrIds + arti.main = attr.main || arti.main || {} + arti.attrs = attr.attrs || arti.attrs || {} + } else { + console.log('attr id error', ds.main, ds.mainId, idx, arti.level, arti.star) + } + } else { + arti.attrs = [] + } + return + } else { + if (isProfile) { + arti.name = ds._name || ds.name || arti.name || '' + arti.set = ds._set || Artifact.getSetNameByArti(arti._name) || ds.set || '' + arti.level = ds._level || ds.level || 1 + arti.star = ds._star || ds.star || 5 + arti.main = ds.main + arti.attrs = ds.attrs + } else { + arti.name = ds.name || arti.name || '' + arti.set = ds.set || Artifact.getSetNameByArti(arti.name) || '' + arti.level = ds.level || 1 + arti.star = ds.star || 5 + } + if (ds.mainId || ds.main) { + arti._name = ds._name || ds.name || arti._name || arti.name + arti._set = ds._set || Artifact.getSetNameByArti(arti._name) || arti._set || '' + arti._level = ds._level || ds.level || arti._level || arti.level + arti._star = ds._star || ds.star || arti._star || arti.star || 5 + } + } + + // 存在面板数据,更新面板数据 + if (ds.mainId && ds.attrIds) { + arti.mainId = ds.mainId + arti.attrIds = ds.attrIds + arti.main = Artifact.getMainById(ds.mainId, arti._level, arti._star) + arti.attrs = Artifact.getAttrsByIds(ds.attrIds, arti._star) + } else if (ds.main && ds.attrs) { + arti.main = ArtisMark.formatAttr(ds.main || {}) + arti.attrs = [] + for (let attrIdx in ds.attrs || []) { + if (ds.attrs[attrIdx]) { + arti.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx])) + } + } + } + } + + forEach (fn) { + lodash.forEach(this.artis, (ds, idx) => { + if (ds.name) { + fn(ds, idx) + } + }) + } + + _get (key) { + let artis = this.artis + switch (key) { + case 'length': + return lodash.keys(artis).length + } + if (artis[key]) { + return artis[key] + } + } + + toJSON () { + let ret = {} + for (let idx = 1; idx <= (this.isGs ? 5 : 6); idx++) { + let ds = this.artis[idx] + if (!ds) { + continue + } + let tmp = { + level: ds.level || 1, + star: ds.star || 5 + } + + if (this.isSr) { + tmp.id = ds.id + tmp.mainId = ds.main?.id + tmp.attrIds = [] + lodash.forEach(ds.attrs, (as) => { + tmp.attrIds.push([ + as?.id || '', + as?.count || 1, + as?.step || 0 + ].join(',')) + }) + } else { + tmp.name = ds.name || '' + if ((ds.mainId && ds.attrIds) || (ds.main && ds.attrs)) { + if ((ds._name && ds._name !== ds.name) || (ds._level && ds._level !== ds.level) || (ds._star && ds._star !== ds.star)) { + tmp._name = ds._name || null + tmp._level = ds._level || null + tmp._star = ds._star || null + } + } + if (ds.mainId && ds.attrIds) { + tmp.mainId = ds.mainId || null + tmp.attrIds = ds.attrIds + } else if (ds.main && ds.attrs) { + tmp.main = ds.main || null + tmp.attrs = [] + for (let attrIdx in ds.attrs || []) { + if (ds.attrs[attrIdx]) { + tmp.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx])) + } + } + } + } + ret[idx] = tmp + } + return ret + } + + getDetail (profile = false) { + let ret = {} + for (let idx = 1; idx <= 5; idx++) { + let ds = this.artis[idx] + if (ds) { + let artis = Artifact.get(profile ? ds._name : ds.name) + let tmp = { + ...artis?.getData('img,name,set'), + level: (profile ? ds._level : ds.level) || 1 + } + if (ds.main && ds.attrs) { + tmp.main = ds.main || null + tmp.attrs = [] + for (let attrIdx in ds.attrs || []) { + if (ds.attrs[attrIdx]) { + tmp.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx])) + } + } + } + ret[idx] = tmp + } + } + return ret + } + + mainAttr (idx = '') { + if (!idx) { + let ret = {} + for (let i = 1; i <= 5; i++) { + ret[i] = this.mainAttr(i) + } + return ret + } + let main = this.artis[idx]?.main + if (!main) { + return '' + } + return main.key || '' + } + + is (check, pos = '') { + if (pos) { + return this.isAttr(check, pos) + } + let sets = this.getSetData()?.abbrs || [] + let ret = false + Data.eachStr(check, (s) => { + if (sets.includes(s)) { + ret = true + return false + } + }) + return ret + } + + isAttr (attr, pos = '3,4,5') { + let mainAttr = this.mainAttr() + let check = true + Data.eachStr(pos.toString(), (p) => { + let attrs = attr.split(',') + if (!attrs.includes(mainAttr[p]) && (p === '4' && !attrs.includes('dmg') && Format.isElem(mainAttr[p]))) { + check = false + return false + } + }) + return check + } + + /** + * 获取圣遗物套装数据 + * @returns {*|{imgs: *[], names: *[], sets: {}, abbrs: *[], sName: string, name: (string|*)}} + * sets: 套装名:2/4 + * names: [套装名] + * imgs: [img] + * abbrs:[别名] + * name: '组合名字', 若为4件套会使用套装完整名 + * sName: '简写名字',若为4件套也会使用简写 + */ + getSetData (profile = false) { + let setCount = {} + this.forEach((arti, idx) => { + setCount[profile ? arti._set : arti.set] = (setCount[profile ? arti._set : arti.set] || 0) + 1 + }) + let sets = {} + let names = [] + let imgs = [] + let abbrs = [] + let abbrs2 = [] + for (let set in setCount) { + if (setCount[set] >= 2) { + let count = setCount[set] >= 4 ? 4 : 2 + sets[set] = count + let artiSet = ArtifactSet.get(set) + names.push(artiSet.name) + imgs.push(artiSet.img) + abbrs.push(artiSet.abbr + count) + abbrs2.push(artiSet.name + count) + } + } + return { + sets, + names, + imgs, + abbrs: [...abbrs, ...abbrs2], + name: (abbrs.length > 1 || abbrs2[0]?.length > 7) ? abbrs.slice(0, 2).join('+') : abbrs2[0], + sName: abbrs.slice(0, 2).join('+') + } + } + + eachArtisSet (fn) { + AvatarArtis._eachArtisSet(this.sets, fn, this.game) + } +} diff --git a/Yunzai/plugins/miao-plugin/models/AvatarData.js b/Yunzai/plugins/miao-plugin/models/AvatarData.js new file mode 100644 index 0000000000000000000000000000000000000000..db10d780c3791cbc90ef02cab2fe87ea0afb24a3 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/AvatarData.js @@ -0,0 +1,280 @@ +import lodash from 'lodash' +import Base from './Base.js' +import moment from 'moment' +import { Character, AvatarArtis, ProfileData, Weapon } from './index.js' +import { Data, Format } from '#miao' +import AttrCalc from './profile/AttrCalc.js' +import Profile from './player/Profile.js' + +const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName'.split(',') + +export default class AvatarData extends Base { + constructor (ds = {}, game = 'gs') { + super() + let char = Character.get({ id: ds.id, elem: ds.elem }) + if (!char) { + return + } + this.id = char.id + this.char = char + this.game = char.game || game + this.initArtis() + this.setAvatar(ds) + } + + get hasTalent () { + return this.talent && !lodash.isEmpty(this.talent) && !!this._talent + } + + get name () { + return this.char?.name || '' + } + + get hasData () { + return !!(this.level > 1 || this?.weapon?.name || this?.talent?.a) + } + + // 是否是合法面板数据 + get isProfile () { + return Profile.isProfile(this) + } + + get costume () { + let costume = this._costume + if (lodash.isArray(costume)) { + costume = costume[0] + } + return costume + } + + get originalTalent () { + return lodash.mapValues(this.talent, (ds) => ds.original) + } + + /** + * 获取圣遗物套装属性 + * @returns {boolean|*|{imgs: *[], names: *[], sets: {}, abbrs: *[], sName: string, name: (string|*)}|{}} + */ + get artisSet () { + return this.artis.getSetData() + } + + get dataSource () { + return { + enka: 'Enka.Network', + miao: '喵喵Api', + mgg: 'MiniGG-Api', + hutao: 'Hutao-Enka', + mys: '米游社', + homo: 'Mihomo' + }[this._source] || this._source + } + + get updateTime () { + let time = this._time + if (!time) { + return '' + } + if (lodash.isString(time)) { + return moment(time).format('MM-DD HH:mm') + } + if (lodash.isNumber(time)) { + return moment(new Date(time)).format('MM-DD HH:mm') + } + return '' + } + + static create (ds, game = 'gs') { + let avatar = new AvatarData(ds, game) + if (!avatar) { + return false + } + return avatar + } + + initArtis () { + this.artis = new AvatarArtis(this.id, this.game) + } + + _get (key) { + if (charKey.includes(key)) { + return this.char[key] + } + } + + setAvatar (ds, source = '') { + this._now = new Date() * 1 + this.setBasic(ds, source) + ds.weapon && this.setWeapon(ds.weapon) + ds.talent && this.setTalent(ds.talent, 'original', source) + ds.artis && this.setArtis(ds) + delete this._now + } + + /** + * 设置角色基础数据 + * @param ds + * @param source + */ + setBasic (ds = {}, source = '') { + const now = this._now || (new Date()) * 1 + this.level = ds.lv || ds.level || this.level || 1 + this.cons = ds.cons || this.cons || 0 + this.fetter = ds.fetter || this.fetter || 0 + this._costume = ds.costume || this._costume || 0 + this.elem = ds.elem || this.elem || this.char.elem || '' + this.promote = lodash.isUndefined(ds.promote) ? (this.promote || AttrCalc.calcPromote(this.level)) : (ds.promote || 0) + this.trees = this.trees || [] + this._source = ds._source || this._source || '' + this._time = ds._time || this._time || now + this._update = ds._update || this._update || ds._time || now + this._talent = ds._talent || this._talent || ds._time || now + + if (ds.trees) { + this.setTrees(ds.trees) + } + + // 存在数据源时更新时间 + if (source) { + this._update = now + if (source !== 'mys') { + this._source = source + this._time = now + } else { + this._source = this._source || source + this._time = this._source !== 'mys' ? (this._time || now) : now + } + } + } + + setTrees (ds) { + this.trees = [] + let prefix = '' + let map = {} + lodash.forEach(this.char?.detail?.tree || {}, (ds, key) => { + let ret = /(\d{4})(\d{3})/.exec(key) + if (ret && ret[1] && ret[2]) { + prefix = prefix || ret[1] + map[ret[2]] = key + } + }) + if (prefix) { + for (let i = 0; i <= 3; i++) { + map[`10${i}`] = `${prefix}10${i}` + } + } + lodash.forEach(ds, (id) => { + let ret = /\d{4}(\d{3})/.exec(id) + this.trees.push(map[ret?.[1] || id] || id) + }) + } + + setWeapon (ds = {}) { + let w = Weapon.get(ds.name || ds.id, this.game) + if (!w) { + return false + } + this.weapon = { + id: ds.id || w.id, + name: ds.name || w.name, + level: ds.level || ds.lv || 1, + promote: lodash.isUndefined(ds.promote) ? AttrCalc.calcPromote(ds.level || ds.lv || 1) : (ds.promote || 0), + affix: ds.affix, + ...w.getData('star,abbr,type,img') + } + if (this.weapon.level < 20) { + this.weapon.promote = 0 + } + } + + getWeaponDetail () { + let ret = { + ...this.weapon + } + if (!ret.id) { + return {} + } + let wData = Weapon.get(ret.id, this.game) + ret.splash = wData.imgs.gacha + let wAttr = wData.calcAttr(ret.level, ret.promote) + let attrs = {} + if (this.isSr) { + lodash.forEach(wAttr, (val, key) => { + attrs[key] = Format.comma(val, 1) + }) + } else if (this.isGs) { + attrs.atkBase = Format.comma(wAttr.atkBase, 1) + if (wAttr?.attr?.key) { + let keyType = { + mastery: 'comma' + } + attrs[wAttr.attr.key] = Format[keyType[wAttr.attr.key] || 'pct'](wAttr.attr.value, 1) + } + } + ret.attrs = attrs + ret.desc = wData.getAffixDesc(ret.affix) + return ret + } + + setTalent (ds = false, mode = 'original', updateTime = '') { + const now = this._now || (new Date()) * 1 + if (ds) { + let ret = this.char.getAvatarTalent(ds, this.cons, mode) + if (ret) { + this.talent = ret || this.talent + // 设置天赋更新时间 + this._talent = ds._talent || this._talent || ds._time || now + } + } + if (updateTime) { + this._talent = now + } + } + + setArtis (ds, source) { + this.artis.setArtisData(ds.artis, source) + } + + getProfile () { + if (!this.isProfile) { + return false + } + return ProfileData.create(this, this.game) + } + + // 判断当前profileData是否具备有效圣遗物信息 + hasArtis () { + return this.isProfile && this.artis.length > 0 + } + + // toJSON 供保存使用 + toJSON () { + let keys = this.isGs ? + 'name,id,elem,level,promote,fetter,costume,cons,talent:originalTalent' : + 'name,id,elem,level,promote,cons,talent:originalTalent,trees' + return { + ...this.getData(keys), + weapon: Data.getData(this.weapon, this.isGs ? 'name,level,promote,affix' : 'id,level,promote,affix'), + ...this.getData('artis,_source,_time,_update,_talent') + } + } + + getDetail (keys = '') { + let imgs = this.char.getImgs(this.costume) + if (this.isGs) { + return { + ...(this.getData(keys || 'id,name,level,star,cons,fetter,elem,abbr,weapon,talent,artisSet') || {}), + ...Data.getData(imgs, 'face,qFace,side,gacha') + } + } else { + return { + ...(this.getData(keys || 'id,name,level,star,cons,elem,abbr,weapon,talent,artisSet,trees') || {}), + ...Data.getData(imgs, 'face,qFace,gacha,preview') + } + } + } + + getArtisDetail () { + return this.artis.getDetail() + } +} diff --git a/Yunzai/plugins/miao-plugin/models/Base.js b/Yunzai/plugins/miao-plugin/models/Base.js new file mode 100644 index 0000000000000000000000000000000000000000..5630aaa91221fb909c2a433b832b93dcb5c09d93 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/Base.js @@ -0,0 +1,104 @@ +/* +* Base Model +* +* 使用Proxy实现meta数据的getter +* 对Character等可复用设置实例缓存,提高性能 +* */ +import { Data } from '#miao' + +let cacheMap = {} +let reFn = {} +let metaMap = {} + +export default class Base { + constructor () { + this.game = 'gs' + let proxy = new Proxy(this, { + get (self, key, receiver) { + if (self._uuid && key === 'meta') { + return metaMap[self._uuid] + } + if (key in self) { + return Reflect.get(self, key, receiver) + } + if (self._get) { + return self._get.call(receiver, key) + } + if (self._uuid) { + return (metaMap[self._uuid] || {})[key] + } else { + return (self.meta || {})[key] + } + }, + set (target, key, newValue) { + if (target._uuid && key === 'meta') { + metaMap[target._uuid] = newValue + return true + } else { + return Reflect.set(target, key, newValue) + } + } + }) + return proxy + } + + getData (arrList = '', cfg = {}) { + arrList = arrList || this._dataKey || '' + return Data.getData(this, arrList, cfg) + } + + // 获取指定值数据,支持通过 + getVal (key, defaultValue) { + return Data.getVal(this, key, defaultValue) + } + + // 获取缓存 + _getCache (uuid = '', time = 10 * 60) { + if (uuid && cacheMap[uuid]) { + return cacheMap[uuid]._expire(time) + } + this._uuid = uuid + } + + // 设置缓存 + _cache (time = 10 * 60) { + let id = this._uuid + if (id) { + this._expire(time) + cacheMap[id] = this + return cacheMap[id] + } + return this + } + + // 设置超时时间 + _expire (time = 10 * 60) { + let id = this._uuid + let self = this + reFn[id] && clearTimeout(reFn[id]) + if (time > 0) { + if (id) { + reFn[id] = setTimeout(() => { + self._delCache() + }, time * 1000) + } + return cacheMap[id] + } + } + + _delCache () { + let id = this._uuid + reFn[id] && clearTimeout(reFn[id]) + delete reFn[id] + delete cacheMap[id] + delete metaMap[id] + } + + get isSr () { + return this.game === 'sr' + } + + get isGs () { + return !this.isSr + } +} diff --git a/Yunzai/plugins/miao-plugin/models/Character.js b/Yunzai/plugins/miao-plugin/models/Character.js new file mode 100644 index 0000000000000000000000000000000000000000..fa771e6a26bd0a853a49a9093c080d78f859a4d2 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/Character.js @@ -0,0 +1,359 @@ +/* +* 角色数据 +* +* 支持角色查询及Meta元数据获取 +* 兼容处理自定义角色 +* */ +import lodash from 'lodash' +import Base from './Base.js' +import { Data, Format, Cfg } from '#miao' +import CharImg from './character/CharImg.js' +import CharTalent from './character/CharTalent.js' +import CharId from './character/CharId.js' +import CharMeta from './character/CharMeta.js' +import CharCfg from './character/CharCfg.js' + +let { wifeMap, idSort, idMap } = CharId + +let getMeta = function (name, game = 'gs') { + if (game === 'gs') { + return Data.readJSON(`resources/meta/character/${name}/data.json`, 'miao') + } else { + return CharId.getSrMeta(name) + } +} + +class Character extends Base { + // 默认获取的数据 + _dataKey = 'id,name,abbr,title,star,elem,allegiance,weapon,birthday,astro,cncv,jpcv,ver,desc,talentCons' + + constructor ({ id, name = '', elem = '', game = 'gs' }) { + super() + // 检查缓存 + let cacheObj = this._getCache(CharId.isTraveler(id) ? `character:${id}:${elem || 'anemo'}` : `character:${id}`) + if (cacheObj) { + return cacheObj + } + // 设置数据 + this._id = id + this.name = name + this.game = game + if (!this.isCustom) { + let meta = getMeta(name, game) + this.meta = meta + if (this.isGs) { + this.elem = Format.elem(elem || meta.elem, 'anemo') + } + } else { + this.meta = {} + } + return this._cache() + } + + // 是否为官方角色 + get isOfficial () { + return this.game === 'sr' || /[12]0\d{6}/.test(this._id) + } + + // 是否为实装官方角色 + get isRelease () { + if (this.isCustom) { + return false + } + if (this.eta) { + return this.eta * 1 < new Date() * 1 + } + return true + } + + // 是否为自定义角色 + get isCustom () { + return !this.isOfficial + } + + get id () { + return this.isCustom ? this._id : this._id * 1 + } + + get isGs () { + return this.game === 'gs' + } + + get isSr () { + return this.game === 'sr' + } + + // 获取短名字 + get sName () { + let name = this.name + let abbr = this.abbr + return name.length <= 4 ? name : (abbr || name) + } + + // 是否是旅行者 + get isTraveler () { + return this.isGs && CharId.isTraveler(this.id) + } + + get weaponType () { + return this.weapon + } + + // 获取武器类型 + get weaponTypeName () { + if (this.isSr) { + return this.weapon + } + const map = { + sword: '单手剑', + catalyst: '法器', + bow: '弓', + claymore: '双手剑', + polearm: '长柄武器' + } + let weaponType = this.weaponType || '' + return map[weaponType.toLowerCase()] || '' + } + + // 获取元素名称 + get elemName () { + if (this.isSr) { + return this.elem + } + return Format.elemName(this.elem) + } + + // 获取角色描述 + get desc () { + return CharMeta.getDesc(this.meta.desc || '') + } + + // 获取头像 + get face () { + return this.getImgs().face + } + + // 获取侧脸图像 + get side () { + if (this.isSr) { + return this.getImgs().face + } + return this.getImgs().side + } + + // gacha图像 + get gacha () { + return this.getImgs().gacha + } + + // 获取character相关图像 + get imgs () { + return this.getImgs() + } + + // 获取详情数据 + get detail () { + return this.getDetail() + } + + // 获取命座天赋等级 + get talentCons () { + if (this.isSr) { + return this.meta?.talentCons || {} + } + if (this.isTraveler) { + return this.elem === 'dendro' ? { e: 3, q: 5 } : { e: 5, q: 3 } + } + return this.meta?.talentCons || {} + } + + // 获取生日 + get birthday () { + let birth = this.birth + if (!birth) { + return '' + } + birth = birth.split('-') + return `${birth[0]}月${birth[1]}日` + } + + // 基于角色名获取Character + static get (val, game = 'gs') { + let id = CharId.getId(val, Character.gsCfg, game) + if (!id) { + return false + } + return new Character(id) + } + + static forEach (fn, type = 'all', game = 'gs') { + lodash.forEach(idMap, (name, id) => { + let char = Character.get({ id, name }) + if (char.game !== 'gs') { + return true + } + if (type === 'release' && !char.isRelease) { + return true + } + if (type === 'official' && !char.isOfficial) { + return true + } + return fn(char) !== false + }) + } + + // 获取排序ID + static sortIds (arr) { + return arr.sort((a, b) => (idSort[a] || 300) - (idSort[b] || 300)) + } + + // 获取attr列表 + getAttrList () { + let { meta } = this + return CharMeta.getAttrList(meta.baseAttr, meta.growAttr, this.elemName) + } + + // 获取素材 + getMaterials (type = 'all') { + return CharMeta.getMaterials(this, type) + } + + // 获取角色character-img图片 + getCardImg (se = false, def = true) { + if (this.name === '旅行者') { + return CharImg.getCardImg(['空', '荧'], se, def) + } + return CharImg.getCardImg(this.name, se, def) + } + + // 设置天赋数据 + getAvatarTalent (talent = {}, cons = 0, mode = 'original') { + return CharTalent.getAvatarTalent(this, talent, cons, mode) + } + + getTalentKey (id) { + if (this.talentId[id]) { + return this.talentId[id] + } + if (this.isSr) { + id = (id + '').replace(this.id, '') + return { + '001': 'a', + '002': 'e', + '003': 'q', + '004': 't', + '007': 'z' + }[id] + } + return false + } + + // 检查老婆类型 + checkWifeType (type) { + return !!wifeMap[type][this.id] + } + + // 检查时装 + checkCostume (id) { + let costume = this.meta?.costume || [] + return costume.includes(id * 1) + } + + // 判断是否为某种元素角色 + isElem (elem = '') { + elem = elem.toLowerCase() + return this.elem === elem || this.elemName === elem + } + + // 获取角色插画 + getImgs (costume = '') { + if (lodash.isArray(costume)) { + costume = costume[0] + } + let costumeIdx = this.checkCostume(costume) ? '2' : '' + let cacheId = `costume${costumeIdx}` + if (!this._imgs) { + this._imgs = {} + } + if (!this._imgs[cacheId]) { + if (this.isSr) { + this._imgs[cacheId] = CharImg.getImgsSr(this.name, this.talentCons) + } else { + this._imgs[cacheId] = CharImg.getImgs(this.name, costumeIdx, this.isTraveler ? this.elem : '', this.weaponType, this.talentCons) + } + } + let imgs = this._imgs[cacheId] + return { + ...imgs, + qFace: Cfg.get('qFace') ? (imgs.qFace || imgs.face) : imgs.face + } + } + + // 基于角色名获取Character + + // 获取详情数据 + getDetail (elem = '') { + if (this._detail) { + return this._detail + } + if (this.isCustom) { + return {} + } + const path = this.isSr ? 'resources/meta-sr/character' : 'resources/meta/character' + const file = this.isSr ? 'data' : 'detail' + + try { + if (this.isTraveler) { + this._detail = Data.readJSON(`${path}/旅行者/${this.elem}/${file}.json`, 'miao') + } else { + this._detail = Data.readJSON(`${path}/${this.name}/${file}.json`, 'miao') + } + } catch (e) { + console.log(e) + } + return this._detail + } + + // 获取伤害计算配置 + getCalcRule () { + if (!this._calcRule && this._calcRule !== false) { + this._calcRule = CharCfg.getCalcRule(this) + } + return this._calcRule + } + + getArtisCfg () { + if (!this._artisRule && this._artisRule !== false) { + this._artisRule = CharCfg.getArtisCfg(this) + } + return this._artisRule + } + + /** + * 获取等级属性 + * @param level + * @param promote + * @returns {{}|boolean} + */ + getLvAttr (level, promote) { + let metaAttr = this.detail?.attr + if (!metaAttr) { + return false + } + if (this.isSr) { + let lvAttr = metaAttr[promote] + let ret = {} + lodash.forEach(lvAttr.attrs, (v, k) => { + ret[k] = v * 1 + }) + lodash.forEach(lvAttr.grow, (v, k) => { + ret[k] = ret[k] * 1 + v * (level - 1) + }) + return ret + } + } +} + +Character.CharId = CharId + +export default Character diff --git a/Yunzai/plugins/miao-plugin/models/Material.js b/Yunzai/plugins/miao-plugin/models/Material.js new file mode 100644 index 0000000000000000000000000000000000000000..689fccf138d32f12d355aecc58eedf11ac7d3b13 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/Material.js @@ -0,0 +1,112 @@ +/* +* 角色培养及天赋材料 +* */ +import lodash from 'lodash' +import Base from './Base.js' +import { Data } from '#miao' +import MaterialMeta from './material/MaterialMeta.js' + +let data = Data.readJSON('resources/meta/material/data.json','miao') +let abbr = await Data.importDefault('resources/meta/material/abbr.js', 'miao') +let mMap = {} +let getItem = (ds) => { + mMap[ds.name] = { + type: ds.type, + name: ds.name, + star: ds.star + } + return mMap[ds.name] +} +lodash.forEach(data, (ds) => { + let ret = getItem(ds) + if (ds.items) { + let items = {} + lodash.forEach(ds.items, (item) => { + getItem(item) + items[item.star] = item.title + }) + ret.items = items + } +}) + +class Material extends Base { + constructor (name) { + super(name) + let meta = mMap[name] + if (!meta) { + return false + } + let cache = this._getCache(`material:${name}`) + if (cache) { + return cache + } + this.name = meta.name + this.meta = meta + this.type = meta.type + this.star = meta.star + if (this.type === 'talent') { + let talentData = MaterialMeta.getTalentData(this.name) + lodash.extend(this, talentData) + } + return this._cache() + } + + get abbr () { + let name = this.name + if (this.type === 'talent') { + return Data.regRet(/「(.+)」/, name, 1) || name + } + return abbr[name] || name + } + + get title () { + return this.name + } + + get label () { + let abbr = this.abbr + if (this.type === 'talent') { + return MaterialMeta.getTalentLabel(abbr) + } + return abbr + } + + get img () { + return `meta/material/${this.type}/${this.name}.webp` + } + + get icon () { + return this.img + } + + getSource () { + if (this.type === 'talent') { + return MaterialMeta.getTalentWeek(this.name) + } + return '' + } + + static get (name) { + if (mMap[name]) { + return new Material(name) + } + return false + } + + static forEach (type = 'all', fn, filter = false) { + if (!lodash.isFunction(filter)) { + filter = () => true + } + lodash.forEach(mMap, (ds, name) => { + if (type !== 'all' && type !== ds.type) { + return true + } + let obj = new Material(name) + if (filter(obj)) { + return fn(obj) !== false + } + }) + } +} + +export default Material diff --git a/Yunzai/plugins/miao-plugin/models/MysApi.js b/Yunzai/plugins/miao-plugin/models/MysApi.js new file mode 100644 index 0000000000000000000000000000000000000000..4b2f32aeef9df77a13c43db940f44e5d005eef35 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/MysApi.js @@ -0,0 +1,158 @@ +import { User } from './index.js' +import { Version } from '#miao' + +export default class MysApi { + constructor (e, uid, mysInfo) { + this.e = e + this.mysInfo = mysInfo + this.ckInfo = mysInfo.ckInfo + this.ckUser = mysInfo.ckUser + this.uid = uid + e.targetUser = this.targetUser + e.selfUser = this.selfUser + e.isSelfCookie = this.isSelfCookie + } + + get isSelfCookie () { + return this.uid * 1 === this.ckUid * 1 || this?.mysInfo?.isSelf + } + + get ckUid () { + return this.ckInfo.uid + } + + get ck () { + return this.ckInfo.ck + } + + get selfUser () { + return new User({ id: this.e.user_id, uid: this.uid }) + } + + get targetUser () { + return new User({ id: this.e.user_id, uid: this.uid }) + } + + static async init (e, auth = 'all') { + if (!e.runtime) { + Version.runtime() + return false + } + let mys = await e.runtime.getMysInfo(auth) + if (!mys) { + return false + } + let uid = mys.uid + e._mys = new MysApi(e, uid, mys) + return e._mys + } + + static async initUser (e, auth = 'all') { + let { runtime } = e + if (!runtime) { + Version.runtime() + return false + } + let uid + if (runtime.getUid) { + uid = await runtime.getUid() + } else { + // 兼容处理老版本Yunzai + uid = runtime.uid || e.uid + if (e.at) { + // 暂时使用MysApi.init替代 + let mys = await MysApi.init(e, auth) + if (!mys) { + return false + } + uid = mys.uid || uid + } + } + if (uid) { + return new User({ id: e.user_id, uid }) + } else { + e.reply('请先发送【#绑定+你的UID】来绑定查询目标') + e._replyNeedUid = true + return false + } + } + + async getMysApi (e, targetType = 'all', option = {}) { + if (this.mys) { + return this.mys + } + this.mys = await e.runtime.getMysApi(targetType, option) + return this.mys + } + + async getData (api, data) { + if (!this.mysInfo) { + return false + } + let e = this.e + let mys = await this.getMysApi(e, api, { log: false }) + if (!mys) { + return false + } + let mysInfo = this.mysInfo || {} + // 暂时先在plugin侧阻止错误,防止刷屏 + e._original_reply = e._original_reply || e.reply + e._reqCount = e._reqCount || 0 + e.reply = function (msg) { + if (!e._isReplyed) { + e._isReplyed = true + return e._original_reply(msg) + } else { + // console.log('请求错误') + } + } + e._reqCount++ + let ret = await mys.getData(api, data) + if (mysInfo && mysInfo.checkCode) { + ret = await mysInfo.checkCode(ret, api, this.mys) + } + e._reqCount-- + if (e._reqCount === 0) { + e.reply = e._original_reply + } + if (!ret) { + return false + } + if (ret.retcode !== 0) { + e._retcode = ret.retcode + } + return ret.data || ret + } + + // 获取角色信息 + async getCharacter () { + return await this.getData('character') + } + + // 获取角色详情 + async getAvatar (id) { + return await this.getData('detail', { avatar_id: id }) + } + + // 首页宝箱信息 + async getIndex () { + return await this.getData('index') + } + + // 获取深渊信息 + async getSpiralAbyss (type = 1) { + return await this.getData('spiralAbyss', { schedule_type: type }) + } + + async getDetail (id) { + return await this.getData('detail', { avatar_id: id }) + } + + async getCompute (data) { + return await this.getData('compute', data) + } + + async getAvatarSkill (id) { + return await this.getData('avatarSkill', { avatar_id: id }) + } +} diff --git a/Yunzai/plugins/miao-plugin/models/Player.js b/Yunzai/plugins/miao-plugin/models/Player.js new file mode 100644 index 0000000000000000000000000000000000000000..7be44e7cfa131a2874620c3009482cda96c14a6a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/Player.js @@ -0,0 +1,363 @@ +/** + * 用户数据文件 + * 数据存储在/data/UserData/${uid}.json 下 + * 兼容处理面板户数及Mys数据 + * + */ +import lodash from 'lodash' +import Base from './Base.js' +import { Data } from '#miao' +import { AvatarData, ProfileRank, Character } from './index.js' + +import MysAvatar from './player/MysAvatar.js' +import Profile from './player/Profile.js' + +Data.createDir('/data/UserData', 'root') +Data.createDir('/data/PlayerData/gs', 'root') +Data.createDir('/data/PlayerData/sr', 'root') + +export default class Player extends Base { + constructor (uid, game = 'gs') { + super() + uid = uid?._mys?.uid || uid?.uid || uid + if (!uid) { + return false + } + let cacheObj = this._getCache(`player:${game}:${uid}`) + if (cacheObj) { + return cacheObj + } + this.uid = uid + this.game = game + this.reload() + return this._cache(100) + } + + get hasProfile () { + let ret = false + lodash.forEach(this._avatars, (avatar) => { + if (avatar.isProfile) { + ret = true + return false + } + }) + return ret + } + + get _file () { + if (this.isSr) { + return `/data/PlayerData/sr/${this.uid}.json` + } else { + return `/data/UserData/${this.uid}.json` + } + } + + get faceImgs () { + let char + if (this.isGs && this.face) { + char = Character.get(this.face) + } + if (!char) { + let charId = lodash.keys(this._avatars)[0] + if (charId) { + char = Character.get(charId) + } + } + let imgs = char?.imgs || {} + return { + face: imgs.face || '/common/item/face.webp', + banner: imgs.banner || `/meta${this.isSr ? '-sr' : ''}/character/common/imgs/banner.webp` + } + } + + static create (e, game = 'gs') { + if (e?._mys?.uid || e.uid) { + // 传入为e + let player = new Player(e?._mys?.uid || e.uid, (game === 'sr' || e.isSr) ? 'sr' : 'gs') + player.e = e + return player + } else { + return new Player(e, game) + } + } + + // 获取面板更新服务名 + static getProfileServName (uid, game = 'gs') { + let Serv = Profile.getServ(uid, game) + return Serv.name + } + + static delByUid (uid, game = 'gs') { + let player = Player.create(uid, game) + if (player) { + player.del() + } + } + + /** + * 重新加载json文件 + */ + reload () { + let data + data = Data.readJSON(this._file, 'root') + this.setBasicData(data) + if (data.chars) { + this.setAvatars(data.chars) + } + this.setAvatars(data.avatars || []) + if (data._ck) { + this._ck = data._ck + } + if (!data.avatars) { + this.save() + } + } + + /** + * 保存json文件 + * @param flag false时暂时禁用保存,true时启用保存,并保存数据 + * @returns {boolean} + */ + save (flag = null) { + if (flag === true) { + this._save = true + } else if (flag === false || this._save === false) { + this._save = false + return false + } + let ret = Data.getData(this, 'uid,name,level,word,face,card,sign,info,_info,_mys,_profile') + ret.avatars = {} + this.forEachAvatar((avatar) => { + ret.avatars[avatar.id] = avatar.toJSON() + }) + if (this._ck) { + ret._ck = this._ck + } + if (this.isSr) { + Data.writeJSON(`/data/PlayerData/sr/${this.uid}.json`, ret, 'root') + } else { + Data.writeJSON(`/data/UserData/${this.uid}.json`, ret, 'root') + } + } + + del () { + try { + Data.delFile(this._file, 'root') + ProfileRank.delUidInfo(this.uid, this.game) + this._delCache() + Bot.logger.mark(`【面板数据删除】${this.uid}本地文件数据已删除...`) + } catch (e) { + console.log('del error', e) + } + return true + } + + /** + * 设置玩家基础数据 + * @param ds + */ + setBasicData (ds) { + this.name = ds.name || this.name || '' + this.level = ds.level || this.level || '' + this.word = ds.word || this.word || '' + this.face = ds.face || this.face || '' + this.card = ds.card || this.card || '' + this.sign = ds.sign || this.sign || '' + this.info = ds.info || this.info || false + this._avatars = this._avatars || {} + this._profile = ds._profile || this._profile + this._mys = ds._mys || this._mys + this._info = ds._info || this._info + } + + // 设置角色列表 + setAvatars (ds) { + lodash.forEach(ds, (avatar) => { + this.setAvatar(avatar) + }) + } + + // 设置角色数据 + setAvatar (ds, source = '') { + let avatar = this.getAvatar(ds.id, true) + avatar.setAvatar(ds, source) + } + + // 获取Avatar角色 + getAvatar (id, create = false) { + let char = Character.get(id) + let avatars = this._avatars + if (this.isGs) { + // 兼容处理旅行者的情况 + if (char.isTraveler && !create) { + id = avatars['10000005'] ? 10000005 : 10000007 + } + } + if (!avatars[id] && create) { + avatars[id] = AvatarData.create({ id }, this.game) + } + return avatars[id] || false + } + + // 异步循环角色 + async forEachAvatarAsync (fn) { + for (let id in this._avatars) { + let ret = await fn(this._avatars[id], id) + if (ret === false) { + return false + } + } + } + + // 循环Avatar + forEachAvatar (fn) { + for (let id in this._avatars) { + let avatar = this._avatars[id] + if (avatar && avatar.hasData) { + let ret = fn(this._avatars[id]) + if (ret === false) { + return false + } + } + } + } + + // 获取所有Avatar数据 + getAvatarData (ids = '') { + let ret = {} + if (!ids) { + this.forEachAvatar((avatar) => { + ret[avatar.id] = avatar.getDetail() + }) + } else { + lodash.forEach(ids, (id) => { + let avatar = this.getAvatar(id) + if (avatar) { + ret[id] = avatar.getDetail() + } + }) + } + return ret + } + + // 获取指定角色的面板数据 + getProfile (id) { + let avatar = this.getAvatar(id) + return avatar ? avatar.getProfile() : false + } + + // 获取所有面板数据 + getProfiles () { + let ret = {} + lodash.forEach(this._avatars, (avatar) => { + let profile = avatar.getProfile() + if (profile) { + ret[profile.id] = profile + } + }) + return ret + } + + getUpdateTime () { + let ret = {} + if (this._profile) { + ret.profile = MysAvatar.getDate(this._profile) + } + if (this._mys) { + ret.mys = MysAvatar.getDate(this._mys) + } + return ret + } + + getInfo () { + return MysAvatar.getInfo(this) + } + + // 更新面板 + async refreshProfile (force = 2) { + return await Profile.refreshProfile(this, force) + } + + // 更新米游社数据 + /** + * 更新米游社数据 + * @param force: 0:不强制,长超时时间 1:短超时时间 2:无视缓存,强制刷新 + * @returns {Promise} + */ + async refreshMysDetail (force = 0) { + return MysAvatar.refreshMysDetail(this, force) + } + + async refreshMysInfo (force = 0) { + return await MysAvatar.refreshMysInfo(this, force) + } + + // 通过已有的Mys CharData更新 + setMysCharData (charData) { + MysAvatar.setMysCharData(this, charData) + } + + // 使用MysApi刷新指定角色的天赋信息 + async refreshTalent (ids = '', force = 0) { + return await MysAvatar.refreshTalent(this, ids, force) + } + + async refresh (cfg) { + this.save(false) + try { + if (cfg.index || cfg.index === 0) { + await this.refreshMysInfo(cfg.index) + } + if (cfg.detail || cfg.detail === 0) { + await this.refreshMysDetail(cfg.detail) + } + if (cfg.talent || cfg.talent === 0) { + await this.refreshTalent(cfg.ids, cfg.talent) + } + if (cfg.profile || cfg.profile === 0) { + await this.refreshProfile(cfg.profile) + } + } catch (e) { + Bot.logger.mark(`刷新uid${this.uid}数据遇到错误...`) + console.log(e) + } + this.save(true) + } + + async refreshAndGetAvatarData (cfg) { + await this.refresh(cfg) + + let rank = false + let e = this.e + if (cfg.rank === true && e && e.group_id) { + rank = await ProfileRank.create({ group: e.group_id, uid: this.uid, qq: e.user_id }) + } + + let avatarRet = {} + this.forEachAvatar((avatar) => { + let { talent } = avatar + let ds = avatar.getDetail() + ds.aeq = talent?.a?.original + talent?.e?.original + talent?.q?.original || 3 + avatarRet[ds.id] = ds + + let profile = avatar.getProfile() + if (profile) { + let mark = profile.getArtisMark(false) + ds.artisMark = Data.getData(mark, 'mark,markClass,names') + if (rank) { + rank.getRank(profile) + } + } + }) + if (cfg.retType !== 'array') { + return avatarRet + } + avatarRet = lodash.values(avatarRet) + if (cfg.sort) { + let sortKey = 'level,star,aeq,cons,weapon.level,weapon.star,weapon.affix,fetter'.split(',') + avatarRet = lodash.orderBy(avatarRet, sortKey) + avatarRet = avatarRet.reverse() + } + return avatarRet + } +} diff --git a/Yunzai/plugins/miao-plugin/models/ProfileArtis.js b/Yunzai/plugins/miao-plugin/models/ProfileArtis.js new file mode 100644 index 0000000000000000000000000000000000000000..659783968487720097973df9947a215b52e8072e --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/ProfileArtis.js @@ -0,0 +1,134 @@ +/** + * 面板圣遗物 + */ +import lodash from 'lodash' +import AvatarArtis from './AvatarArtis.js' +import { Artifact, ArtifactSet, Character } from './index.js' +import { Format } from '../components/index.js' +import ArtisMark from './profile/ArtisMark.js' +import { attrMap as attrMapGS } from '../resources/meta/artifact/index.js' +import { attrMap as attrMapSR } from '../resources/meta-sr/artifact/index.js' +import CharArtis from './profile/CharArtis.js' + +export default class ProfileArtis extends AvatarArtis { + constructor (charid = 0, elem = '', game = 'gs') { + super(charid, game) + this.elem = elem + } + + setProfile (profile, artis) { + this.profile = profile + this.elem = profile.elem || profile.char?.elem + if (artis) { + this.setArtisData(artis, true) + } + } + + /** + * 获取角色配置 + * @returns {{classTitle: *, weight: *, posMaxMark: {}, mark: {}, attrs: {}}} + */ + getCharCfg () { + let char = Character.get(this.charid) + let { game, isGs } = char + let { attrWeight, title } = CharArtis.getCharArtisCfg(char, this.profile, this) + let attrs = {} + let baseAttr = char.baseAttr || { hp: 14000, atk: 230, def: 700 } + let attrMap = isGs ? attrMapGS : attrMapSR + lodash.forEach(attrMap, (attr, key) => { + let k = attr.base || '' + let weight = attrWeight[k || key] + if (!weight || weight * 1 === 0) { + return true + } + let ret = { + ...attr, + weight, + fixWeight: weight, + mark: weight / attr.value + } + if (!k) { + ret.mark = weight / attr.value + } else { + let plus = k === 'atk' ? 520 : 0 + ret.mark = weight / attrMap[k].value / (baseAttr[k] + plus) * 100 + ret.fixWeight = weight * attr.value / attrMap[k].value / (baseAttr[k] + plus) * 100 + } + attrs[key] = ret + }) + let posMaxMark = ArtisMark.getMaxMark(attrs, game) + // 返回内容待梳理简化 + return { + attrs, + classTitle: title, + posMaxMark + } + } + + getMarkDetail (withDetail = true) { + let charCfg = this.getCharCfg() + let artis = {} + let setCount = {} + let totalMark = 0 + let self = this + this.forEach((arti, idx) => { + let mark = ArtisMark.getMark({ + charCfg, + idx, + arti, + elem: this.elem, + game: self.game + }) + totalMark += mark + setCount[arti.set] = (setCount[arti.set] || 0) + 1 + if (!withDetail) { + artis[idx] = { + _mark: mark, + mark: Format.comma(mark, 1), + markClass: ArtisMark.getMarkClass(mark) + } + } else { + let artifact = Artifact.get(arti.name, this.game) + artis[idx] = { + name: artifact.name, + abbr: artifact.abbr, + set: artifact.setName, + img: artifact.img, + level: arti.level, + _mark: mark, + mark: Format.comma(mark, 1), + markClass: ArtisMark.getMarkClass(mark), + main: ArtisMark.formatArti(arti.main, charCfg.attrs, true, this.game), + attrs: ArtisMark.formatArti(arti.attrs, charCfg.attrs, false, this.game) + } + } + }) + let sets = {} + let names = [] + let imgs = [] + for (let set in setCount) { + if (setCount[set] >= 2) { + sets[set] = setCount[set] >= 4 ? 4 : 2 + let artiSet = ArtifactSet.get(set) + imgs.push(artiSet.img) + names.push(artiSet.name) + } + } + this.mark = totalMark + this.markClass = ArtisMark.getMarkClass(totalMark / 5) + let ret = { + mark: Format.comma(totalMark, 1), + _mark: totalMark, + markClass: ArtisMark.getMarkClass(totalMark / 5), + artis, + sets, + names, + imgs, + classTitle: charCfg.classTitle + } + if (withDetail) { + ret.charWeight = lodash.mapValues(charCfg.attrs, ds => ds.weight) + } + return ret + } +} diff --git a/Yunzai/plugins/miao-plugin/models/ProfileAttr.js b/Yunzai/plugins/miao-plugin/models/ProfileAttr.js new file mode 100644 index 0000000000000000000000000000000000000000..75d57b779a95cf6235973ddadabf9dc148bc590b --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/ProfileAttr.js @@ -0,0 +1,150 @@ +import lodash from 'lodash' +import Base from './Base.js' +import { Format } from '#miao' + +const baseAttr = { + gs: 'atk,def,hp,mastery,recharge,cpct,cdmg,dmg,phy,heal,shield'.split(','), + sr: 'atk,def,hp,speed,recharge,cpct,cdmg,dmg,heal,stance,effPct,effDef'.split(',') +} +let attrReg = { + gs: new RegExp(`^(${baseAttr.gs.join('|')})(Base|Plus|Pct|Inc)$`), + sr: new RegExp(`^(${baseAttr.sr.join('|')})(Base|Plus|Pct|Inc)$`) +} + +class ProfileAttr extends Base { + constructor (char, data = null) { + super() + this.char = char + this.game = char.game + this.init(data, this.game) + } + + static create (char, data = null) { + return new ProfileAttr(char, data) + } + + init (data) { + // 基础属性 + this._attr = {} + this._base = {} + let attr = this._attr + let base = this._base + lodash.forEach(baseAttr[this.game], (key) => { + attr[key] = { + base: 0, + plus: 0, + pct: 0 + } + base[key] = 0 + }) + + if (data) { + this.setAttr(data, true) + } + } + + /** + * getter + * + * @param key + * @returns {*|number} + * @private + */ + _get (key) { + let attr = this._attr + if (baseAttr[this.game].includes(key)) { + let a = attr[key] + return a.base * (1 + a.pct / 100) + a.plus + } + + let testRet = attrReg[this.game].exec(key) + if (testRet && testRet[1] && testRet[2]) { + let key = testRet[1] + let key2 = testRet[2].toLowerCase() + return attr[key][key2] || 0 + } + } + + /** + * 添加或追加Attr数据 + * @param key + * @param val + * @param isBase + * @returns {boolean} + */ + addAttr (key, val, isBase = false) { + let attr = this._attr + let base = this._base + + if (this.isSr && Format.isElem(key, this.game)) { + if (Format.sameElem(this.char.elem, key, this.game)) { + key = 'dmg' + } + } + + if (baseAttr[this.game].includes(key)) { + attr[key].plus += val * 1 + if (isBase) { + base[key] = (base[key] || 0) + val * 1 + } + return true + } + + let testRet = attrReg[this.game].exec(key) + if (testRet && testRet[1] && testRet[2]) { + let key = testRet[1] + let key2 = testRet[2].toLowerCase() + attr[key][key2] = attr[key][key2] || 0 + attr[key][key2] += val * 1 + if (key2 === 'base' || isBase) { + base[key] = (base[key] || 0) + val * 1 + } + return true + } + return false + } + + /** + * 设置属性 + * @param data + * @param withBase:带有base数据的初始化设置,会将atk/hp/def视作结果数据而非plus数据 + */ + setAttr (data, withBase = false) { + if (withBase) { + lodash.forEach(['hp', 'def', 'atk'], (key) => { + let base = `${key}Base` + if (data[key] && data[base]) { + data[`${key}Plus`] = data[key] - data[base] + delete data[key] + } + }) + } + lodash.forEach(data, (val, key) => { + if (this.isSr && Format.isElem(key, this.game)) { + if (this.char.elem === Format.elem(key, '', this.game)) { + this.addAttr('dmg', val) + } + } else { + this.addAttr(key, val) + } + }) + } + + getAttr () { + let ret = {} + lodash.forEach(baseAttr[this.game], (key) => { + ret[key] = this[key] + if (['hp', 'atk', 'def', 'speed'].includes(key)) { + ret[`${key}Base`] = this[`${key}Base`] + } + }) + ret._calc = true + return ret + } + + getBase () { + return this._base + } +} + +export default ProfileAttr diff --git a/Yunzai/plugins/miao-plugin/models/ProfileData.js b/Yunzai/plugins/miao-plugin/models/ProfileData.js new file mode 100644 index 0000000000000000000000000000000000000000..5a5175a2f9b7087aef33435c1e42910d069413d3 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/ProfileData.js @@ -0,0 +1,106 @@ +import lodash from 'lodash' +import AvatarData from './AvatarData.js' +import { Data, Cfg } from '#miao' +import { ProfileArtis, ProfileDmg } from './index.js' +import AttrCalc from './profile/AttrCalc.js' +import CharImg from './character/CharImg.js' + +export default class ProfileData extends AvatarData { + constructor (ds = {}, game = 'gs', calc = true) { + super(ds, game) + if (calc) { + this.calcAttr() + } + } + + // 判断当前profileData是否具有有效数据 + get hasData () { + return this.isProfile + } + + get imgs () { + return this.char.getImgs(this.costume) || {} + } + + get costumeSplash () { + let costume = this._costume + costume = this.char.checkCostume(costume) ? '2' : '' + + if (!Cfg.get('costumeSplash', true)) { + return this.char.getImgs(this._costume).splash + } + + let nPath = `meta/character/${this.name}` + let isSuper = false + let talent = this.talent ? lodash.map(this.talent, (ds) => ds.original).join('') : '' + if (this.cons === 6 || ['ACE', 'ACE²'].includes(this.artis?.markClass) || talent === '101010') { + isSuper = true + } + if (isSuper) { + return CharImg.getRandomImg( + [`profile/super-character/${this.name}`, `profile/normal-character/${this.name}`], + [`${nPath}/imgs/splash0.webp`, `${nPath}/imgs/splash${costume}.webp`, `/${nPath}/imgs/splash.webp`] + ) + } else { + return CharImg.getRandomImg( + [`profile/normal-character/${this.name}`], + [`${nPath}/imgs/splash${costume}.webp`, `/${nPath}/imgs/splash.webp`] + ) + } + } + + get hasDmg () { + return this.hasData && !!ProfileDmg.dmgRulePath(this.name, this.game) + } + + static create (ds, game = 'gs') { + let profile = new ProfileData(ds, game) + if (!profile) { + return false + } + return profile + } + + initArtis () { + this.artis = new ProfileArtis(this.id, this.elem, this.game) + } + + setAttr (ds) { + this.attr = lodash.extend(Data.getData(ds, 'atk,atkBase,def,defBase,hp,hpBase,mastery,recharge'), { + heal: ds.heal || ds.hInc || 0, + cpct: ds.cpct || ds.cRate, + cdmg: ds.cdmg || ds.cDmg, + dmg: ds.dmg || ds.dmgBonus || 0, + phy: ds.phy || ds.phyBonus || 0 + }) + } + + calcAttr () { + this._attr = AttrCalc.create(this) + this.attr = this._attr.calc() + this.base = this._attr.getBase() + } + + setArtis (ds = false) { + this.artis?.setProfile(this, ds.artis?.artis || ds.artis || ds) + } + + // 获取当前profileData的圣遗物评分,withDetail=false仅返回简略信息 + getArtisMark (withDetail = true) { + if (this.hasData) { + return this.artis.getMarkDetail(withDetail) + } + return {} + } + + // 计算当前profileData的伤害信息 + async calcDmg ({ enemyLv = 91, mode = 'profile', dmgIdx = 0, idxIsInput = false }) { + if (!this.dmg) { + let ds = this.getData('id,level,attr,cons,artis:artis.sets,trees') + ds.talent = lodash.mapValues(this.talent, 'level') + ds.weapon = Data.getData(this.weapon, 'name,affix') + this.dmg = new ProfileDmg(ds, this.game) + } + return await this.dmg.calcData({ enemyLv, mode, dmgIdx, idxIsInput }) + } +} diff --git a/Yunzai/plugins/miao-plugin/models/ProfileDmg.js b/Yunzai/plugins/miao-plugin/models/ProfileDmg.js new file mode 100644 index 0000000000000000000000000000000000000000..626433b0eddbcf1d21abd5fb67e07e6a141045fd --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/ProfileDmg.js @@ -0,0 +1,275 @@ +import fs from 'fs' +import lodash from 'lodash' +import Base from './Base.js' +import { Character } from './index.js' +import { attrMap as attrMapGS } from '../resources/meta/artifact/index.js' +import { attrMap as attrMapSR } from '../resources/meta-sr/artifact/index.js' +import DmgBuffs from './profile/DmgBuffs.js' +import DmgAttr from './profile/DmgAttr.js' +import DmgCalc from './profile/DmgCalc.js' +import { Common, MiaoError } from '#miao' + +export default class ProfileDmg extends Base { + constructor (profile = {}, game = 'gs') { + super() + this.profile = profile + this.game = game + if (profile && profile.id) { + let { id } = profile + this.char = Character.get(id) + } + } + + static dmgRulePath (name, game = 'gs') { + const _path = process.cwd() + const meta = game === 'sr' ? 'meta-sr' : 'meta' + let path = `${_path}/plugins/miao-plugin/resources/${meta}/character/${name}/calc_user.js` + if (fs.existsSync(path)) { + return path + } + path = `${_path}/plugins/miao-plugin/resources/${meta}/character/${name}/calc_auto.js` + if (fs.existsSync(path) && Common.cfg('teamCalc')) { + return path + } + path = `${_path}/plugins/miao-plugin/resources/${meta}/character/${name}/calc.js` + if (fs.existsSync(path)) { + return path + } + return false + } + + // 获取天赋数据 + talent () { + let char = this.char + let profile = this.profile + let ret = {} + let talentData = profile.talent || {} + let detail = char.detail + let { isSr, isGs } = this + lodash.forEach((isSr ? 'a,a2,e,e2,q,t' : 'a,e,q').split(','), (key) => { + let level = lodash.isNumber(talentData[key]) ? talentData[key] : (talentData[key]?.level || 1) + if (key === 'a2' || key === 'e2') { + let tmpKey = key === 'a2' ? 'a' : 'e' + level = lodash.isNumber(talentData[tmpKey]) ? talentData[tmpKey] : (talentData[tmpKey]?.level || 1) + } + let map = {} + if (isGs && detail.talentData) { + lodash.forEach(detail.talentData[key], (ds, key) => { + map[key] = ds[level - 1] + }) + } else if (isSr && detail.talent && detail.talent[key]) { + lodash.forEach(detail.talent[key].tables, (ds) => { + map[ds.name] = ds.values[level - 1] + }) + } + ret[key] = map + }) + return ret + } + + trees () { + let ret = {} + let reg = /\d{4}(\d{3})/ + lodash.forEach(this.profile.trees, (t) => { + let regRet = reg.exec(t) + if (regRet && regRet[1]) { + ret[regRet[1]] = true + } + }) + return ret + } + + // 获取buff列表 + getBuffs (buffs) { + return DmgBuffs.getBuffs(this.profile, buffs, this.game) + } + + async getCalcRule () { + const cfgPath = ProfileDmg.dmgRulePath(this.char?.name, this.char?.game) + let cfg = {} + if (cfgPath) { + cfg = await import(`file://${cfgPath}`) + return { + details: cfg.details || false, // 计算详情 + buffs: cfg.buffs || [], // 角色buff + defParams: cfg.defParams || {}, // 默认参数,一般为空 + defDmgIdx: cfg.defDmgIdx || -1, // 默认详情index + defDmgKey: cfg.defDmgKey || '', + mainAttr: cfg.mainAttr || 'atk,cpct,cdmg', // 伤害属性 + enemyName: cfg.enemyName || this.isGs ? '小宝' : '弱点敌人' // 敌人名称 + } + } + return false + } + + async calcData ({ enemyLv = 91, mode = 'profile', dmgIdx = 0, idxIsInput = false }) { + if (!this.char || !this.profile) { + return false + } + let { profile } = this + let { game } = this.char + let sp = this.detail?.sp + let charCalcData = await this.getCalcRule() + + if (!charCalcData) { + return false + } + let { buffs, details, defParams, mainAttr, defDmgIdx, defDmgKey, enemyName } = charCalcData + + let talent = this.talent() + + let meta = { + level: profile.level, + cons: profile.cons * 1, + talent, + trees: this.trees() + } + + let { id, weapon, attr } = profile + + defParams = defParams || {} + + let originalAttr = DmgAttr.getAttr({ id, weapon, attr, char: this.char, game, sp }) + + buffs = this.getBuffs(buffs) + + let { msg } = DmgAttr.calcAttr({ originalAttr, buffs, meta, params: defParams || {} }) + let msgList = [] + + let ret = [] + let detailMap = [] + let dmgRet = [] + let dmgDetail = {} + + // 用户手动输入伤害序号 + if (idxIsInput) { + // 从1开始,所以需要 - 1 + dmgIdx = --dmgIdx < 0 ? 0 : dmgIdx + } + + if (mode === 'single') { + dmgIdx = defDmgIdx > -1 ? defDmgIdx : 0 + } + + lodash.forEach(details, (detail, detailSysIdx) => { + if (mode === 'single') { + if (defDmgKey) { + if (detail.dmgKey !== defDmgKey) { + return true + } + } else if (detailSysIdx !== dmgIdx) { + return true + } + } + + if (lodash.isFunction(detail)) { + let { attr } = DmgAttr.calcAttr({ originalAttr, buffs, meta }) + let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta)) + detail = detail({ ...ds, attr, profile }) + } + let params = lodash.merge({}, defParams, detail?.params || {}) + let { attr, msg } = DmgAttr.calcAttr({ originalAttr, buffs, meta, params, talent: detail.talent || '' }) + if (detail.isStatic) { + return + } + if (detail.check && !detail.check(DmgAttr.getDs(attr, meta, params))) { + return + } + if (detail.cons && meta.cons < detail.cons * 1) { + return + } + let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta, params)) + + let dmg = DmgCalc.getDmgFn({ ds, attr, level: profile.level, enemyLv, showDetail: detail.showDetail, game }) + let basicDmgRet + + if (detail.dmg) { + basicDmgRet = detail.dmg(ds, dmg) + detail.userIdx = detailMap.length + detailMap.push(detail) + ret.push({ + title: detail.title, + ...basicDmgRet + }) + } + msgList.push(msg) + }) + + if (mode === 'dmg') { + let detail + if (idxIsInput && detailMap[dmgIdx]) { + detail = detailMap[dmgIdx] + } else if (idxIsInput) { + // 当用户输入的下标错误时,提示错误 + throw new MiaoError(`序号输入错误:${this.char.name}最多只支持${detailMap.length}种伤害计算哦`) + } else if (!lodash.isUndefined(defDmgIdx) && details[defDmgIdx]) { + detail = details[defDmgIdx] + } else { + detail = detailMap[0] + } + + if (lodash.isFunction(detail)) { + let { attr } = DmgAttr.calcAttr({ originalAttr, buffs, meta }) + let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta)) + detail = detail({ ...ds, attr, profile }) + } + dmgDetail = { + title: detail.title, + userIdx: detail.userIdx || defDmgIdx, + basicRet: lodash.merge({}, ret[detail.userIdx] || ret[defDmgIdx]), + attr: [] + } + + let attrMap = game === 'gs' ? attrMapGS : attrMapSR + + // 计算角色属性增减 + mainAttr = mainAttr.split(',') + let params = lodash.merge({}, defParams, detail.params || {}) + let basicDmg = dmgDetail.basicRet + lodash.forEach(mainAttr, (reduceAttr) => { + dmgDetail.attr.push(attrMap[reduceAttr]) + let rowData = [] + lodash.forEach(mainAttr, (incAttr) => { + if (incAttr === reduceAttr) { + rowData.push({ type: 'na' }) + return + } + let { attr } = DmgAttr.calcAttr({ + originalAttr, + buffs, + meta, + params, + incAttr, + reduceAttr, + talent: detail.talent || '', + game + }) + let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta, params)) + let dmg = DmgCalc.getDmgFn({ ds, attr, level: profile.level, enemyLv, game }) + if (detail.dmg) { + let dmgCalcRet = detail.dmg(ds, dmg) + rowData.push({ + type: dmgCalcRet.avg === basicDmg.avg ? 'avg' : (dmgCalcRet.avg > basicDmg.avg ? 'gt' : 'lt'), + ...dmgCalcRet + }) + } + }) + dmgRet.push(rowData) + }) + } + + if (mode === 'single') { + return ret[0] + } + return { + ret, + // 根据当前计算的伤害,显示对应的buff列表 + msg: msgList[idxIsInput ? dmgIdx : (defDmgIdx > -1 ? defDmgIdx : dmgIdx)] || msg, + msgList, + dmgRet, + enemyName, + dmgCfg: dmgDetail, + enemyLv + } + } +} diff --git a/Yunzai/plugins/miao-plugin/models/ProfileRank.js b/Yunzai/plugins/miao-plugin/models/ProfileRank.js new file mode 100644 index 0000000000000000000000000000000000000000..b5227be842ee7787075607888c5a712e58d7b773 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/ProfileRank.js @@ -0,0 +1,413 @@ +import lodash from 'lodash' +import moment from 'moment' +import { Cfg, Common, Data, Version } from '#miao' + +export default class ProfileRank { + constructor (data) { + this.groupId = data.groupId || data.groupId || '' + if (!this.groupId || this.groupId === 'undefined') { + return false + } + this.qq = data.qq + this.uid = data.uid + '' + this.allowRank = false + } + + static async create (data) { + let rank = new ProfileRank(data) + rank.allowRank = await ProfileRank.checkRankLimit(rank.uid) + return rank + } + + /** + * 获取群排行UID + * @param groupId + * @param charId + * @param type + * @returns {Promise} + */ + static async getGroupMaxUid (groupId, charId, type = 'mark') { + let uids = await redis.zRange(`miao:rank:${groupId}:${type}:${charId}`, -1, -1) + return uids ? uids[0] : false + } + + static async getGroupMaxUidList (groupId, type = 'mark') { + let keys = await redis.keys(`miao:rank:${groupId}:${type}:*`) + let ret = [] + for (let key of keys) { + let keyRet = /^miao:rank:[\w-]+:(?:mark|dmg|crit|valid):(\d{8})$/.exec(key) + if (keyRet && keyRet[1]) { + let charId = keyRet[1] + let uid = await ProfileRank.getGroupMaxUid(groupId, charId, type) + if (uid) { + ret.push({ + uid, + charId + }) + } + } + } + return ret + } + + /** + * 获取排行榜 + * @param groupId + * @param charId + * @param type + * @returns {Promise[]|boolean>} + */ + static async getGroupUidList (groupId, charId, type = 'mark') { + let number = Cfg.get('rankNumber', 15) + let uids = await redis.zRangeWithScores(`miao:rank:${groupId}:${type}:${charId}`, -`${number}`, -1) + return uids ? uids.reverse() : false + } + + /** + * 重置群排行 + * @param groupId + * @param charId + * @returns {Promise} + */ + static async resetRank (groupId, charId = '') { + let keys = await redis.keys(`miao:rank:${groupId}:*`) + for (let key of keys) { + let charRet = /^miao:rank:\d+:(?:mark|dmg|crit|valid):(\d{8})$/.exec(key) + if (charRet) { + if (charId === '' || charId * 1 === charRet[1] * 1) { + await redis.del(key) + } + } + } + if (charId === '') { + await redis.del(`miao:rank:${groupId}:cfg`) + } + } + + static async getGroupCfg (groupId) { + const rankLimitTxt = { + 1: '无限制', + 2: '绑定有CK的用户', + 3: '绑定CK,或列表有16个角色数据', + 4: '绑定CK,或列表有安柏&凯亚&丽莎的数据', + 5: '绑定CK,或列表有16个角色数据且包含安柏&凯亚&丽莎' + } + let rankLimit = Common.cfg('groupRankLimit') * 1 || 1 + let ret = await Data.redisGet(`miao:rank:${groupId}:cfg`, { + timestamp: (new Date()) * 1, + status: 0 + }) + await Data.redisSet(`miao:rank:${groupId}:cfg`, ret, 3600 * 24 * 365) + ret.limitTxt = rankLimitTxt[rankLimit] + ret.time = moment(new Date(ret.timestamp)).format('MM-DD HH:mm') + ret.number = Cfg.get('rankNumber', 15) + return ret + } + + /** + * 设置群开关状态 + * @param groupId + * @param status:0开启,1关闭 + * @returns {Promise} + */ + static async setGroupStatus (groupId, status = 0) { + let cfg = await Data.redisGet(`miao:rank:${groupId}:cfg`, { + timestamp: (new Date()) * 1, + status + }) + cfg.status = status + await Data.redisSet(`miao:rank:${groupId}:cfg`, cfg, 3600 * 24 * 365) + } + + static async setUidInfo ({ uid, qq, profiles, uidType = 'bind' }) { + if (!uid) { + return false + } + let basicCount = 0 + let totalCount = 0 + for (let charId in profiles) { + let profile = profiles[charId] + if (!profile || !profile.hasData) { + continue + } + if (['安柏', '凯亚', '丽莎'].includes(profile.name)) { + basicCount++ + } + totalCount++ + } + let data = {} + try { + let uData = await redis.get(`miao:rank:uid-info:${uid}`) + if (uData) { + data = JSON.parse(uData) + } + } catch (e) { + data = {} + } + data.totalCount = totalCount + data.basicCount = basicCount + if (data.isSelfUid) { + delete data.isSelfUid + data.uidType = 'ck' + } + + if (uidType === 'ck') { + data.uidType = 'ck' + data.qq = qq || data.qq || '' + } else { + data.uidType = data.uidType || 'bind' + if (data.uidType === 'bind') { + data.qq = data.qq || qq || '' + } else { + data.qq = qq || data.qq || '' + } + } + await redis.set(`miao:rank:uid-info:${uid}`, JSON.stringify(data), { EX: 3600 * 24 * 365 }) + } + + static async delUidInfo (uid) { + let keys = await redis.keys('miao:rank:*') + uid = uid + '' + if (!/\d{9}/.test(uid)) { + return false + } + for (let key of keys) { + let charRet = /^miao:rank:\d+:(?:mark|dmg|crit|valid):(\d{8})$/.exec(key) + if (charRet) { + await redis.zRem(key, uid) + } + } + } + + static async getUidInfo (uid) { + try { + let data = await redis.get(`miao:rank:uid-info:${uid}`) + return JSON.parse(data) + } catch (e) { + } + return false + } + + static async getUserUidMap (e, game = 'gs') { + let rn = e.runtime + let groupMemMap = await e.group?.getMemberMap() || [] + let users = {} + for (let [qq] of groupMemMap) { + users[qq] = true + } + + let uidMap = {} + let qqMap = {} + let add = (qq, uid, type) => { + uidMap[uid] = { uid, qq, type: type === 'ck' ? 'ck' : 'bind' } + qqMap[qq] = true + } + + let keys = await redis.keys('miao:rank:uid-info:*') + for (let key of keys) { + let data = await Data.redisGet(key) + let { qq, uidType } = data + if (!users[qq]) continue + let uidRet = /miao:rank:uid-info:(\d{9})/.exec(key) + if (qq && uidType && uidRet?.[1]) { + add(qq, uidRet[1], uidType === 'ck' ? 'ck' : 'bind') + } + } + + if (rn.NoteUser) { + // Miao-Yunzai + await rn.NoteUser.forEach(async (user) => { + if (!users[user.qq]) return true + let uids = user.getUidList(game) + lodash.forEach(uids, (ds) => { + let { uid, type } = ds + add(user.qq, uid, type) + }) + }) + } else { + if (rn?.gsCfg?.getBingCk) { + // Yunzai-V3 + let noteCks = await rn.gsCfg.getBingCk(game) || {} + lodash.forEach(noteCks.ck, (ck, _qq) => { + let qq = ck.qq || _qq + let uid = ck.uid + if (!users[qq]) return true + add(qq, uid, 'ck') + }) + } + } + + for (let qq in users) { + if (qqMap[qq]) continue + let uid = await redis.get(Version.isV3 ? `Yz:genshin:mys:qq-uid:${qq}` : `genshin:id-uid:${qq}`) + if (uid) { + add(qq, uid, 'bind') + } + } + + return uidMap + } + + /** + * 1: '无限制', + * 2: '绑定有CK的用户', + * 3: '面板列表有16个角色数据,或绑定CK', + * 4: '面板列表有安柏&凯亚&丽莎的数据,或绑定CK', + * 5: '面板列表有16个角色数据且包含安柏&凯亚&丽莎,或绑定CK' + * @param uid + * @returns {Promise} + */ + static async checkRankLimit (uid) { + if (!uid) { + return false + } + // 预设面板不参与排名 + if (uid * 1 < 100000006) { + return false + } + try { + let rankLimit = Common.cfg('groupRankLimit') * 1 || 1 + if (rankLimit === 1) { + return true + } + let data = await redis.get(`miao:rank:uid-info:${uid}`) + data = JSON.parse(data) + if (data.isSelfUid || data.uidType === 'ck') { + return true + } + if (rankLimit === 2) { + return false + } + if ((data.totalCount || 0) < 16 && [3, 5].includes(rankLimit)) { + return false + } + if ((data.basicCount || 0) < 3 && [4, 5].includes(rankLimit)) { + return false + } + return true + } catch (e) { + return false + } + } + + key (profile, type) { + return `miao:rank:${this.groupId}:${type}:${profile.id}` + } + + /** + * 获取排行信息 + * @param profile + * @param force + * @returns {Promise<{}|boolean>} + */ + async getRank (profile, force = false) { + if (!profile || !this.groupId || !this.allowRank || !profile.hasData) { + return false + } + let ret = {} + for (let typeKey of ['mark', 'dmg', 'crit', 'valid']) { + let typeRank = await this.getTypeRank(profile, typeKey, force) + if (['mark', 'dmg'].includes(typeKey)) { + ret[typeKey] = typeRank + if (!ret.rank || ret.rank >= typeRank.rank) { + ret.rank = typeRank.rank + ret.rankType = typeKey + } + } + } + return ret + } + + async getTypeRank (profile, type, force) { + if (!profile || !profile.hasData || !type) { + return false + } + if (type === 'dmg' && !profile.hasDmg) { + return false + } + const typeKey = this.key(profile, type) + let value + let rank + if (force) { + value = await this.getTypeValue(profile, type) + } else { + rank = await redis.zRevRank(typeKey, this.uid) + if (!lodash.isNumber(rank)) { + value = await this.getTypeValue(profile, type) + } + } + if (value && !lodash.isUndefined(value.score)) { + await redis.zAdd(typeKey, { score: value.score, value: this.uid }) + } + if (!lodash.isNumber(rank)) { + rank = await redis.zRevRank(typeKey, this.uid) + } + if (rank === null) { + rank = 99 + } + if (force) { + return { + rank: rank + 1, + value: value.score, + data: value.data + } + } + return { + rank: rank + 1 + } + } + + async getTypeValue (profile, type) { + if (!profile || !profile.hasData) { + return false + } + if (type === 'mark') { + if (!profile?.artis?.hasArtis) { + return false + } + let mark = profile.getArtisMark(false) + if (mark && mark._mark) { + return { + score: mark.mark * 1, + data: mark + } + } + } + if (type === 'crit') { + if (!profile?.artis?.hasArtis) { + return false + } + let mark = profile.getArtisMark(false) + if (mark && mark._crit) { + return { + score: mark._crit * 1, + data: mark + } + } + } + if (type === 'valid') { + if (!profile?.artis?.hasArtis) { + return false + } + let mark = profile.getArtisMark(false) + if (mark && mark._valid) { + return { + score: mark._valid * 1, + data: mark + } + } + } + if (type === 'dmg' && profile.hasDmg) { + let dmg = await profile.calcDmg({ mode: 'single' }) + if (dmg && dmg.avg) { + return { + score: dmg.avg, + data: dmg + } + } + } + return false + } + + +} diff --git a/Yunzai/plugins/miao-plugin/models/ProfileReq.js b/Yunzai/plugins/miao-plugin/models/ProfileReq.js new file mode 100644 index 0000000000000000000000000000000000000000..b1877e6bf3ada18e0b841fdcd8586699b8b6da08 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/ProfileReq.js @@ -0,0 +1,128 @@ +import Base from './Base.js' +import fetch from 'node-fetch' + +export default class ProfileReq extends Base { + constructor (e, game = 'gs') { + super() + this.e = e + this.game = game + this.uid = e.uid + } + + static create (e, game = 'gs') { + if (!e || !e.uid) { + return false + } + // 预设面板不更新数据 + if (e.uid * 1 < 100000006) { + return false + } + return new ProfileReq(e, game) + } + + async setCd (seconds = 60) { + let ext = new Date() * 1 + seconds * 1000 + await redis.set(`miao:profile-cd:${this.uid}`, ext + '', { EX: seconds }) + } + + async inCd () { + let ext = await redis.get(`miao:profile-cd:${this.uid}`) + if (!ext || isNaN(ext)) { + return false + } + let cd = (new Date() * 1) - ext + if (cd < 0 && Math.abs(cd) < 100 * 60 * 1000) { + return Math.ceil(0 - cd / 1000) + } + return false + } + + err (msg = '', cd = 0) { + let serv = this.serv + let extra = serv.name ? `当前面板服务${serv.name},` : '' + const msgs = { + error: `UID${this.uid}更新面板失败,${extra}\n可能是面板服务维护中,请稍后重试...`, + empty: '请将角色放置在【游戏内】角色展柜,并打开【显示详情】,等待5分钟重新获取面板' + } + msg = msgs[msg] || msg + this.msg(msg) + // 设置CD + if (cd) { + this.setCd(cd) + } + return false + } + + msg (msg) { + let e = this.e + if (msg && !e._isReplyed) { + e.reply(msg) + e._isReplyed = true + } + } + + log (msg) { + logger.mark(`【面板】${this.uid} :${msg}`) + } + + async requestProfile (player, serv) { + let self = this + this.serv = serv + let uid = this.uid + let reqParam = await serv.getReqParam(uid, self.game) + let cdTime = await this.inCd() + if (cdTime && !process.argv.includes('web-debug')) { + // return this.err(`请求过快,请${cdTime}秒后重试..`) + } + await this.setCd(20) + // 若3秒后还未响应则返回提示 + setTimeout(() => { + if (self._isReq) { + this.e.reply(`开始获取uid:${uid}的数据,可能会需要一定时间~`) + } + }, 2000) + // 发起请求 + this.log(`${logger.yellow('开始请求数据')},面板服务:${serv.name}...`) + const startTime = new Date() * 1 + let data = {} + try { + let params = reqParam.params || {} + params.timeout = params.timeout || 1000 * 20 + self._isReq = true + let req = await fetch(reqParam.url, params) + data = await req.text() + self._isReq = false + const reqTime = new Date() * 1 - startTime + this.log(`${logger.green(`请求结束,请求用时${reqTime}ms`)},面板服务:${serv.name}...`) + if (data[0] === '<') { + let titleRet = /(.+)<\/title>/.exec(data) + if (titleRet && titleRet[1]) { + data = { error: titleRet[1] } + } else { + return this.err('error', 60) + } + } else { + data = JSON.parse(data) + } + } catch (e) { + console.log('面板请求错误', e) + self._isReq = false + data = {} + } + data = await serv.response(data, this, self.game) + // 设置CD + cdTime = serv.getCdTime(data) + if (cdTime) { + await this.setCd(cdTime) + } + if (data === false) { + return false + } + serv.updatePlayer(player, data) + cdTime = serv.getCdTime(data) + if (cdTime) { + await this.setCd(cdTime) + } + return player + } +} diff --git a/Yunzai/plugins/miao-plugin/models/ProfileServ.js b/Yunzai/plugins/miao-plugin/models/ProfileServ.js new file mode 100644 index 0000000000000000000000000000000000000000..20847f02865bf95b83d6473a215a15ffb11815a3 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/ProfileServ.js @@ -0,0 +1,82 @@ +import lodash from 'lodash' +import Base from './Base.js' +import { Data, Cfg } from '#miao' + +let { sysCfg, diyCfg } = await Data.importCfg('profile') + +export default class ProfileServ extends Base { + constructor (cfg) { + super() + this._name = cfg.name + this.cfgKey = cfg.cfgKey || cfg.id + this.diyCfg = diyCfg[this.cfgKey] || {} + this.sysCfg = sysCfg[this.cfgKey] || {} + this._cfg = cfg + } + + get name () { + let url = this.getCfg('url') + return this._name || url.replace('https://', '').replace('/', '').trim() + } + + // 获取当前面板服务配置 + getCfg (key, def = '') { + if (!lodash.isUndefined(this.diyCfg[key])) { + return this.diyCfg[key] + } + if (!lodash.isUndefined(this.sysCfg[key])) { + return this.sysCfg[key] + } + return def + } + + // 请求当前面板服务 + async getReqParam (uid, game = 'gs') { + let url = this.getCfg('url') + let profileApi = this.getCfg('listApi') + let cfg = this._cfg + let api = profileApi({ + url, + uid: uid, + diyCfg: this.diyCfg, + game + }) + let param = {} + + // 获取请求参数 + if (cfg.request) { + param = await cfg.request.call(this, api) + } + + return { + url: param.api || api, + params: param.params || {} + } + } + + async response (data, req, game = 'gs') { + // 处理返回 + let cfg = this._cfg + if (cfg.response) { + return await cfg.response.call(this, data, req, game) + } + } + + execFn (fn, args = [], def = false) { + let { _cfg } = this + if (_cfg[fn]) { + return _cfg[fn].apply(this, args) + } + return def + } + + getCdTime (data) { + const requestInterval = diyCfg.requestInterval || sysCfg.requestInterval || 5 + let cdTime = requestInterval * 60 + return Math.max(cdTime, this.execFn('cdTime', [data], 60)) + } + + updatePlayer (player, data) { + return this.execFn('updatePlayer', [player, data], {}) + } +} diff --git a/Yunzai/plugins/miao-plugin/models/User.js b/Yunzai/plugins/miao-plugin/models/User.js new file mode 100644 index 0000000000000000000000000000000000000000..3ef4fa1e6ba0c35f5cca1258aad2b252b4203c8a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/User.js @@ -0,0 +1,69 @@ +/* +* User Class +* 提供用户实例相关的操作方法 +* */ +import Base from './Base.js' +import lodash from 'lodash' + +/* User Class Model + +* 所有用户实例均可调用实例方法 +* */ +class User extends Base { + // 初始化用户 + constructor (cfg) { + super() + if (!cfg.id) { + return false + } + let self = this._getCache(`user:${cfg.id}`) + if (!self) { + self = this + } + self.id = cfg.id + self.uid = cfg.uid || self.uid || '' + self.ck = cfg.ck || cfg.cookie || self.ck || '' + return self._cache() + } + + // 保存用户配置 + async setCfg (path, value) { + let userCfg = await redis.get(`miao:user-cfg:${this.id}`) || await redis.get(`genshin:user-cfg:${this.id}`) + userCfg = userCfg ? JSON.parse(userCfg) : {} + lodash.set(userCfg, path, value) + await redis.set(`miao:user-cfg:${this.id}`, JSON.stringify(userCfg)) + } + + /* 获取用户配置 */ + async getCfg (path, defaultValue) { + let userCfg = await redis.get(`miao:user-cfg:${this.id}`) || await redis.get(`genshin:user-cfg:${this.id}`) + userCfg = userCfg ? JSON.parse(userCfg) : {} + return lodash.get(userCfg, path, defaultValue) + } + + async getMysUser () { + return { + uid: this.uid + } + } + + get cookie () { + return this.ck || '' + } + + static async get (e) { + if (e.user_id) { + return new User({ id: e.user_id }) + } + } + + static async checkAuth (e, type = 'all') { + let user = await User.get(e) + if (type === 'master') { + return false + } + return user + } +} + +export default User diff --git a/Yunzai/plugins/miao-plugin/models/Weapon.js b/Yunzai/plugins/miao-plugin/models/Weapon.js new file mode 100644 index 0000000000000000000000000000000000000000..607a6ea2986e3b29952c7979eece0d0e7757b4ba --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/Weapon.js @@ -0,0 +1,283 @@ +import Base from './Base.js' +import { Data, Format } from '#miao' +import { weaponData, weaponAbbr, weaponAlias, weaponType, weaponSet, weaponBuffs } from '../resources/meta/weapon/index.js' +import { + weaponData as weaponDataSR, + weaponAlias as weaponAliasSR, + weaponBuffs as weaponBuffsSR +} from '../resources/meta-sr/weapon/index.js' + +import lodash from 'lodash' + +class Weapon extends Base { + constructor (name, game = 'gs') { + super(name) + let meta = game === 'gs' ? weaponData[name] : weaponDataSR[name] + if (!meta) { + return false + } + let cache = this._getCache(`weapon:${game}:${name}`) + if (cache) { + return cache + } + this.id = meta.id + this.name = meta.name + this.meta = meta + this.type = meta.type + this.star = meta.star + this.game = game + return this._cache() + } + + get abbr () { + return weaponAbbr[this.name] || this.name + } + + get title () { + return this.name + } + + get img () { + return `${this.isGs ? 'meta' : 'meta-sr'}/weapon/${this.type}/${this.name}/icon.webp` + } + + get imgs () { + if (this.isGs) { + return { + icon: `meta/weapon/${this.type}/${this.name}/icon.webp`, + icon2: `meta/weapon/${this.type}/${this.name}/awaken.webp`, + gacha: `meta/weapon/${this.type}/${this.name}/gacha.webp` + } + } else { + return { + icon: `meta-sr/weapon/${this.type}/${this.name}/icon.webp`, + icon2: `meta-sr/weapon/${this.type}/${this.name}/icon-s.webp`, + gacha: `meta-sr/weapon/${this.type}/${this.name}/splash.webp` + } + } + } + + get icon () { + return this.img + } + + get detail () { + return this.getDetail() + } + + get maxLv () { + return this.star <= 2 ? 70 : 90 + } + + get maxPromote () { + return this.star <= 2 ? 4 : 6 + } + + get maxAffix () { + if (this.isSr) { + return 5 + } + let data = this.detail?.affixData?.datas || {} + return (data['0'] && data['0'][4]) ? 5 : 1 + } + + static isWeaponSet (name) { + return weaponSet.includes(name) + } + + static get (name, game = 'gs', type = '') { + name = lodash.trim(name) + let alias = game === 'gs' ? weaponAlias : weaponAliasSR + if (alias[name]) { + return new Weapon(alias[name], game) + } + if (type && game === 'gs') { + let name2 = name + (weaponType[type] || type) + if (weaponAlias[name2]) { + return new Weapon(weaponAlias[name2]) + } + } + return false + } + + static async forEach (fn, type = '') { + for (let name in weaponData) { + let ds = weaponData[name] + let w = Weapon.get(ds.name) + if (!w || (type && type !== w.type)) { + continue + } + await fn(w) + } + } + + getDetail () { + if (this._detail) { + return this._detail + } + const path = this.isGs ? 'resources/meta/weapon' : 'resources/meta-sr/weapon' + try { + this._detail = Data.readJSON(`${path}/${this.type}/${this.name}/data.json`, 'miao') + } catch (e) { + console.log(e) + } + return this._detail + } + + calcAttr (level, promote = -1) { + let metaAttr = this.detail?.attr + if (!metaAttr) { + return false + } + if (this.isSr) { + let lvAttr = metaAttr[promote] + let ret = {} + lodash.forEach(lvAttr.attrs, (v, k) => { + ret[k] = v * 1 + }) + lodash.forEach(this.detail?.growAttr, (v, k) => { + ret[k] = ret[k] * 1 + v * (level - 1) + }) + return ret + } + + let lvLeft = 1 + let lvRight = 20 + let lvStep = [1, 20, 40, 50, 60, 70, 80, 90] + let currPromote = 0 + for (let idx = 0; idx < lvStep.length - 1; idx++) { + if (promote === -1 || (currPromote === promote)) { + if (level >= lvStep[idx] && level <= lvStep[idx + 1]) { + lvLeft = lvStep[idx] + lvRight = lvStep[idx + 1] + break + } + } + currPromote++ + } + let wAttr = this?.detail?.attr || {} + let wAtk = wAttr.atk || {} + let valueLeft = wAtk[lvLeft + '+'] || wAtk[lvLeft] || {} + let valueRight = wAtk[lvRight] || {} + let atkBase = valueLeft * 1 + ((valueRight - valueLeft) * (level - lvLeft) / (lvRight - lvLeft)) + let wBonus = wAttr.bonusData || {} + valueLeft = wBonus[lvLeft + '+'] || wBonus[lvLeft] + valueRight = wBonus[lvRight] + let stepCount = Math.ceil((lvRight - lvLeft) / 5) + let valueStep = (valueRight - valueLeft) / stepCount + let value = valueLeft + (stepCount - Math.ceil((lvRight - level) / 5)) * valueStep + return { + atkBase, + attr: { + key: wAttr.bonusKey, + value + } + } + } + + // 获取精炼描述 + getAffixDesc (affix = 1) { + if (this.isGs) { + return {} + } + let skill = this.detail.skill + let { name, desc, tables } = skill + let reg = /\$(\d)\[(?:i|f1)\](\%?)/g + let ret + while ((ret = reg.exec(desc)) !== null) { + let idx = ret[1] + let pct = ret[2] + let value = tables?.[idx]?.[affix - 1] + if (pct === '%') { + value = Format.pct(value) + } else { + value = Format.comma(value) + } + desc = desc.replaceAll(ret[0], value) + } + return { + name: skill.name, + desc + } + } + + getWeaponBuffs () { + let { isSr } = this + let wBuffs = (isSr ? weaponBuffsSR : weaponBuffs) + let buffs = wBuffs[this.id] || wBuffs[this.name] + if (!buffs) { + return false + } + if (lodash.isPlainObject(buffs) || lodash.isFunction(buffs)) { + buffs = [buffs] + } + return buffs + } + + getWeaponAffixBuffs (affix, isStatic = true) { + let buffs = this.getWeaponBuffs() + let ret = [] + let self = this + let { detail } = this + + let tables = {} + lodash.forEach(detail?.skill?.tables || {}, (ds, idx) => { + tables[idx] = ds[affix - 1] + }) + + lodash.forEach(buffs, (ds) => { + if (lodash.isFunction(ds)) { + ds = ds(tables) + } + if (!!ds.isStatic !== !!isStatic) { + return true + } + + // 静态属性 + if (ds.isStatic) { + let tmp = {} + // 星铁武器格式 + if (ds.idx && ds.key) { + if (!ds.idx || !ds.key) return true + if (!tables[ds.idx]) return true + tmp[ds.key] = tables[ds.idx] + } + if (ds.refine) { + lodash.forEach(ds.refine, (r, key) => { + tmp[key] = r[affix - 1] * (ds.buffCount || 1) + }) + } + if (!lodash.isEmpty(tmp)) { + ret.push({ + isStatic: true, + data: tmp + }) + } + return true + } + + // 自动拼接标题 + if (!/:/.test(ds.title)) { + ds.title = `${self.name}:${ds.title}` + } + ds.data = ds.data || {} + // refine + if (ds.idx && ds.key) { + if (!ds.idx || !ds.key) return true + if (!tables[ds.idx]) return true + ds.data[ds.key] = tables[ds.idx] + } else if (ds.refine) { + + lodash.forEach(ds.refine, (r, key) => { + ds.data[key] = ({ refine }) => r[refine] * (ds.buffCount || 1) + }) + } + + ret.push(ds) + }) + + return ret + } +} + +export default Weapon diff --git a/Yunzai/plugins/miao-plugin/models/character/CharCfg.js b/Yunzai/plugins/miao-plugin/models/character/CharCfg.js new file mode 100644 index 0000000000000000000000000000000000000000..d20982f10fd18abb0f33873c7307b6e432c0e784 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/character/CharCfg.js @@ -0,0 +1,64 @@ +import { Data } from '#miao' +import lodash from 'lodash' +import fs from 'fs' + +const charPath = process.cwd() + '/plugins/miao-plugin/resources/meta/character' +let cfgMap = { + char: {}, + async init () { + let chars = fs.readdirSync(charPath) + for (let char of chars) { + cfgMap.char[char] = {} + let curr = cfgMap.char[char] + // 评分规则 + if (cfgMap.exists(char, 'artis_user')) { + curr.artis = await cfgMap.getCfg(char, 'artis_user', 'default') + } else if (cfgMap.exists(char, 'artis')) { + curr.artis = await cfgMap.getCfg(char, 'artis', 'default') + } + // 伤害计算 + if (cfgMap.exists(char, 'calc_user')) { + curr.calc = await cfgMap.getCfg(char, 'calc_user') + } else if (cfgMap.exists(char, 'calc')) { + curr.calc = await cfgMap.getCfg(char, 'calc') + } + } + }, + exists (char, file) { + return fs.existsSync(`${charPath}/${char}/${file}.js`) + }, + async getCfg (char, file, module = '') { + let cfg = await Data.importModule(`resources/meta/character/${char}/${file}.js`, 'miao') + if (module) { + return cfg[module] + } + return cfg + } +} +await cfgMap.init() + +/** + * 角色相关配置 + */ +let CharCfg = { + // 获取角色伤害计算相关配置 + getCalcRule (char) { + let cfg = cfgMap.char[char.isTraveler ? '旅行者' : char.name]?.calc + if (!cfg || lodash.isEmpty(cfg)) { + return false + } + return { + details: cfg.details || false, // 计算详情 + buffs: cfg.buffs || [], // 角色buff + defParams: cfg.defParams || {}, // 默认参数,一般为空 + defDmgIdx: cfg.defDmgIdx || -1, // 默认详情index + defDmgKey: cfg.defDmgKey || '', + mainAttr: cfg.mainAttr || 'atk,cpct,cdmg', // 伤害属性 + enemyName: cfg.enemyName || '小宝' // 敌人名称 + } + }, + getArtisCfg (char) { + return cfgMap.char[char.isTraveler ? '旅行者' : char.name]?.artis || false + } +} +export default CharCfg diff --git a/Yunzai/plugins/miao-plugin/models/character/CharId.js b/Yunzai/plugins/miao-plugin/models/character/CharId.js new file mode 100644 index 0000000000000000000000000000000000000000..c586bac8ef4181ba1748d71c54e1f247812ec376 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/character/CharId.js @@ -0,0 +1,163 @@ +/** + * 角色别名及角色ID相关 + * */ +import lodash from 'lodash' +import { Data, Format } from '#miao' +import { charPosIdx } from './CharMeta.js' +import { aliasMap as aliasMapSR } from '../../resources/meta-sr/character/meta.js' + +// 别名表 +let aliasMap = {} +// ID表 +let idMap = {} +// 简写表 +let abbrMap = {} +// wife +let wifeMap = {} +// id排序 +let idSort = {} + +let gameMap = {} + +let srData = Data.readJSON('/resources/meta-sr/character/data.json', 'miao') + +async function init () { + let { sysCfg, diyCfg } = await Data.importCfg('character') + + lodash.forEach(srData, (ds) => { + let { id, name } = ds + aliasMap[id] = id + aliasMap[name] = id + idMap[id] = name + gameMap[id] = 'sr' + }) + + // 添加别名 + lodash.forEach(aliasMapSR, (v, k) => { + aliasMap[k] = aliasMap[v] + }) + + lodash.forEach([diyCfg.customCharacters, sysCfg.characters], (roleIds) => { + lodash.forEach(roleIds || {}, (aliases, id) => { + aliases = aliases || [] + if (aliases.length === 0) { + return + } + // 建立别名映射 + lodash.forEach(aliases || [], (alias) => { + alias = alias.toLowerCase() + aliasMap[alias] = id + }) + aliasMap[id] = id + idMap[id] = aliases[0] + gameMap[id] = 'gs' + }) + }) + + lodash.forEach([sysCfg.wifeData, diyCfg.wifeData], (wifeData) => { + lodash.forEach(wifeData || {}, (ids, type) => { + type = Data.def({ girlfriend: 0, boyfriend: 1, daughter: 2, son: 3 }[type], type) + if (!wifeMap[type]) { + wifeMap[type] = {} + } + Data.eachStr(ids, (id) => { + id = aliasMap[id] + if (id) { + wifeMap[type][id] = true + } + }) + }) + }) + abbrMap = sysCfg.abbr +} + +await init() + +lodash.forEach(charPosIdx, (chars, pos) => { + chars = chars.split(',') + lodash.forEach(chars, (name, idx) => { + let id = aliasMap[name] + if (id) { + idSort[id] = pos * 100 + idx + } + }) +}) + +const CharId = { + aliasMap, + idMap, + gameMap, + abbrMap, + wifeMap, + idSort, + isGs (id) { + return gameMap[id] === 'gs' + }, + isSr (id) { + return gameMap[id] === 'sr' + }, + getId (ds = '', gsCfg = null, game = 'gs') { + if (!ds) { + return false + } + const ret = (id, elem = '') => { + if (CharId.isSr(id)) { + return { id, name: idMap[id], game: 'sr' } + } else { + return { id, elem, name: idMap[id], game: 'gs' } + } + } + if (!lodash.isObject(ds)) { + let original = lodash.trim(ds || '') + ds = original.toLowerCase() + // 尝试使用元素起始匹配 + let em = Format.matchElem(ds, '', true) + if (em && aliasMap[em.name] && CharId.isTraveler(aliasMap[em.name])) { + return ret(aliasMap[em.name], em.elem) + } + // 直接匹配 + if (aliasMap[ds]) { + return ret(aliasMap[ds]) + } + // 调用V3方法匹配 + if (gsCfg && gsCfg.getRole) { + let roleRet = gsCfg.getRole(original) + if (roleRet.name && aliasMap[roleRet.name]) { + return ret(aliasMap[roleRet.name]) + } + } + // 无匹配结果 + return false + } + // 获取字段进行匹配 + let { id = '', name = '' } = ds + let elem = Format.elem(ds.elem || ds.element) + // 直接匹配 + if (aliasMap[id || name]) { + return ret(aliasMap[id || name], elem) + } + // 尝试解析名字 + let nId = CharId.getId(ds.name) + if (nId) { + return ret(nId.id, elem || nId.elem || '') + } + // 无匹配结果 + return false + }, + + isTraveler (id, game = 'gs') { + if (id) { + return [10000007, 10000005, 20000000].includes(id * 1) + } + return false + }, + + getTravelerId (id, game = 'gs') { + return id * 1 === 10000005 ? 10000005 : 10000007 + }, + + getSrMeta (name) { + return srData?.[aliasMap[name]] || {} + } +} +export default CharId diff --git a/Yunzai/plugins/miao-plugin/models/character/CharImg.js b/Yunzai/plugins/miao-plugin/models/character/CharImg.js new file mode 100644 index 0000000000000000000000000000000000000000..e9b67182c34b23ebcfe333845b3153396163b9d2 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/character/CharImg.js @@ -0,0 +1,149 @@ +/** + * 角色照片及角色图像资源相关 + * */ +import fs from 'fs' +import lodash from 'lodash' +import sizeOf from 'image-size' + +const rPath = `${process.cwd()}/plugins/miao-plugin/resources` +const CharImg = { + + // 获取角色的插画 + getCardImg (names, se = false, def = true) { + let list = [] + let addImg = function (charImgPath, disable = false) { + let dirPath = `./plugins/miao-plugin/resources/${charImgPath}` + + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath) + } + if (disable) { + return + } + + let imgs = fs.readdirSync(dirPath) + imgs = imgs.filter((img) => /\.(png|jpg|webp|jpeg)/i.test(img)) + lodash.forEach(imgs, (img) => { + list.push(`${charImgPath}/${img}`) + }) + } + if (!lodash.isArray(names)) { + names = [names] + } + for (let name of names) { + addImg(`character-img/${name}`) + addImg(`character-img/${name}/upload`) + addImg(`character-img/${name}/se`, !se) + const plusPath = './plugins/miao-plugin/resources/miao-res-plus/' + if (fs.existsSync(plusPath)) { + addImg(`miao-res-plus/character-img/${name}`) + addImg(`miao-res-plus/character-img/${name}/se`, !se) + } + } + let img = lodash.sample(list) + if (!img) { + if (def) { + img = '/character-img/default/01.jpg' + } else { + return false + } + } + let ret = sizeOf(`./plugins/miao-plugin/resources/${img}`) + ret.img = img + ret.mode = ret.width > ret.height ? 'left' : 'bottom' + return ret + }, + + getRandomImg (imgPaths, defImgs = []) { + for (let imgPath of imgPaths) { + let ret = [] + for (let type of ['webp', 'png']) { + if (fs.existsSync(`${rPath}/${imgPath}.${type}`)) { + ret.push(imgPath + '.webp') + } + } + if (fs.existsSync(`${rPath}/${imgPath}`)) { + let imgs = fs.readdirSync(`${rPath}/${imgPath}`).filter((file) => { + return /\.(png|webp)$/.test(file) + }) + for (let img of imgs) { + ret.push(`${imgPath}/${encodeURIComponent(img)}`) + } + } + if (ret.length > 0) { + return lodash.sample(ret) + } + } + for (let defImg of defImgs) { + if (fs.existsSync(`${rPath}/${defImg}`)) { + return defImg + } + } + }, + + // 获取角色的图像资源数据 + getImgs (name, costumeIdx = '', travelerElem = '', weaponType = 'sword', talentCons) { + let fileType = 'webp' + costumeIdx = costumeIdx === '2' ? '2' : '' + let imgs = {} + if (!['空', '荧', '旅行者'].includes(name)) { + travelerElem = '' + } + const nPath = `/meta/character/${name}/` + const tPath = `/meta/character/旅行者/${travelerElem}/` + let add = (key, path, path2) => { + if (path2 && fs.existsSync(`${rPath}/${nPath}/${path2}.${fileType}`)) { + imgs[key] = `${nPath}${path2}.${fileType}` + } else { + imgs[key] = `${nPath}${path}.${fileType}` + } + } + let tAdd = (key, path) => { + imgs[key] = `${travelerElem ? tPath : nPath}${path}.${fileType}` + } + add('face', 'imgs/face', `imgs/face${costumeIdx}`) + add('qFace', 'imgs/face', 'imgs/face-q') + add('side', 'imgs/side', `imgs/side${costumeIdx}`) + add('gacha', 'imgs/gacha') + add('splash', 'imgs/splash', `imgs/splash${costumeIdx}`) + tAdd('card', 'imgs/card') + tAdd('banner', 'imgs/banner') + for (let i = 1; i <= 6; i++) { + tAdd(`cons${i}`, `icons/cons-${i}`) + } + for (let i = 0; i <= 3; i++) { + tAdd(`passive${i}`, `icons/passive-${i}`) + } + imgs.a = `/common/item/atk-${weaponType}.webp` + for (let t of ['e', 'q']) { + imgs[t] = talentCons[t] > 0 ? imgs[`cons${talentCons[t]}`] : `${nPath}icons/talent-${t}.webp` + } + return imgs + }, + getImgsSr (name, talentCons) { + let fileType = 'webp' + const nPath = `/meta-sr/character/${name}/` + let imgs = {} + let add = (key, path, path2) => { + imgs[key] = `${nPath}${path}.${fileType}` + } + add('face', 'imgs/face') + add('splash', 'imgs/splash') + add('preview', 'imgs/preview') + for (let i = 1; i <= 3; i++) { + add(`tree${i}`, `imgs/tree-${i}`) + } + for (let key of ['a', 'e', 'q', 't', 'z', 'a2', 'e2']) { + add(key, `imgs/talent-${key}`) + } + for (let i = 1; i <= 6; i++) { + if (i !== 3 && i !== 5) { + add(`cons${i}`, `imgs/cons-${i}`) + } + } + imgs.cons3 = imgs[talentCons[3]] + imgs.cons5 = imgs[talentCons[5]] + return imgs + } +} +export default CharImg diff --git a/Yunzai/plugins/miao-plugin/models/character/CharMeta.js b/Yunzai/plugins/miao-plugin/models/character/CharMeta.js new file mode 100644 index 0000000000000000000000000000000000000000..5d13c1b913c38d427f28e3e39863814c8469da3b --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/character/CharMeta.js @@ -0,0 +1,189 @@ +/* +* 角色资料数据相关 +* */ +import lodash from 'lodash' +import { Material } from '../index.js' +import { Format } from '#miao' + +// 角色排序 +export const charPosIdx = { + 1: '宵宫,雷神,胡桃,甘雨,优菈,一斗,公子,绫人,魈,可莉,迪卢克,凝光,刻晴,辛焱,烟绯,雷泽', + 2: '夜兰,八重,九条,行秋,香菱,安柏,凯亚,丽莎,北斗,菲谢尔,重云,罗莎莉亚,埃洛伊', + 3: '申鹤,莫娜,早柚,云堇,久岐忍,五郎,砂糖,万叶,温迪', + 4: '班尼特,心海,琴,芭芭拉,七七,迪奥娜,托马,空,荧,阿贝多,钟离' +} + +export const baseAttrName = { + hp: '基础生命', + atk: '基础攻击', + def: '基础防御' +} +export const growAttrName = { + atkPct: '大攻击', + hpPct: '大生命', + defPct: '大防御', + cpct: '暴击', + cdmg: '爆伤', + recharge: '充能', + mastery: '精通', + heal: '治疗', + phy: '物伤' +} + +const mKeys = [{ + key: 'gem', + num: '1/9/9/6' +}, { + key: 'boss', + num: '46', + check: (char) => !char.isTraveler +}, { + key: 'normal', + num: '18/30/36' +}, { + key: 'specialty', + num: '168' +}, { + key: 'talent' +}, { + key: 'weekly', + star: 5 +}] + +let item = (type, lv, num) => { + return { type, lv, num } +} +let gem = (lv = 1, num = 1) => item('gem', lv, num) +let sp = (num) => item('specialty', 1, num) +let normal = (lv, num) => item('normal', lv, num) +let boss = (num) => item('boss', 1, num) +let money = (num) => item('money', 1, num) +const lvKeys = [{ + lv: '1' +}, { + lv: '20' +}, { + lv: '20+', + items: [gem(1, 1), sp(3), normal(1, 3), money(2)] +}, { + lv: '40', + total: [gem(1, 1), sp(3), normal(1, 3), money(2)] +}, { + lv: '40+', + items: [gem(2, 3), boss(2), sp(10), normal(1, 15), money(4)] +}, { + lv: '50', + total: [gem(1, 1), gem(2, 3), boss(2), sp(13), normal(1, 18), money(6)] +}, { + lv: '50+', + items: [gem(2, 6), boss(4), sp(20), normal(2, 12), money(6)], +}, { + lv: '60', + total: [gem(1, 1), gem(2, 9), boss(6), sp(33), normal(1, 18), normal(2, 12), money(12)] +}, { + lv: '60+', + items: [gem(3, 3), boss(8), sp(30), normal(2, 18), money(8)], +}, { + lv: '70', + total: [gem(1, 1), gem(2, 9), gem(3, 3), boss(14), sp(63), normal(1, 18), normal(2, 30), money(20)] +}, { + lv: '70+', + items: [gem(3, 6), boss(12), sp(45), normal(3, 12), money(10)], +}, { + lv: '80', + total: [gem(1, 1), gem(2, 9), gem(3, 9), boss(26), sp(108), normal(1, 18), normal(2, 30), normal(3, 12), money(30)] +}, { + lv: '80+', + items: [gem(4, 6), boss(20), sp(60), normal(3, 24), money(12)] +}, { + lv: '90', + total: [gem(1, 1), gem(2, 9), gem(3, 9), gem(4, 6), boss(46), sp(168), normal(1, 18), normal(2, 30), normal(3, 36), money(42)] +}] + +const CharMeta = { + getAttrList (base, grow, elem = '') { + let ret = [] + lodash.forEach(base, (v, k) => { + ret.push({ + title: baseAttrName[k], + value: Format.comma(v, 1) + }) + }) + ret.push({ + title: '成长·' + (grow.key === 'dmg' ? `${elem}伤` : growAttrName[grow.key]), + value: grow.value.toString().length > 10 ? Format.comma(grow.value, 1) : grow.value + }) + return ret + }, + getMaterials (char, type = 'all') { + let ds = char.meta.materials + let ret = [] + lodash.forEach(mKeys, (cfg) => { + let title = ds[cfg.key] + let mat = Material.get(title) + if (!mat) { + return true + } + if (cfg.check && !cfg.check(char)) { + return true + } + if (type !== 'all' && mat.type !== type) { + return true + } + ret.push({ + ...mat.getData('label,star,icon,type'), + num: cfg.num || mat.getSource() || '' + }) + }) + return type === 'all' ? ret : ret[0] + }, + + getDesc (desc) { + desc = desc.replace(/。$/, '') + desc = desc.replace('</br>', ',') + desc = desc.replace(/[。,]/g, ',') + desc = desc.replace('——', ',——') + let len = desc.length + if (len < 25) { + return desc + } + if (/-/.test(desc)) { + let idx = desc.indexOf('—') + return [desc.substr(0, idx), desc.substr(idx, desc.length)].join('</br>') + } + desc = desc.split(',') + return CharMeta.getDescLine(desc) + }, + getDescLine (inputs) { + let lens = [] + let len = 0 + let descs = [] + const maxChars = 26 + for (let desc of inputs) { + if (len + desc.length < maxChars * 2) { + lens.push(desc.length) + descs.push(desc) + len += desc.length + } else { + break + } + } + if (len <= maxChars - 6) { + return descs.join(',') + } + let ret = [[], []] + let idx = 0 + for (let desc of descs) { + if (ret[idx].join(' ').length + desc.length > maxChars) { + idx++ + } + ret[idx] = ret[idx] || [] + ret[idx].push(desc) + if (descs.length === 2) { + idx++ + } + } + return ret[0].join(',') + '</br>' + ret[1].join(',') + } +} +export default CharMeta diff --git a/Yunzai/plugins/miao-plugin/models/character/CharTalent.js b/Yunzai/plugins/miao-plugin/models/character/CharTalent.js new file mode 100644 index 0000000000000000000000000000000000000000..7118e91a48f26307b2f5e3609d61f8c9a9703b90 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/character/CharTalent.js @@ -0,0 +1,57 @@ +/** + * 角色天赋相关处理 + * */ +import lodash from 'lodash' + +const CharTalent = { + // 处理获取天赋数据 + getAvatarTalent (char, talent, cons, mode) { + let { id, talentCons, game, isGs } = char + let ret = {} + let addTalent = { + gs: { a: 3, e: 3, q: 3 }, + sr: { a: 1, e: 2, q: 2, t: 2 } + } + lodash.forEach(addTalent[game], (addNum, key) => { + let ds = talent[key] + if (!ds) { + return false + } + let value + let level + let original + let aPlus = id === 10000033 + if (lodash.isNumber(ds)) { + value = ds + } + if (mode !== 'level') { + // 基于original计算level + value = value || ds.original || ds.level_original || ds.level || ds.level_current + if (value > 10 && isGs) { + mode = 'level' + } else { + original = value + if (key === 'a' && isGs) { + level = aPlus ? value + 1 : value + } + level = (talentCons[key] > 0 && cons >= talentCons[key]) ? (value + addNum) : value + } + } + if (mode === 'level') { + // 基于level计算original + value = value || ds.level || ds.level_current || ds.original || ds.level_original + level = value + if (key === 'a' && isGs) { + original = aPlus ? value - 1 : value + } + original = (talentCons[key] > 0 && cons >= talentCons[key]) ? (value - addNum) : value + } + ret[key] = { level, original } + }) + if (lodash.isEmpty(ret)) { + return false + } + return ret + } +} +export default CharTalent diff --git a/Yunzai/plugins/miao-plugin/models/index.js b/Yunzai/plugins/miao-plugin/models/index.js new file mode 100644 index 0000000000000000000000000000000000000000..ee26053ec5b2c9f0e5ddb74c3f2150aeadf95c8f --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/index.js @@ -0,0 +1,41 @@ +import Base from './Base.js' +import Character from './Character.js' +import Artifact from './Artifact.js' +import ArtifactSet from './ArtifactSet.js' +import AvatarData from './AvatarData.js' +import AvatarArtis from './AvatarArtis.js' +import Abyss from './Abyss.js' +import Player from './Player.js' +import ProfileServ from './ProfileServ.js' +import ProfileReq from './ProfileReq.js' +import ProfileData from './ProfileData.js' +import ProfileArtis from './ProfileArtis.js' +import ProfileAttr from './ProfileAttr.js' +import ProfileDmg from './ProfileDmg.js' +import ProfileRank from './ProfileRank.js' +import Material from './Material.js' +import Weapon from './Weapon.js' +import User from './User.js' +import MysApi from './MysApi.js' + +export { + Base, + Abyss, + Character, + Artifact, + ArtifactSet, + AvatarData, + AvatarArtis, + ProfileServ, + ProfileReq, + ProfileData, + ProfileArtis, + ProfileAttr, + ProfileDmg, + ProfileRank, + Material, + Weapon, + User, + MysApi, + Player +} diff --git a/Yunzai/plugins/miao-plugin/models/material/MaterialMeta.js b/Yunzai/plugins/miao-plugin/models/material/MaterialMeta.js new file mode 100644 index 0000000000000000000000000000000000000000..61209af671247cc32cfc279d2f202f110bb23cd6 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/material/MaterialMeta.js @@ -0,0 +1,55 @@ +import lodash from 'lodash' +import { Data } from '#miao' + +const talentMeta = { + 自由: { week: 1, city: '蒙德', cid: 1 }, + 繁荣: { week: 1, city: '璃月', cid: 2 }, + 浮世: { week: 1, city: '稻妻', cid: 3 }, + 诤言: { week: 1, city: '须弥', cid: 4 }, + 公平: { week: 1, city: '枫丹', cid: 5 }, + + 抗争: { week: 2, city: '蒙德', cid: 1 }, + 勤劳: { week: 2, city: '璃月', cid: 2 }, + 风雅: { week: 2, city: '稻妻', cid: 3 }, + 巧思: { week: 2, city: '须弥', cid: 4 }, + 正义: { week: 2, city: '枫丹', cid: 5 }, + + 诗文: { week: 3, city: '蒙德', cid: 1 }, + 黄金: { week: 3, city: '璃月', cid: 2 }, + 天光: { week: 3, city: '稻妻', cid: 3 }, + 笃行: { week: 3, city: '须弥', cid: 4 }, + 秩序: { week: 3, city: '枫丹', cid: 5 } +} + +const talentReg = new RegExp(`(${lodash.keys(talentMeta).join('|')})`) + +let MaterialMeta = { + getTalentData (talent) { + talent = MaterialMeta.getTalentKey(talent) + return talentMeta[talent] + }, + getTalentKey (name) { + return Data.regRet(talentReg, name, 1) || name + }, + getTalentLabel (t) { + let key = MaterialMeta.getTalentKey(t) + let tm = MaterialMeta.getTalentData(key) + if (!tm) { + return t + } + return `${tm.city}·${key}` + }, + getTalentWeek (t) { + let tm = MaterialMeta.getTalentData(t) + switch (tm.week) { + case 1: + return '周一/周四' + case 2: + return '周二/周五' + case 3: + return '周三/周六' + } + return '' + } +} +export default MaterialMeta diff --git a/Yunzai/plugins/miao-plugin/models/player/AvocadoApi.js b/Yunzai/plugins/miao-plugin/models/player/AvocadoApi.js new file mode 100644 index 0000000000000000000000000000000000000000..842a3758bbbb8a9800d43d2ee421d1f6881ce5c0 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/AvocadoApi.js @@ -0,0 +1,112 @@ +import lodash from 'lodash' +import { Data } from '#miao' +import { Character } from '#miao.models' + +/** + * 鳄梨 + */ +export default { + id: 'avocado', + name: 'avocado.wiki', + cfgKey: 'avocadoApi', + // 处理请求参数 + async request (api) { + let params = { + headers: { 'User-Agent': this.getCfg('userAgent') } + } + return { api, params } + }, + + // 处理服务返回 + async response (data, req) { + if (!data.playerDetailInfo) { + return req.err('error', 60) + } + let ds = data.playerDetailInfo + let ac = ds.assistAvatar + let avatars = {} + if (ac && !lodash.isEmpty(ac)) { + avatars[ac.avatarId] = ac + } + lodash.forEach(ds.displayAvatars, (ds) => { + avatars[ds.avatarId] = ds + }) + + if (lodash.isEmpty(avatars)) { + return req.err('empty', 5 * 60) + } + ds.avatars = avatars + return ds + }, + + updatePlayer (player, data) { + try { + player.setBasicData(Data.getData(data, 'name:nickname,face:headIconID,level:level,word:level,sign:signature')) + lodash.forEach(data.avatars, (ds, id) => { + let ret = AvocadoData.setAvatar(player, ds) + if (ret) { + player._update.push(ds.avatarId) + } + }) + } catch (e) { + console.log(e) + } + }, + + // 获取冷却时间 + cdTime (data) { + return data.ttl || 60 + } +} + +const AvocadoData = { + setAvatar (player, data) { + let char = Character.get(data.avatarId) + if (!char) { + return false + } + let avatar = player.getAvatar(char.id, true) + let setData = { + level: data.level, + promote: data.promotion, + cons: data.rank || 0, + weapon: Data.getData(data.equipment, 'id:id,promote:promotion,level,affix:rank'), + ...AvocadoData.getTalent(data.behaviorList, char), + artis: AvocadoData.getArtis(data.relics) + } + avatar.setAvatar(setData, 'avocado.wiki') + return avatar + }, + getTalent (ds, char) { + let talent = {} + let trees = [] + lodash.forEach(ds, (d) => { + let key = char.getTalentKey(d.id) + if (key || d.level > 1) { + talent[key || d.id] = d.level + } else { + trees.push(d.id) + } + }) + return { talent, trees } + }, + getArtis (artis) { + let ret = {} + lodash.forEach(artis, (ds) => { + let tmp = { + id: ds.id, + level: ds.level || 1, + mainId: ds.main_affix_id, + attrIds: [] + } + lodash.forEach(ds.sub_affix_id, (s) => { + if (!s.id) { + return true + } + tmp.attrIds.push([s.id, s.cnt, s.step || 0].join(',')) + }) + ret[ds.type] = tmp + }) + return ret + } +} diff --git a/Yunzai/plugins/miao-plugin/models/player/EnkaApi.js b/Yunzai/plugins/miao-plugin/models/player/EnkaApi.js new file mode 100644 index 0000000000000000000000000000000000000000..b46ad8488a197551591d035877fd12c31bc1ca66 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/EnkaApi.js @@ -0,0 +1,59 @@ +import lodash from 'lodash' +import EnkaData from './EnkaData.js' +import { Data } from '#miao' + +let HttpsProxyAgent = '' + +export default { + id: 'enka', + cfgKey: 'enkaApi', + // 处理请求参数 + async request (api) { + let params = { + headers: { 'User-Agent': this.getCfg('userAgent') } + } + let proxy = this.getCfg('proxyAgent') + if (proxy) { + if (HttpsProxyAgent === '') { + HttpsProxyAgent = await import('https-proxy-agent').catch((err) => { + logger.error(err) + }) + HttpsProxyAgent = HttpsProxyAgent ? HttpsProxyAgent.HttpsProxyAgent : undefined + } + if (HttpsProxyAgent) { + params.agent = new HttpsProxyAgent(proxy) + } + } + return { api, params } + }, + + // 处理服务返回 + async response (data, req) { + if (!data.playerInfo) { + if (data.error) { + console.log(`Enka ReqErr: ${data.error}`) + } + return req.err('error', 60) + } + let details = data.avatarInfoList + if (!details || details.length === 0 || !details[0].propMap) { + return req.err('empty', 5 * 60) + } + return data + }, + + updatePlayer (player, data) { + player.setBasicData(Data.getData(data, 'name:nickname,face:profilePicture.avatarID,card:nameCardID,level,word:worldLevel,sign:signature')) + lodash.forEach(data.avatarInfoList, (ds) => { + let ret = EnkaData.setAvatar(player, ds) + if (ret) { + player._update.push(ret.id) + } + }) + }, + + // 获取冷却时间 + cdTime (data) { + return data.ttl || 60 + } +} diff --git a/Yunzai/plugins/miao-plugin/models/player/EnkaData.js b/Yunzai/plugins/miao-plugin/models/player/EnkaData.js new file mode 100644 index 0000000000000000000000000000000000000000..b0dea8b5cc373e9db169059067825856fbb6d340 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/EnkaData.js @@ -0,0 +1,126 @@ +import lodash from 'lodash' +import { attrMap, idsMap, artisIdxMap } from './ProfileMeta.js' +import { Character, ArtifactSet, Weapon } from '../index.js' + +let EnkaData = { + setAvatar (player, data, dataSource = 'enka') { + let char = Character.get(data.avatarId) + if (!char) { + return + } + let avatar = player.getAvatar(char.id, true) + let talentRet = EnkaData.getTalent(char.id, data.skillLevelMap) + avatar.setAvatar({ + level: data.propMap['4001'].val * 1, + promote: data.propMap['1002'].val * 1, + cons: data.talentIdList ? data.talentIdList.length : 0, + fetter: data.fetterInfo.expLevel, + costume: char.checkCostume(data.costumeId) ? data.costumeId : 0, + elem: talentRet.elem, + weapon: EnkaData.getWeapon(data.equipList), + talent: talentRet.talent, + artis: EnkaData.getArtifact(data.equipList) + }, dataSource) + return avatar + }, + + getWeapon (data) { + let ds = {} + lodash.forEach(data, (temp) => { + if (temp.flat && temp.flat.itemType === 'ITEM_WEAPON') { + ds = temp + return false + } + }) + let { weapon } = ds + let w = Weapon.get(ds.itemId) + return { + name: w ? w.name : '', + level: weapon.level, + promote: weapon.promoteLevel, + affix: (lodash.values(weapon.affixMap)[0] || 0) + 1 + } + }, + + getTalent (charid, ds = {}) { + let char = Character.get(charid) + let { talentId = {}, talentElem = {} } = char.meta + let elem = '' + let idx = 0 + let ret = {} + lodash.forEach(ds, (lv, id) => { + let key + if (talentId[id]) { + let key = talentId[id] + elem = elem || talentElem[id] + ret[key] = lv + } else { + key = ['a', 'e', 'q'][idx++] + ret[key] = ret[key] || lv + } + }) + return { + elem: elem, + talent: ret + } + }, + + getArtifact (data) { + let ret = {} + lodash.forEach(data, (ds) => { + let flat = ds.flat || {} + let re = ds.reliquary + let idx = artisIdxMap[flat.equipType] + if (!idx) { + return + } + let setName = idsMap[flat.setNameTextMapHash] || '' + ret[idx] = { + name: ArtifactSet.getArtiNameBySet(setName, idx), + level: Math.min(20, ((re.level) || 1) - 1), + star: flat.rankLevel || 5, + mainId: re.mainPropId, + attrIds: re.appendPropIdList + } + }) + return ret + }, + + getArtifactBak (data) { + let ret = {} + let get = function (d) { + if (!d) { + return {} + } + let id = d.appendPropId || d.mainPropId || '' + id = id.replace('FIGHT_PROP_', '') + if (!attrMap[id]) { + return {} + } + return { key: attrMap[id], value: d.statValue } + } + lodash.forEach(data, (ds) => { + let flat = ds.flat || {} + let sub = flat.reliquarySubstats || [] + let idx = artisIdxMap[flat.equipType] + if (!idx) { + return + } + let setName = idsMap[flat.setNameTextMapHash] || '' + ret[idx] = { + name: ArtifactSet.getArtiNameBySet(setName, idx), + level: Math.min(20, ((ds.reliquary && ds.reliquary.level) || 1) - 1), + main: get(flat.reliquaryMainstat), + attrs: [ + get(sub[0]), + get(sub[1]), + get(sub[2]), + get(sub[3]) + ] + } + }) + return ret + } +} + +export default EnkaData diff --git a/Yunzai/plugins/miao-plugin/models/player/EnkaHSRApi.js b/Yunzai/plugins/miao-plugin/models/player/EnkaHSRApi.js new file mode 100644 index 0000000000000000000000000000000000000000..f2e9ad75ef8fa0cc8cf6d50b743bfc232d84da50 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/EnkaHSRApi.js @@ -0,0 +1,109 @@ +import lodash from 'lodash' +import { Data } from '#miao' +import { Character } from '#miao.models' + +export default { + id: 'enkahsr', + name: 'EnkaHSR', + cfgKey: 'enkaHSRApi', + // 处理请求参数 + async request (api) { + let params = { + headers: { 'User-Agent': this.getCfg('userAgent') } + } + return { api, params } + }, + + // 处理服务返回 + async response (data, req) { + if (!data.detailInfo) { + return req.err('error', 60) + } + let ds = data.detailInfo + let ac = ds.assistAvatarDetail + let avatars = {} + if (ac && !lodash.isEmpty(ac)) { + avatars[ac.AvatarID] = ac + } + lodash.forEach(ds.avatarDetailList, (ds) => { + avatars[ds.avatarId] = ds + }) + + if (lodash.isEmpty(avatars)) { + return req.err('empty', 5 * 60) + } + ds.avatars = avatars + return ds + }, + + updatePlayer (player, data) { + try { + player.setBasicData(Data.getData(data, 'name:nickname,face:headIcon,level:level,word:level,sign:signature')) + lodash.forEach(data.avatars, (ds, id) => { + let ret = HomoData.setAvatar(player, ds) + if (ret) { + player._update.push(ds.avatarId) + } + }) + } catch (e) { + console.log(e) + } + }, + + // 获取冷却时间 + cdTime (data) { + return data.ttl || 60 + } +} + +const HomoData = { + setAvatar (player, data) { + let char = Character.get(data.avatarId) + if (!char) { + return false + } + let avatar = player.getAvatar(char.id, true) + let setData = { + level: data.level, + promote: data.promotion, + cons: data.rank || 0, + weapon: Data.getData(data.equipment, 'id:tid,promote:promotion,level,affix:rank'), + ...HomoData.getTalent(data.skillTreeList, char), + artis: HomoData.getArtis(data.relicList) + } + avatar.setAvatar(setData, 'EnkaHSR') + return avatar + }, + getTalent (ds, char) { + let talent = {} + let trees = [] + lodash.forEach(ds, (d) => { + let key = char.getTalentKey(d.pointId) + if (key || d.Level > 1) { + talent[key || d.pointId] = d.level + } else { + trees.push(d.pointId) + } + }) + return { talent, trees } + }, + getArtis (artis) { + let ret = {} + lodash.forEach(artis, (ds) => { + let tmp = { + id: ds.tid, + level: ds.level || 1, + mainId: ds.mainAffixId, + attrIds: [] + } + lodash.forEach(ds.subAffixList, (s) => { + if (!s.affixId) { + return true + } + tmp.attrIds.push([s.affixId, s.cnt, s.step || 0].join(',')) + }) + ret[ds.type] = tmp + }) + return ret + } +} diff --git a/Yunzai/plugins/miao-plugin/models/player/HomoApi.js b/Yunzai/plugins/miao-plugin/models/player/HomoApi.js new file mode 100644 index 0000000000000000000000000000000000000000..ff27faab092e407fc00c486580a15978b3377470 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/HomoApi.js @@ -0,0 +1,109 @@ +import lodash from 'lodash' +import { Data } from '#miao' +import { Character } from '#miao.models' + +export default { + id: 'homo', + name: 'Mihomo', + cfgKey: 'homoApi', + // 处理请求参数 + async request (api) { + let params = { + headers: { 'User-Agent': this.getCfg('userAgent') } + } + return { api, params } + }, + + // 处理服务返回 + async response (data, req) { + if (!data.detailInfo) { + return req.err('error', 60) + } + let ds = data.detailInfo + let ac = ds.assistAvatarDetail + let avatars = {} + if (ac && !lodash.isEmpty(ac)) { + avatars[ac.AvatarID] = ac + } + lodash.forEach(ds.avatarDetailList, (ds) => { + avatars[ds.avatarId] = ds + }) + + if (lodash.isEmpty(avatars)) { + return req.err('empty', 5 * 60) + } + ds.avatars = avatars + return ds + }, + + updatePlayer (player, data) { + try { + player.setBasicData(Data.getData(data, 'name:nickname,face:headIcon,level:level,word:level,sign:signature')) + lodash.forEach(data.avatars, (ds, id) => { + let ret = HomoData.setAvatar(player, ds) + if (ret) { + player._update.push(ds.avatarId) + } + }) + } catch (e) { + console.log(e) + } + }, + + // 获取冷却时间 + cdTime (data) { + return data.ttl || 60 + } +} + +const HomoData = { + setAvatar (player, data) { + let char = Character.get(data.avatarId) + if (!char) { + return false + } + let avatar = player.getAvatar(char.id, true) + let setData = { + level: data.level, + promote: data.promotion, + cons: data.rank || 0, + weapon: Data.getData(data.equipment, 'id:tid,promote:promotion,level,affix:rank'), + ...HomoData.getTalent(data.skillTreeList, char), + artis: HomoData.getArtis(data.relicList) + } + avatar.setAvatar(setData, 'homo') + return avatar + }, + getTalent (ds, char) { + let talent = {} + let trees = [] + lodash.forEach(ds, (d) => { + let key = char.getTalentKey(d.pointId) + if (key || d.Level > 1) { + talent[key || d.pointId] = d.level + } else { + trees.push(d.pointId) + } + }) + return { talent, trees } + }, + getArtis (artis) { + let ret = {} + lodash.forEach(artis, (ds) => { + let tmp = { + id: ds.tid, + level: ds.level || 1, + mainId: ds.mainAffixId, + attrIds: [] + } + lodash.forEach(ds.subAffixList, (s) => { + if (!s.affixId) { + return true + } + tmp.attrIds.push([s.affixId, s.cnt, s.step || 0].join(',')) + }) + ret[ds.type] = tmp + }) + return ret + } +} diff --git a/Yunzai/plugins/miao-plugin/models/player/HutaoApi.js b/Yunzai/plugins/miao-plugin/models/player/HutaoApi.js new file mode 100644 index 0000000000000000000000000000000000000000..71e0044c43b8e906762540f2614a3b8f2a5f19bf --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/HutaoApi.js @@ -0,0 +1,46 @@ +import lodash from 'lodash' +import EnkaData from './EnkaData.js' +import { Data } from '#miao' + +export default { + id: 'hutao', + name: 'Hutao-Enka', + cfgKey: 'hutaoApi', + // 处理请求参数 + async request (api) { + let params = { + headers: { 'User-Agent': this.getCfg('userAgent') } + } + return { api, params } + }, + + // 处理服务返回 + async response (data, req) { + if (!data.playerInfo) { + if (data.error) { + console.log(`Enka ReqErr: ${data.error}`) + } + return req.err('error', 60) + } + let details = data.avatarInfoList + if (!details || details.length === 0 || !details[0].propMap) { + return req.err('empty', 5 * 60) + } + return data + }, + + updatePlayer (player, data) { + player.setBasicData(Data.getData(data, 'name:nickname,face:profilePicture.avatarID,card:nameCardID,level,word:worldLevel,sign:signature')) + lodash.forEach(data.avatarInfoList, (ds) => { + let ret = EnkaData.setAvatar(player, ds, 'hutao') + if (ret) { + player._update.push(ret.id) + } + }) + }, + + // 获取冷却时间 + cdTime (data) { + return data.ttl || 60 + } +} diff --git a/Yunzai/plugins/miao-plugin/models/player/MggApi.js b/Yunzai/plugins/miao-plugin/models/player/MggApi.js new file mode 100644 index 0000000000000000000000000000000000000000..a0688a81d45c2c958cc8d97a47feb8d456c97082 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/MggApi.js @@ -0,0 +1,46 @@ +import lodash from 'lodash' +import EnkaData from './EnkaData.js' +import { Data } from '#miao' + +export default { + id: 'mgg', + name: 'MiniGG-Api', + cfgKey: 'mggApi', + // 处理请求参数 + async request (api) { + let params = { + headers: { 'User-Agent': this.getCfg('userAgent') } + } + return { api, params } + }, + + // 处理服务返回 + async response (data, req) { + if (!data.playerInfo) { + if (data.error) { + console.log(`Enka ReqErr: ${data.error}`) + } + return req.err('error', 60) + } + let details = data.avatarInfoList + if (!details || details.length === 0 || !details[0].propMap) { + return req.err('empty', 5 * 60) + } + return data + }, + + updatePlayer (player, data) { + player.setBasicData(Data.getData(data, 'name:nickname,face:profilePicture.avatarID,card:nameCardID,level,word:worldLevel,sign:signature')) + lodash.forEach(data.avatarInfoList, (ds) => { + let ret = EnkaData.setAvatar(player, ds, 'mgg') + if (ret) { + player._update.push(ret.id) + } + }) + }, + + // 获取冷却时间 + cdTime (data) { + return data.ttl || 60 + } +} diff --git a/Yunzai/plugins/miao-plugin/models/player/MiaoApi.js b/Yunzai/plugins/miao-plugin/models/player/MiaoApi.js new file mode 100644 index 0000000000000000000000000000000000000000..8904453704fbb018b7fa519c0be9a3604194d0c3 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/MiaoApi.js @@ -0,0 +1,50 @@ +import lodash from 'lodash' +import MiaoData from './MiaoData.js' +import { Data } from '#miao' + +export default { + key: 'miao', + name: '喵喵Api', + cfgKey: 'miaoApi', + async request (api) { + api = this.getCfg('api') || api + return { api } + }, + async response (data, req, game = 'gs') { + if (data.status !== 0) { + return req.err(data.msg || 'error', 60) + } + if (game === 'sr') { + return data.data + } + if (data.version === 2) { + data = data.data || {} + if (!data.avatars || data.avatars.length === 0) { + return req.err('empty', 5 * 60) + } + data.version = 2 + return data + } else { + return req.err('empty', 5 * 60) + } + }, + + updatePlayer (player, data) { + player.setBasicData(data) + lodash.forEach(data.avatars, (avatar) => { + let ret = MiaoData.setAvatar(player, avatar) + if (ret) { + player._update.push(ret.id) + } + }) + }, + + // 获取冷却时间 + cdTime (data = {}) { + if (data.cacheExpireAt) { + let exp = Math.max(0, Math.round(data.cacheExpireAt - (new Date() / 1000))) + return Math.max(60, exp) + } + return 60 + } +} diff --git a/Yunzai/plugins/miao-plugin/models/player/MiaoData.js b/Yunzai/plugins/miao-plugin/models/player/MiaoData.js new file mode 100644 index 0000000000000000000000000000000000000000..3733ec3a3eca95b1a05f436d2785b4d8d18f53d9 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/MiaoData.js @@ -0,0 +1,66 @@ +import { Character } from '../index.js' +import lodash from 'lodash' + +import { attrMap, artisIdxMap } from './ProfileMeta.js' + +let MiaoData = { + setAvatar (player, ds) { + let char = Character.get(ds.id) + let avatar = player.getAvatar(ds.id, true) + if (!char) { + return false + } + if (player.isSr) { + avatar.setAvatar({ + ...ds, + ...MiaoData.getTalentSR(char, ds.talent) + }, 'miao') + } else { + let talentRet = MiaoData.getTalent(char, ds.talent) + avatar.setAvatar({ + ...ds, + elem: talentRet.elem, + talent: talentRet.talent + }, 'miao') + } + return avatar + }, + + getTalent (char, data = {}) { + let { talentId = {}, talentElem = {} } = char.meta + let elem = '' + let idx = 0 + let ret = {} + lodash.forEach(data, (level, id) => { + let key + if (talentId[id]) { + key = talentId[id] + elem = elem || talentElem[id] + ret[key] = level + } else { + key = ['a', 'e', 'q'][idx] + ret[key] = level + } + idx++ + }) + return { + talent: ret, + elem + } + }, + + getTalentSR (char, data) { + let talent = {} + let trees = [] + lodash.forEach(data, (lv, id) => { + let key = char.getTalentKey(id) + if (key || lv > 1) { + talent[key || id] = lv + } else { + trees.push(id) + } + }) + return { talent, trees } + } +} +export default MiaoData diff --git a/Yunzai/plugins/miao-plugin/models/player/MysAvatar.js b/Yunzai/plugins/miao-plugin/models/player/MysAvatar.js new file mode 100644 index 0000000000000000000000000000000000000000..c61e32b52ca6a4154e14e34544d13eb94748293f --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/MysAvatar.js @@ -0,0 +1,331 @@ +import lodash from 'lodash' +import moment from 'moment' +import { Data } from '#miao' +import { chestInfo } from '../../resources/meta/info/index.js' + + +const MysAvatar = { + + needRefresh (time, force = 0, forceMap = {}) { + if (!time || force === 2) { + return true + } + if (force === true) { + force = 0 + } + let duration = (new Date() * 1 - time * 1) / 1000 + if (isNaN(duration) || duration < 0) { + return true + } + let reqTime = forceMap[force] === 0 ? 0 : (forceMap[force] || 60) + return duration > reqTime * 60 + }, + checkForce (player, force) { + let e = player?.e + let mys = e?._mys + if (!e || !mys || !mys.isSelfCookie) { + return force + } + let ck = mys?.ckInfo?.ck + if (!ck || player._ck === ck) { + return force + } + player._info = 0 + player._mys = 0 + lodash.forEach(player._avatars, (ds) => { + ds._talent = 0 + }) + return 2 + }, + /** + * 更新米游社角色信息 + * @param player + * @param force + * @returns {Promise<boolean>} + */ + async refreshMysDetail (player, force = 0) { + let e = player.e || {} + let mys = e?._mys + if (!mys) { + return false + } + if (!MysAvatar.needRefresh(player._mys, force, { 0: 60, 1: 2, 2: 0 })) { + return false + } + let charData = await mys.getCharacter() + MysAvatar.setMysCharData(player, charData) + }, + + /** + * 更新米游社统计信息 + * @param player + * @param force + * @returns {Promise<boolean>} + */ + async refreshMysInfo (player, force = 0) { + let mys = player?.e?._mys + if (!mys) { + return false + } // 不必要更新 + if (!MysAvatar.needRefresh(player._info, force, { 0: 60, 1: 2, 2: 0 })) { + return false + } + let infoData = await mys.getIndex() + if (!infoData || !infoData.role) { + return false + } + MysAvatar.setMysInfo(player, infoData) + }, + + /** + * 根据已有Mys CharData更新player + * @param player + * @param charData + */ + setMysCharData (player, charData) { + if (charData && charData.avatars) { + let role = charData.role || {} + player.setBasicData({ + level: role.level, + name: role.nickname + }) + let charIds = {} + lodash.forEach(charData.avatars, (ds) => { + let avatar = Data.getData(ds, 'id,level,cons:actived_constellation_num,fetter') + avatar.elem = ds.element.toLowerCase() + // 处理时装数据 + let costume = (ds?.costumes || [])[0] + if (costume && costume.id) { + avatar.costume = costume.id + } + avatar.weapon = Data.getData(ds.weapon, 'name,star:rarity,level,promote:promote_level,affix:affix_level') + // 处理圣遗物数据 + let artis = {} + lodash.forEach(ds.reliquaries, (re) => { + const posIdx = { 生之花: 1, 死之羽: 2, 时之沙: 3, 空之杯: 4, 理之冠: 5 } + if (re && re.name && posIdx[re.pos_name]) { + artis[posIdx[re.pos_name]] = { + name: re.name, + level: re.level + } + } + }) + avatar.artis = artis + player.setAvatar(avatar, 'mys') + charIds[avatar.id] = true + }) + // 若角色数据>8,检查缓存,删除错误缓存的数据 + if (lodash.keys(charIds).length > 8) { + player.forEachAvatar((avatar) => { + if (!charIds[avatar.id] && !avatar.isProfile) { + delete player._avatars[avatar.id] + } + }) + } + } + if (player._avatars && !lodash.isEmpty(player._avatars)) { + player._mys = new Date() * 1 + player.save() + } + }, + + setMysInfo (player, infoData) { + let role = infoData.role + // 设置角色信息 + let homeLevel = ((infoData?.homes || [])[0])?.level + if (role) { + player.setBasicData({ + level: role.level, + name: role.nickname + }) + } + // 设置角色数据 + lodash.forEach(infoData?.avatars || [], (ds) => { + let avatar = Data.getData(ds, 'id,level,cons:actived_constellation_num,fetter') + avatar.elem = ds.element.toLowerCase() + player.setAvatar(avatar, 'mys') + }) + let stats = {} + lodash.forEach(infoData?.stats || [], (num, key) => { + key = key.replace('_number', '') + if (key !== 'spiral_abyss') { + stats[lodash.camelCase(key)] = num + } + }) + + let exploration = {} + lodash.forEach(infoData?.world_explorations || [], (ds) => { + let { name } = ds + if (name === '层岩巨渊') { + return true + } + exploration[name === '层岩巨渊·地下矿区' ? '层岩巨渊' : name] = ds.exploration_percentage + }) + player.info = { + homeLevel, + stats, + exploration + } + player._info = new Date() * 1 + player.save() + }, + + /** + * 获取当前角色需要更新天赋的角色ID + * @param player + * @param ids 角色列表,若传入则查询指定角色列表,不传入查询全部 + * @param force + * @returns {*[]} + */ + getNeedRefreshIds (player, ids, force = 0) { + let ret = [] + if (!ids) { + ids = lodash.keys(player._avatars) + } else if (!lodash.isArray(ids)) { + ids = [ids] + } + lodash.forEach(ids, (id) => { + let avatar = player.getAvatar(id) + if (!avatar) { + return true + } + let needMap = { 0: avatar.hasTalent ? 60 * 48 : 60 * 3, 1: 60, 2: 0 } + if (MysAvatar.needRefresh(avatar._talent, force, needMap)) { + ret.push(avatar.id) + } + }) + return ret + }, + + /** + * 使用MysApi刷新指定角色的天赋信息 + * @param player + * @param ids + * @param force + * @returns {Promise<boolean>} + */ + async refreshTalent (player, ids, force = 0) { + let e = player?.e + let mys = e?._mys + if (!e || !mys || !mys.isSelfCookie) { + return false + } + force = MysAvatar.checkForce(player, force) + let needReqIds = MysAvatar.getNeedRefreshIds(player, ids, force) + if (needReqIds.length > 0) { + if (needReqIds.length > 8) { + e && e.reply('正在获取角色信息,请稍候...') + } + let failCount = 0 + // 并发5,请求天赋数据 + await Data.asyncPool(5, needReqIds, async (id) => { + let avatar = player.getAvatar(id) + if (!avatar) { + return false + } + if (failCount > 5) { + avatar.setTalent(false, 'original', true) + return false + } + let ret = await MysAvatar.refreshAvatarTalent(avatar, mys) + if (ret === false) { + failCount++ + } + }) + } + player.save() + return true + }, + + async refreshAvatarTalent (avatar, mys) { + if (mys && mys.isSelfCookie) { + let char = avatar.char + if (!char) { + return false + } + let id = char.id + let talent = {} + let talentRes = await mys.getDetail(id) + // { data: null, message: '请先登录', retcode: -100, api: 'detail' } + if (talentRes && talentRes.skill_list) { + let talentList = lodash.orderBy(talentRes.skill_list, ['id'], ['asc']) + for (let val of talentList) { + let { max_level: maxLv, level_current: lv } = val + if (val.name.includes('普通攻击')) { + talent.a = lv + continue + } + if (maxLv >= 10 && !talent.e) { + talent.e = lv + continue + } + if (maxLv >= 10 && !talent.q) { + talent.q = lv + } + } + } + let ret = char.getAvatarTalent(talent, avatar.cons, 'original') + avatar.setTalent(ret, 'original', true) + return !!ret + } + return false + }, + + getDate (time) { + return time ? moment(new Date(time)).format('MM-DD HH:mm') : '' + }, + + getInfo (player) { + let chestMap = [] + Data.eachStr('common,exquisite,precious,luxurious,magic', (key) => { + chestMap.push({ + key: `${key}Chest`, + ...chestInfo[key] + }) + }) + let ret = { + ...(player.info || {}), + chestMap + } + let stats = ret.stats || {} + if (stats?.activeDay) { + let num = stats?.activeDay + let year = Math.floor(num / 365) + let month = Math.floor((num % 365) / 30.41) + let day = Math.floor((num % 365) % 30.41) + let msg = '' + if (year > 0) { + msg += year + '年' + } + if (month > 0) { + msg += month + '个月' + } + if (day > 0) { + msg += day + '天' + } + ret.activeDay = msg + } + let avatarCount = 0 + let avatar5Count = 0 + let goldCount = 0 + player.forEachAvatar((avatar) => { + avatarCount++ + if (avatar.star === 5) { + avatar5Count++ + if (!avatar.char?.isTraveler) { + goldCount += (avatar.cons || 0) + 1 + } + } + let w = avatar.weapon + if (w && w.star === 5) { + goldCount += w.affix * 1 + } + }) + stats.avatar = Math.max(stats.avatar, avatarCount) + stats.goldCount = goldCount + stats.avatar5 = avatar5Count + ret.stats = stats + return ret + } +} +export default MysAvatar diff --git a/Yunzai/plugins/miao-plugin/models/player/Profile.js b/Yunzai/plugins/miao-plugin/models/player/Profile.js new file mode 100644 index 0000000000000000000000000000000000000000..580560cccbdbf2851e3a5c1f04bd008eb8e013a6 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/Profile.js @@ -0,0 +1,137 @@ +import { ProfileReq, ProfileServ } from '../index.js' +import { Cfg, Data } from '#miao' +import MysAvatar from './MysAvatar.js' + +import enkaApi from './EnkaApi.js' +import miaoApi from './MiaoApi.js' +import mggApi from './MggApi.js' +import hutaoApi from './HutaoApi.js' +import homoApi from './HomoApi.js' + +import lodash from 'lodash' +import avocadoApi from './AvocadoApi.js' +import enkaHSRApi from './EnkaHSRApi.js' + +let { diyCfg } = await Data.importCfg('profile') + +const Profile = { + servs: {}, + serv (key) { + if (!Profile.servs[key]) { + Profile.servs[key] = new ProfileServ({ + miao: miaoApi, + mgg: mggApi, + enka: enkaApi, + hutao: hutaoApi, + homo: homoApi, + avocado: avocadoApi, + enkaHSR: enkaHSRApi + }[key]) + } + return Profile.servs[key] + }, + + /** + * 根据UID分配请求服务器 + * @param uid + * @param game + * @returns {ProfileServ} + */ + getServ (uid, game = 'gs') { + let token = diyCfg?.miaoApi?.token + let qq = diyCfg?.miaoApi?.qq + let hasToken = !!(qq && token && token.length === 32 && !/^test/.test(token)) + let isGs = game === 'gs' + + // 根据uid判断当前服务器类型。官服0 B服1 国际2 + let servType = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2 }[uid[0]] + + // 获取原神、星铁对应服务选择的配置 + let servCfg = Cfg.get(isGs ? 'profileServer' : 'srProfileServer', '0').toString() || '0' + let servIdx = servCfg[servType] || servCfg[0] || '0' + + // 设置为自动或1时,如果具备token则使用miao + if ((servIdx === '0' || servIdx === '1') && hasToken) { + return Profile.serv('miao') + } + + // 如果指定了序号,则返回对应服务。0和1已前置判断 + // 原神:0自动,1喵,2Enka,3Mgg, 4:Hutao + // 星铁:0自动,1喵,2Mihomo,3Avocado, 4EnkaHSR + let servKey = isGs ? { + 2: 'enka', + 3: 'mgg', + 4: 'hutao' + } : { + 2: 'homo', + 3: 'avocado', + 4: 'enkaHSR' + } + if (servKey[servIdx]) { + return Profile.serv(servKey[servIdx]) + } + + // 设置为0或无token,使用返回默认的serv。官服0 B服1 国际2 + let defServKey = isGs ? ['mgg', 'mgg', 'enka'] : ['homo', 'homo', 'homo'] + return Profile.serv(defServKey[servType]) + }, + + /** + * 更新面板数据 + * @param player + * @param force + * @returns {Promise<boolean|number>} + */ + async refreshProfile (player, force = 2) { + if (!MysAvatar.needRefresh(player._profile, force, { 0: 24, 1: 2, 2: 0 })) { + return false + } + player._update = [] + let { uid, e } = player + if (uid.toString().length !== 9 || !e) { + return false + } + let req = ProfileReq.create(e, player.game) + if (!req) { + return false + } + let serv = Profile.getServ(uid, player.game) + try { + await req.requestProfile(player, serv, player.game) + player._profile = new Date() * 1 + player.save() + return player._update.length + } catch (err) { + if (!e._isReplyed) { + e.reply(`UID:${uid}更新面板失败,更新服务:${serv.name}`) + } + console.log(err) + return false + } + }, + + isProfile (avatar) { + if (avatar.isSr) { + return true + } + // 检查数据源 + if (!avatar._source || !['enka', 'change', 'miao', 'mgg', 'hutao', 'homo'].includes(avatar._source)) { + return false + } + // 检查武器及天赋 + if (!avatar.weapon || lodash.isUndefined(avatar.weapon.promote) || !avatar.talent) { + return false + } + // 检查圣遗物词条是否完备 + if (!avatar.artis || !avatar.artis.hasAttr) { + return false + } + // 检查旅行者 + if (['空', '荧'].includes(avatar.name)) { + return !!avatar.elem + } + return true + } +} + +export default Profile diff --git a/Yunzai/plugins/miao-plugin/models/player/ProfileMeta.js b/Yunzai/plugins/miao-plugin/models/player/ProfileMeta.js new file mode 100644 index 0000000000000000000000000000000000000000..f3cf366125717cc7f0090a533166c6207a3f4e72 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/player/ProfileMeta.js @@ -0,0 +1,575 @@ +// Enka IdsMap +export const idsMap = { + 20848859: '黑岩斩刀', + 22949795: '蔚蓝深空', + 33330467: '元素熟练', + 37147251: '匣里日月', + 43015699: '待定', + 54857595: '止水息雷', + 83115355: '被怜爱的少女', + 85795635: '专注', + 88505754: '枫原万叶', + 135182203: '止水息雷', + 141119323: '风与花的密语', + 143051931: '西福斯的月光', + 147298547: '流浪大地的乐团', + 156294403: '沉沦之心', + 160493219: '暗铁剑', + 168956722: '七七', + 197755235: '贯虹之槊', + 212557731: '祭雷之人', + 231911858: '米卡', + 235897163: '花海甘露之光', + 240385755: '破浪', + 246984427: '踏火息雷', + 262428003: '祭冰之人', + 270124867: '护国的无垢之心', + 275622963: '裁叶萃光', + 287454963: '祭风之人', + 288666635: '无垢之心', + 302691299: '琥珀玥', + 303155515: '离簇不归', + 307541163: '未完的杰作', + 310247243: '神乐之真意', + 313300315: '原木刀', + 316078811: '鹮穿之喙', + 334242634: '申鹤', + 339931171: '乘胜追击', + 342097547: '辰砂之纺锤', + 346510395: '衔珠海皇', + 359484419: '图莱杜拉的回忆', + 368014203: '斩裂晴空的龙脊', + 370151050: '莱欧斯利', + 388272194: '多莉', + 391273955: '斫断黑翼的利齿', + 411685275: '钢轮弓', + 426363739: '流浪的晚星', + 449192923: '峡湾长歌', + 452357939: '贯月矢', + 453444347: '千夜的曙歌', + 454086795: '圣显之钥', + 466355514: '卡维', + 479076483: '冷刃', + 481755219: '黑岩刺枪', + 486287579: '余热', + 500612819: '「旗杆」', + 500987603: '(test)穿模测试', + 506630267: '顺风而行', + 514784907: '踏火止水', + 521221323: '护国的无垢之心', + 540938627: '掠食者', + 566772267: '御伽大王御伽话', + 577103787: '能量沐浴', + 578575283: '流月针', + 586598971: '圆满之相', + 597991835: '白夜皓月', + 607067963: '澄澄一心传', + 613846163: '降世', + 618786571: '钺矛', + 623494555: '摧坚', + 623534363: '西风秘典', + 630452219: '樱之斋宫', + 646032090: '鹿野院平藏', + 646100491: '千岩诀·同心', + 650049651: '风花之颂', + 650438131: '秘智之眸的青睐', + 655825874: '云堇', + 656120259: '神射手之誓', + 675511059: '万世的浪涛', + 680510411: '白影剑', + 688991243: '息灾', + 693354267: '尘世之锁', + 697277554: '烟绯', + 712501082: '纳西妲', + 716252627: '千岩长枪', + 724881171: '金流监督', + 729851187: '冰之川与雪之砂', + 735056795: '西风大剑', + 800766043: '海渊终曲', + 807607555: '天空之卷', + 824949859: '嘟嘟!大冒险', + 828711395: '阿莫斯之弓', + 836208539: '炊金', + 850802171: '白铁大剑', + 855894507: '战狂', + 862591315: '苍白之火', + 877751435: '宗室大剑', + 882305891: '勘探钻机', + 902184579: '森林王器', + 902264035: '风鹰剑', + 902282051: '收割', + 909145139: '护国的无垢之心', + 925251851: '枪尖一点', + 930640955: '钟剑', + 933076627: '冰风迷途的勇士', + 942758755: '专注', + 944332883: '斫峰之刃', + 949506483: '海洋的胜利', + 968378595: '西风之鹰的抗争', + 968893378: '班尼特', + 991968139: '非时之梦·常世灶食', + 1006042610: '神里绫华', + 1012170803: '笼钓瓶一心', + 1021898539: '弹弓', + 1021947690: '魈', + 1028735635: '抗争的践行之歌', + 1049891906: '赛诺', + 1053433018: '砂糖', + 1055195035: '测距规', + 1072884907: '万国诸海图谱', + 1075647299: '松籁响起之时', + 1082448331: '微光的海渊民', + 1089950259: '天空之傲', + 1097898243: '沉重', + 1103732675: '幸运儿', + 1113306282: '莫娜', + 1113839851: '石匠号子', + 1114777131: '和弦', + 1119368259: '旅程', + 1130996346: '香菱', + 1133599347: '矢志不忘', + 1148024603: '「渔获」', + 1154009435: '试作星镰', + 1163263227: '流浪乐章', + 1163616891: '霜葬', + 1176721851: '船工号子', + 1182966603: '佣兵重剑', + 1186209435: '赌徒', + 1200948859: '饰铁之花', + 1201790667: '千夜浮梦', + 1212345779: '角斗士的终幕礼', + 1217552947: '白刃流转', + 1225226258: '琳妮特', + 1229532227: '苍狼北风', + 1240067179: '西风猎弓', + 1249831867: '逐影猎人', + 1307222899: '徊徊切舍刀', + 1310150611: '伟大者帕西法尔', + 1319974859: '激励', + 1321135667: '匣里龙吟', + 1337666507: '千岩牢固', + 1344953075: '顺风而行', + 1345343763: '磐岩结绿', + 1348687251: '猎人之径', + 1383427723: '白月枝芒', + 1383639611: '奇迹', + 1388004931: '飞天御剑', + 1390797107: '白缨枪', + 1395607523: '兽径的终点', + 1404688115: '别离的思念之歌', + 1406746947: '异世界行记', + 1414366819: '金璋皇极', + 1437658243: '螭骨剑', + 1438974835: '逆飞的流星', + 1455107995: '四风原典', + 1456643042: '绮良良', + 1468367538: '迪奥娜', + 1470442731: '风信之锋', + 1479961579: '铁影阔剑', + 1483922610: '九条裟罗', + 1485303435: '注能之刺', + 1492752155: '气定神闲', + 1499235563: '乘胜追击', + 1499745907: '「一心传」名刀', + 1499817443: '苍翠之风', + 1504902330: '那维莱特', + 1516554699: '石英大剑', + 1522029867: '踏火息雷', + 1523089323: '定土玉圭', + 1524173875: '炽烈的炎之魔女', + 1533656818: '旅行者', + 1533746995: '冰原的诸多故事', + 1538092267: '「一心传」名刀', + 1541919827: '染血的骑士道', + 1545992315: '「正义」', + 1558036915: '辰砂往生录', + 1562601179: '翠绿之影', + 1588620330: '神里绫人', + 1595734083: '(test)穿模测试', + 1600275315: '波乱月白经津', + 1608953539: '黎明神剑', + 1610242915: '传承', + 1628928163: '风花之愿', + 1632377563: '渡过烈火的贤人', + 1651985379: '极昼的先兆者', + 1660598451: '岩藏之胤', + 1675079283: '深林的记忆', + 1675686363: '祭礼大剑', + 1702903411: '镇灵的低语', + 1706534267: '有话直说', + 1722706579: '止水融冰', + 1732418482: '瑶瑶', + 1745286795: '名士振舞', + 1745712907: '驭浪的海祇民', + 1751039235: '昔日宗室之仪', + 1756609915: '海染砗磲', + 1771603299: '金璋皇极', + 1773425155: '降临之剑', + 1789612403: '回响', + 1790067483: '船坞长剑', + 1820235315: '无矢之歌', + 1836628747: '叛逆的守护者', + 1860795787: '曚云之月', + 1864015138: '刻晴', + 1873342283: '平息鸣雷的尊者', + 1890163363: '不灭月华', + 1901973075: '冬极白星', + 1921306659: '灰河渡手', + 1921418842: '诺艾尔', + 1925210475: '水仙之梦', + 1927643091: '沙海守望', + 1932742643: '灭却之戒法', + 1934830979: '无尽的渴慕', + 1940821986: '久岐忍', + 1940919994: '胡桃', + 1966438658: '安柏', + 1982136171: '专注', + 1990641987: '祭礼剑', + 1990820123: '天目影打刀', + 1991707099: '试作斩岩', + 1997709467: '和璞鸢', + 2006422931: '千岩古剑', + 2009975571: '(test)穿模测试', + 2017033267: '气定神闲', + 2025598051: '顺风而行', + 2029582603: '怪谭·时雨心地一本足', + 2040573235: '悠古的磐岩', + 2060049099: '祭火之人', + 2077869763: '浪影阔剑', + 2108574027: '碎石', + 2109571443: '专注', + 2125206395: '银剑', + '2149411851': '金璋皇极', + '2153521307': '沙上楼阁', + '2172529947': '乘胜追击', + '2176134843': '专注', + '2190368347': '决', + '2191797987': '冒险家', + '2195436779': '石匠号子', + '2195665683': '祭礼残章', + '2242027395': '黑檀弓', + '2244980899': '沉入沙海的史诗', + '2257505883': '森林的瑞佑', + '2258943483': '巡航的白浪', + '2265792579': '狼牙', + '2267978875': '盈满之实', + '2275710883': '遗祀玉珑', + '2276480763': '绝缘之旗印', + '2279290283': '魔导绪论', + '2297485451': '速射弓斗', + '2312640651': '气定神闲', + '2317820211': '注能之针', + '2322648115': '粉碎', + '2324146259': '白辰之环', + '2340970067': '历练的猎弓', + '2351445619': '堙没的蓝宝石泪滴', + '2359799475': '恶王丸', + '2360533154': '迪希雅', + '2364208851': '行者之心', + '2365025043': '街巷游侠', + '2375993851': '宗室长剑', + '2383998915': '驭浪的海祇民', + '2384519283': '弹弓', + '2387711994': '珐露珊', + '2388785242': '早柚', + '2400012995': '祭礼弓', + '2410593283': '无锋剑', + '2415974179': '船工号子', + '2417717595': '暗巷猎手', + '2425414923': '落霞', + '2432865507': '纯水流华', + '2433755451': '揭旗的叛逆之歌', + '2440850563': '回响长天的诗歌', + '2448629019': '东花坊时雨', + '2466140362': '温迪', + '2469300579': '乘胜追击', + '2470144971': '「伶牙俐齿」', + '2470306939': '飞雷御执', + '2472444970': '林尼', + '2474354867': '西风剑', + '2476346187': '踏火止水', + '2491797315': '喜多院十文字', + '2504399314': '宵宫', + '2506955778': '提纳里', + '2512309395': '如雷的盛怒', + '2521338131': '试作金珀', + '2534304035': '雾切御腰物', + '2538235187': '沙上楼阁史话', + '2539208459': '证誓之明瞳', + '2546254811': '华馆梦醒形骸记', + '2556914683': '绝弦', + '2587614459': '忍冬之果', + '2600875323': '静谧之曲', + '2614170427': '飞天大御剑', + '2646367730': '北斗', + '2664629131': '匣里灭辰', + '2666951267': '训练大剑', + '2673337443': '注能之矢', + '2679781122': '甘雨', + '2684365579': '登场乐', + '2691070627': '森林的瑞佑', + '2705029563': '口袋魔导书', + '2713453234': '八重神子', + '2719832059': '(test)穿模测试', + '2722902043': '无垠蔚蓝之歌', + '2743659331': '激流', + '2749508387': '金璋皇极', + '2749853923': '腐殖之剑', + '2753539619': '雪葬的星银', + '2764598579': '流放者', + '2792766467': '无工之剑', + '2796697027': '新手长枪', + '2832648187': '宗室长弓', + '2834063555': '苇海信标', + '2834803571': '金璋皇极', + '2848374378': '夜兰', + '2853296811': '穿刺高天的利齿', + '2871793795': '锐利', + '2876340530': '重云', + '2889777514': '莱依拉', + '2890909531': '武人', + '2893964243': '飞矢传书', + '2915865819': '渊中霞彩', + '2918525947': '飞雷之弦振', + '2935286715': '宗室猎枪', + '2947140987': '暗巷闪光', + '2948362178': '柯莱', + '2949448555': '苍古自由之誓', + '2958179435': '烈阳之嗣', + '2963220587': '翡玉法球', + '2984815066': '白术', + '2988480723': '最初的大魔术', + '3001782875': '气定神闲', + '3018479371': '船歌', + '3024507506': '雷电将军', + '3063191787': '竭泽', + '3063488107': '强力攻击', + '3068316954': '荒泷一斗', + '3070169307': '铁尖枪', + '3073454867': '玛海菈的水色', + '3079462611': '驭浪的海祇民', + '3082528187': '深海弦振', + '3090373787': '暗巷的酒与诗', + '3092975658': '坎蒂丝', + '3094139291': '乐园遗落之花', + '3097441915': '以理服人', + '3101537195': '黄金的血潮', + '3102522787': '最终的崇高', + '3112448011': '决心', + '3112679155': '终末嗟叹之诗', + '3156385731': '昭心', + '3159145923': '徊徊切舍刀', + '3169209451': '弓藏', + '3176599083': '王下近侍', + '3192689683': '霜葬', + '3209694115': '林野晚星', + '3221566250': '琴', + '3230559562': '流浪者', + '3235324891': '护摩之杖', + '3252085691': '顺风而行', + '3258658763': '嗜魔', + '3265161211': '注能之锋', + '3273999011': '黑岩绯玉', + '3277782506': '菲谢尔', + '3302787771': '霜葬', + '3305772819': '奔袭战术', + '3314157803': '克柔', + '3337185491': '浅濑之弭', + '3337249451': '过载', + '3339083250': '可莉', + '3344622722': '丽莎', + '3364338659': '无边际的眷顾', + '3371922315': '神樱神游神乐舞', + '3378007475': '黑岩长剑', + '3400133546': '五郎', + '3406113971': '顺风而行', + '3410220315': '黄金剧团', + '3421967235': '吃虎鱼刀', + '3439749859': '苍翠猎弓', + '3443142923': '龙脊长枪', + '3447737235': '黑岩战弓', + '3453611803': '网破', + '3456986819': '嘟嘟可故事集', + '3459616011': '聊聊棒', + '3464027035': '「一心传」名刀', + '3465493459': '精准', + '3500935003': '讨龙英杰谭', + '3513240283': '不至之风', + '3535784755': '勇士之心', + '3541083923': '角斗士', + '3555115602': '托马', + '3584825427': '学徒笔记', + '3587062891': '千岩诀·同心', + '3587621259': '笛剑', + '3600623979': '猎弓', + '3608180322': '迪卢克', + '3618167299': '学士', + '3625393819': '试作澹月', + '3626268211': '来歆余响', + '3673792067': '旅行剑', + '3684723963': '雨裁', + '3685735523': '徊徊切舍刀', + '3689108098': '埃洛伊', + '3693117451': '便携动力锯', + '3717341819': '幽林月影', + '3717667418': '优菈', + '3717849275': '薙草之稻光', + '3719372715': '甲级宝珏', + '3722933411': '试作古华', + '3747103099': '阳炎古道', + '3755004051': '西风长枪', + '3762437019': '(test)穿模测试', + '3775299170': '芭芭拉', + '3782508715': '游医', + '3796702635': '变化万端', + '3796905611': '黑剑', + '3816664530': '旅行者', + '3827789435': '宗室秘法录', + '3832443723': '不屈', + '3836188467': '无羁的朱赤之蝶', + '3847143266': '达达利亚', + '3850149970': '妮露', + '3862787418': '钟离', + '3890292467': '教官', + '3898539027': '浮游四方的灵云', + '3909785739': '蜃气尽头的热梦', + '3914045794': '珊瑚宫心海', + '3914951691': '赤角石溃杵', + '3933622347': '天空之翼', + '3949653579': '幽夜华尔兹', + '3956074723': '迷宫之王的教导', + '3966753539': '洗濯诸类之形', + '3975746731': '鸦羽弓', + '3995710363': '狼的末路', + '3996017211': '收割', + '3999792907': '祭水之人', + '4000770243': '街巷伏击', + '4002157418': '艾尔海森', + '4007372867': '碧落之珑', + '4022012131': '乘胜追击', + '4049410651': '决斗之枪', + '4055003299': '天空之刃', + '4060235987': '日月辉', + '4080317355': '勇气', + '4082302819': '守护之心', + '4090429643': '沐浴龙血的剑', + '4103022435': '铁蜂刺', + '4103766499': '黑缨枪', + '4108620722': '阿贝多', + '4113638323': '昭理的鸢之枪', + '4119663210': '凯亚', + '4122509083': '断浪长鳍', + '4124851547': '雾切之回光', + '4127888970': '凝光', + '4137694339': '(test)竿测试', + '4139294531': '信使', + '4144069251': '追忆之注连', + '4145306051': '饰金之梦', + '4158505619': '天空之脊', + '4158971171': '公义的酬报', + '4160147242': '雷泽', + '4162981171': '(test)穿模测试', + '4176923379': '万世流涌大典', + '4186179883': '破魔之弓', + '4193089947': '桂木斩长正', + '4197635682': '行秋', + '4201964354': '菲米尼', + '4226083179': '名士振舞', + '4227142475': '碧玉流转', + '4230231107': '若水', + '4231466539': '铁骨', + '4238339131': '赤沙之杖', + '4245213187': '注能之卷', + '4258047555': '极夜二重奏', + '4260733330': '罗莎莉亚', + '4267718859': '反曲弓', + '4273845410': '辛焱', + '4275754179': '如狼般狩猎者', + FIGHT_PROP_BASE_HP: '基础生命值', + FIGHT_PROP_HP: '生命值', + FIGHT_PROP_HP_PERCENT: '生命值', + FIGHT_PROP_BASE_ATTACK: '基础攻击力', + FIGHT_PROP_ATTACK: '攻击力', + FIGHT_PROP_ATTACK_PERCENT: '攻击力', + FIGHT_PROP_BASE_DEFENSE: '基础防御力', + FIGHT_PROP_DEFENSE: '防御力', + FIGHT_PROP_DEFENSE_PERCENT: '防御力', + FIGHT_PROP_BASE_SPEED: '移动速度', + FIGHT_PROP_SPEED_PERCENT: '移动速度', + FIGHT_PROP_CRITICAL: '暴击率', + FIGHT_PROP_ANTI_CRITICAL: '暴击抗性', + FIGHT_PROP_CRITICAL_HURT: '暴击伤害', + FIGHT_PROP_CHARGE_EFFICIENCY: '元素充能效率', + FIGHT_PROP_ADD_HURT: '伤害增加', + FIGHT_PROP_SUB_HURT: '受伤减免', + FIGHT_PROP_HEAL_ADD: '治疗加成', + FIGHT_PROP_HEALED_ADD: '受治疗加成', + FIGHT_PROP_ELEMENT_MASTERY: '元素精通', + FIGHT_PROP_PHYSICAL_SUB_HURT: '物理抗性', + FIGHT_PROP_PHYSICAL_ADD_HURT: '物理伤害加成', + FIGHT_PROP_FIRE_ADD_HURT: '火元素伤害加成', + FIGHT_PROP_ELEC_ADD_HURT: '雷元素伤害加成', + FIGHT_PROP_WATER_ADD_HURT: '水元素伤害加成', + FIGHT_PROP_GRASS_ADD_HURT: '草元素伤害加成', + FIGHT_PROP_WIND_ADD_HURT: '风元素伤害加成', + FIGHT_PROP_ROCK_ADD_HURT: '岩元素伤害加成', + FIGHT_PROP_ICE_ADD_HURT: '冰元素伤害加成', + FIGHT_PROP_FIRE_SUB_HURT: '火元素抗性', + FIGHT_PROP_ELEC_SUB_HURT: '雷元素抗性', + FIGHT_PROP_WATER_SUB_HURT: '水元素抗性', + FIGHT_PROP_GRASS_SUB_HURT: '草元素抗性', + FIGHT_PROP_WIND_SUB_HURT: '风元素抗性', + FIGHT_PROP_ROCK_SUB_HURT: '岩元素抗性', + FIGHT_PROP_ICE_SUB_HURT: '冰元素抗性', + FIGHT_PROP_EFFECT_HIT: '效果命中', + FIGHT_PROP_EFFECT_RESIST: '效果抵抗', + FIGHT_PROP_FREEZE_SHORTEN: '冻结时间缩短', + FIGHT_PROP_DIZZY_SHORTEN: '眩晕时间缩短', + FIGHT_PROP_SKILL_CD_MINUS_RATIO: '冷却缩减', + FIGHT_PROP_SHIELD_COST_MINUS_RATIO: '护盾强效', + FIGHT_PROP_CUR_HP: '生命值', + FIGHT_PROP_MAX_HP: '生命值上限', + FIGHT_PROP_CUR_ATTACK: '攻击力', + FIGHT_PROP_CUR_DEFENSE: '防御力', + FIGHT_PROP_CUR_SPEED: '移动速度', + abyss: '深境螺旋', + achievements: '成就总数', + level: '等级' +} + +// 圣遗物词条映射 +export const attrMap = { + HP: 'hpPlus', + HP_PERCENT: 'hp', + ATTACK: 'atkPlus', + ATTACK_PERCENT: 'atk', + DEFENSE: 'defPlus', + DEFENSE_PERCENT: 'def', + FIRE_ADD_HURT: 'pyro', + ICE_ADD_HURT: 'cryo', + ROCK_ADD_HURT: 'geo', + ELEC_ADD_HURT: 'electro', + WIND_ADD_HURT: 'anemo', + WATER_ADD_HURT: 'hydro', + PHYSICAL_ADD_HURT: 'phy', + GRASS_ADD_HURT: 'dendro', + HEAL_ADD: 'heal', + ELEMENT_MASTERY: 'mastery', + CRITICAL: 'cpct', + CRITICAL_HURT: 'cdmg', + CHARGE_EFFICIENCY: 'recharge' +} + +// 圣遗物位置映射 +export const artisIdxMap = { + EQUIP_BRACER: 1, + EQUIP_NECKLACE: 2, + EQUIP_SHOES: 3, + EQUIP_RING: 4, + EQUIP_DRESS: 5, + 生之花: 1, + 死之羽: 2, + 时之沙: 3, + 空之杯: 4, + 理之冠: 5 +} diff --git a/Yunzai/plugins/miao-plugin/models/profile/ArtisMark.js b/Yunzai/plugins/miao-plugin/models/profile/ArtisMark.js new file mode 100644 index 0000000000000000000000000000000000000000..5555e9b47dbe99991d993f7be197635bca3c7dda --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/ArtisMark.js @@ -0,0 +1,209 @@ +import lodash from 'lodash' +import { Format } from '#miao' +import { + attrNameMap, + mainAttr as mainAttrGS, + subAttr as subAttrGS, + attrMap as attrMapGS +} from '../../resources/meta/artifact/index.js' +import { + attrMap as attrMapSR, + mainAttr as mainAttrSR, + subAttr as subAttrSR +} from '../../resources/meta-sr/artifact/meta.js' + +let ArtisMark = { + // 根据Key获取标题 + getKeyByTitle (title, game = 'gs') { + if (/元素伤害加成/.test(title) || Format.isElem(title)) { + let elem = Format.matchElem(title) + return elem + } else if (title === '物理伤害加成') { + return 'phy' + } + return attrNameMap[title] || attrMapGS[title] + }, + + getKeyTitleMap (game = 'gs') { + let ret = {} + let attrMap = game === 'gs' ? attrMapGS : attrMapSR + lodash.forEach(attrMap, (ds, key) => { + ret[key] = ds.title + }) + Format.eachElem((key, name) => { + ret[key] = `${name}伤加成` + }, game) + return ret + }, + + formatAttr (ds, game = 'gs') { + if (!ds) { + return {} + } + if (lodash.isArray(ds) && ds[0] && ds[1]) { + return { + key: ArtisMark.getKeyByTitle(ds[0], game), + value: ds[1] + } + } + if (!ds.value) { + return {} + } + return { + key: ds.key || ArtisMark.getKeyByTitle(ds.title || ds.name || ds.key || ds.id || '', game), + value: ds.value || '' + } + }, + + /** + * 格式化圣遗物词条 + * @param ds + * @param charAttrCfg + * @param isMain + * @param game + * @returns {{title: *, value: string}|*[]} + */ + formatArti (ds, charAttrCfg = false, isMain = false, game = 'gs') { + // 若为attr数组 + if (ds[0] && (ds[0].title || ds[0].key)) { + let ret = [] + lodash.forEach(ds, (d) => { + let arti = ArtisMark.formatArti(d, charAttrCfg, isMain, game) + ret.push(arti) + }) + return ret + } + + let key = ds.key + let title = ds.title || ds[0] + if (!key) { + key = ArtisMark.getKeyByTitle(title, game) + } + let isDmg = Format.isElem(key) + let val = ds.value || ds[1] + let num = ds.value || ds[1] + if (!key || key === 'undefined') { + return {} + } + let arrCfg = (game === 'gs' ? attrMapGS : attrMapSR)[isDmg ? 'dmg' : key] + val = Format[arrCfg?.format || 'comma'](val, 1) + let ret = { + key, + value: val, + upNum: ds.upNum || 0, + eff: ds.eff || 0 + } + + if (charAttrCfg) { + let mark = charAttrCfg[key]?.mark * num || 0 + if (isMain) { + mark = mark / 4 + 0.01 + ret.key = key + } + ret.mark = Format.comma(mark || 0) + ret._mark = mark || 0 + } + ret.eff = ret.eff ? Format.comma(ret.eff / (game === 'gs' ? 0.85 : 0.9), 1) : '-' + return ret + }, + + // 获取评分档位 + getMarkClass (mark) { + let pct = mark + let scoreMap = [['D', 7], ['C', 14], ['B', 21], ['A', 28], ['S', 35], ['SS', 42], ['SSS', 49], ['ACE', 56], ['ACE²', 70]] + for (let idx = 0; idx < scoreMap.length; idx++) { + if (pct < scoreMap[idx][1]) { + return scoreMap[idx][0] + } + } + }, + + // 获取位置分数 + getMark ({ charCfg, idx, arti, elem = '', game = 'gs' }) { + let ret = 0 + let mAttr = arti.main + let sAttr = arti.attrs + let { attrs, posMaxMark } = charCfg + let key = mAttr?.key + if (!key) { + return 0 + } + let fixPct = 1 + idx = idx * 1 + if (idx >= 3) { + let mainKey = key + if (key !== 'recharge') { + let dmgIdx = { gs: 4, sr: 5 } + if (idx === dmgIdx[game] && Format.sameElem(elem, key, game)) { + mainKey = 'dmg' + } + fixPct = Math.max(0, Math.min(1, (attrs[mainKey]?.weight || 0) / (posMaxMark['m' + idx]))) + } + ret += (attrs[mainKey]?.mark || 0) * (mAttr.value || 0) / 4 + } + + lodash.forEach(sAttr, (ds) => { + ret += (attrs[ds.key]?.mark || 0) * (ds.value || 0) + }) + return ret * (1 + fixPct) / 2 / posMaxMark[idx] * 66 + }, + + // 获取位置最高分 + getMaxMark (attrs, game = 'gs') { + let ret = {} + let mainAttr = game === 'gs' ? mainAttrGS : mainAttrSR + let subAttr = game === 'gs' ? subAttrGS : subAttrSR + for (let idx = 1; idx <= (game === 'gs' ? 5 : 6); idx++) { + let totalMark = 0 + let mMark = 0 + let mAttr = '' + if (idx === 1) { + mAttr = 'hpPlus' + } else if (idx === 2) { + mAttr = 'atkPlus' + } else if (idx >= 3) { + mAttr = ArtisMark.getMaxAttr(attrs, mainAttr[idx])[0] + mMark = attrs[mAttr].fixWeight + totalMark += attrs[mAttr].fixWeight * 2 + } + + let sAttr = ArtisMark.getMaxAttr(attrs, subAttr, 4, mAttr) + lodash.forEach(sAttr, (attr, aIdx) => { + totalMark += attrs[attr].fixWeight * (aIdx === 0 ? 6 : 1) + }) + ret[idx] = totalMark + ret['m' + idx] = mMark + } + return ret + }, + + // 获取最高分的属性 + getMaxAttr (attrs = {}, list2 = [], maxLen = 1, banAttr = '') { + let tmp = [] + lodash.forEach(list2, (attr) => { + if (attr === banAttr) return + if (!attrs[attr]) return + tmp.push({ attr, mark: attrs[attr].fixWeight }) + }) + tmp = lodash.sortBy(tmp, 'mark') + tmp = tmp.reverse() + let ret = [] + lodash.forEach(tmp, (ds) => ret.push(ds.attr)) + return ret.slice(0, maxLen) + }, + + hasAttr (artis, game = 'gs') { + for (let idx = 1; idx <= 5; idx++) { + let ds = artis[idx] + if (ds) { + // 不再支持非id格式的面板 + if ((!ds.attrIds && !ds.attr) || !ds.mainId) { + return false + } + } + } + return true + } +} + +export default ArtisMark diff --git a/Yunzai/plugins/miao-plugin/models/profile/AttrCalc.js b/Yunzai/plugins/miao-plugin/models/profile/AttrCalc.js new file mode 100644 index 0000000000000000000000000000000000000000..05a901471eb51961fb31dcb9c5ecedd73ed5b5f1 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/AttrCalc.js @@ -0,0 +1,269 @@ +/** + * 面板属性计算 + * @type {{}} + */ + +import { Weapon, ProfileAttr, ArtifactSet } from '../index.js' +import { Format } from '#miao' +import { weaponBuffs } from '../../resources/meta/weapon/index.js' +import lodash from 'lodash' + +class AttrCalc { + constructor (profile) { + this.profile = profile + this.char = profile.char + this.game = this.char.game + } + + get isGs () { + return this.game === 'gs' + } + + get isSr () { + return this.game === 'sr' + } + + /** + * 静态调用入口 + * @param profile + * @returns {AttrCalc} + */ + static create (profile) { + return new AttrCalc(profile) + } + + // 只有原神才需要 + static calcPromote (lv) { + if (lv === 20) { + return 1 + } + if (lv === 90) { + return 6 + } + let lvs = [1, 20, 40, 50, 60, 70, 80, 90] + let promote = 0 + for (let idx = 0; idx < lvs.length - 1; idx++) { + if (lv >= lvs[idx] && lv <= lvs[idx + 1]) { + return promote + } + promote++ + } + return promote + } + + /** + * 面板属性计算 + * @returns {{}} + */ + calc () { + this.attr = ProfileAttr.create(this.char, {}) + if (this.isGs) { + this.addAttr('recharge', 100, true) + this.addAttr('cpct', 5, true) + this.addAttr('cdmg', 50, true) + } + this.setCharAttr() + this.setWeaponAttr() + this.setArtisAttr() + return this.attr.getAttr() + + } + + getBase () { + return this.attr.getBase() + } + + + addAttr (key, val, isBase = false) { + this.attr.addAttr(key, val, isBase) + } + + /** + * 计算角色属性 + * @param affix + */ + setCharAttr (affix = '') { + let { char, level, promote, trees } = this.profile + let metaAttr = char.detail?.attr || {} + let self = this + if (this.isSr) { + // 星铁面板属性 + let attr = char.getLvAttr(level, promote) + lodash.forEach(attr, (v, k) => { + k = k + (['hp', 'atk', 'def', 'speed'].includes(k) ? 'Base' : '') + self.addAttr(k, v, true) + }) + + let tree = char.detail?.tree || {} + lodash.forEach(trees || [], (tid) => { + let tCfg = tree[tid] + if (tCfg) { + let key = tCfg.key + if (['atk', 'hp', 'def'].includes(key)) { + key = key + 'Pct' + } + self.addAttr(key, tCfg.value) + } + }) + return + } + + let { keys = {}, details = {} } = metaAttr + let lvLeft = 0 + let lvRight = 0 + let lvStep = [1, 20, 40, 50, 60, 70, 80, 90] + let currPromote = 0 + for (let idx = 0; idx < lvStep.length - 1; idx++) { + if (currPromote === promote) { + if (level >= lvStep[idx] && level <= lvStep[idx + 1]) { + lvLeft = lvStep[idx] + lvRight = lvStep[idx + 1] + break + } + } + currPromote++ + } + let detailLeft = details[lvLeft + '+'] || details[lvLeft] || {} + let detailRight = details[lvRight] || {} + + let getLvData = (idx, step = false) => { + let valueLeft = detailLeft[idx] + let valueRight = detailRight[idx] + if (!step) { + return valueLeft * 1 + ((valueRight - valueLeft) * (level - lvLeft) / (lvRight - lvLeft)) + } else { + return valueLeft * 1 + ((valueRight - valueLeft) * Math.floor((level - lvLeft) / 5) / Math.round(((lvRight - lvLeft) / 5))) + } + } + this.addAttr('hpBase', getLvData(0), true) + this.addAttr('atkBase', getLvData(1), true) + this.addAttr('defBase', getLvData(2), true) + this.addAttr(keys[3], getLvData(3, true), !/(hp|atk|def)/.test(keys[3])) + + let charBuffs = char.getCalcRule() + lodash.forEach(charBuffs.buffs, (buff) => { + if (!buff.isStatic) { + return true + } + if (buff) { + lodash.forEach(buff.data, (val, key) => { + this.addAttr(key, val) + }) + } + }) + } + + /** + * 计算武器属性 + */ + setWeaponAttr () { + let wData = this.profile?.weapon || {} + if (!wData || !wData.name) { + return false + } + let weapon = Weapon.get(wData?.name || wData?.id, this.game) + if (!weapon) { + return false + } + let wCalcRet = weapon.calcAttr(wData.level, wData.promote) + let self = this + + if (this.isSr) { + // 星铁面板属性 + lodash.forEach(wCalcRet, (v, k) => { + k = k + (['hp', 'atk', 'def'].includes(k) ? 'Base' : '') + self.addAttr(k, v, true) + }) + // 检查武器类型 + if (weapon.type === this.char.weapon) { + // todo sr&gs 统一 + let wBuffs = weapon.getWeaponAffixBuffs(wData.affix, true) + lodash.forEach(wBuffs, (buff) => { + lodash.forEach(buff.data || [], (v, k) => { + self.addAttr(k, v) + }) + }) + } + return + } + + // 原神属性 + if (wCalcRet) { + this.addAttr('atkBase', wCalcRet.atkBase) + this.addAttr(wCalcRet.attr?.key, wCalcRet.attr?.value) + } + + let wBuffs = weaponBuffs[weapon.name] || [] + if (lodash.isPlainObject(wBuffs)) { + wBuffs = [wBuffs] + } + let affix = wData.affix || 1 + lodash.forEach(wBuffs, (buff) => { + if (!buff.isStatic) { + return true + } + if (buff) { + lodash.forEach(buff.refine, (r, key) => { + this.addAttr(key, r[affix - 1] * (buff.buffCount || 1)) + }) + } + }) + } + + /** + * 计算圣遗物属性 + */ + setArtisAttr () { + let artis = this.profile?.artis + // 计算圣遗物词条 + artis.forEach((arti) => { + this.calcArtisAttr(arti.main, this.char) + lodash.forEach(arti.attrs, (ds) => { + this.calcArtisAttr(ds, this.char) + }) + }) + // 计算圣遗物静态加成 + artis.eachArtisSet((set, num) => { + let buffs = ArtifactSet.getArtisSetBuff(set.name, num, this.game) + if (!buffs) return true + + lodash.forEach(buffs, (buff) => { + if (!buff.isStatic) { + return true + } + if (buff.elem && !this.char.isElem(buff.elem)) { + return true + } + lodash.forEach(buff.data, (val, key) => { + this.addAttr(key, val) + }) + }) + }) + } + + /** + * 计算单条圣遗物词缀 + * @param ds + * @param char + * @param autoPct + * @returns {boolean} + */ + calcArtisAttr (ds, char) { + if (!ds) { + return false + } + let key = ds.key + if (Format.isElem(key) && char.elem === key) { + key = 'dmg' + } + if (!key) { + return false + } + if (['atk', 'hp', 'def'].includes(key)) { + key = key + 'Pct' + } + this.attr.addAttr(key, ds.value * 1) + } +} + +export default AttrCalc diff --git a/Yunzai/plugins/miao-plugin/models/profile/CharArtis.js b/Yunzai/plugins/miao-plugin/models/profile/CharArtis.js new file mode 100644 index 0000000000000000000000000000000000000000..2179623cd852cb7146039c965e0dc5b15b2123af --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/CharArtis.js @@ -0,0 +1,96 @@ +import { usefulAttr as usefulAttrGS } from '../../resources/meta/artifact/artis-mark.js' +import { usefulAttr as usefulAttrSR } from '../../resources/meta-sr/artifact/artis-mark.js' +import lodash from 'lodash' + +const CharArtis = { + + getCharArtisCfg (char, profile, artis) { + let { attr, weapon, elem } = profile + let { isGs } = char + let usefulAttr = isGs ? usefulAttrGS : usefulAttrSR + + let rule = function (title, attrWeight) { + return { + title, + attrWeight + } + } + + let def = function (attrWeight) { + let title = [] + + let weight = lodash.extend({}, attrWeight || usefulAttr[char.name] || {}) + let check = (key, max = 75, maxPlus = 75, isWeapon = true) => { + let original = weight[key] || 0 + if (original < max) { + let plus = isWeapon ? maxPlus * (1 + weapon.affix / 5) / 2 : maxPlus + weight[key] = Math.min(Math.round(original + plus), max) + return true + } + return false + } + + let wn = weapon?.name || '' + + if (isGs) { + // 对原神一些特殊情况做适配与判定 + + // 增加攻击力或直接伤害类武器判定 + const weaponCfg = { + 磐岩结绿: { + attr: 'hp', + abbr: '绿剑' + }, + 赤角石溃杵: { + attr: 'def', + abbr: '赤角' + }, + 猎人之径: { + attr: 'mastery' + }, + 薙草之稻光: { + attr: 'recharge', + abbr: '薙刀' + }, + 护摩之杖: { + attr: 'hp', + abbr: '护摩' + } + } + + if (weight.atk > 0 && weaponCfg[wn]) { + let wCfg = weaponCfg[wn] + if (check(wCfg.attr, wCfg.max || 75, wCfg.plus || 75)) { + title.push(wCfg.abbr || wn) + } + } + + // 不与攻击力挂钩的武器判定 + if (wn === '辰砂之纺锤' && check('def')) { + title.push('纺锤') + } + + // 圣遗物判定,如果是绝缘4,将充能权重拉高至沙漏圣遗物当前最高权重齐平 + let maxWeight = Math.max(weight.atk || 0, weight.hp || 0, weight.def || 0, weight.mastery || 0) + if (artis.is('绝缘4') && check('recharge', maxWeight, 75, false)) { + title.push('绝缘4') + } + } + + title = title.length > 0 ? title.join('') : '通用' + return { + title: `${char.abbr}-${title}`, + attrWeight: weight + } + } + + let charRule = char.getArtisCfg() || function ({ def }) { + return def(usefulAttr[char.name] || { atk: 75, cpct: 100, cdmg: 100 }) + } + + if (charRule) { + return charRule({ attr, elem, artis, rule, def, weapon, cons: profile.cons }) + } + } +} +export default CharArtis diff --git a/Yunzai/plugins/miao-plugin/models/profile/DataTrans.js b/Yunzai/plugins/miao-plugin/models/profile/DataTrans.js new file mode 100644 index 0000000000000000000000000000000000000000..a85da198391b569ad115535b78dfc42654f40fe2 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/DataTrans.js @@ -0,0 +1,32 @@ +/** + * 旧面板数据迁移 + * 去除旧格式,控制逻辑复杂度 + */ +import fs from 'node:fs' +import lodash from 'lodash' +import { Data } from '#miao' + +const DataTrans = { + trans () { + const srcPath = './data/UserData' + let uids = fs.readdirSync(srcPath) + uids = uids.filter((uid) => /\.json/i.test(uid)) + lodash.forEach(uids, (uid) => { + let data = Data.readJSON(`/data/UserData/${uid}`) + DataTrans.doTrans(data) + }) + }, + doTrans (data) { + lodash.forEach(data.avatars, (ds, id) => { + data.avatars[id] = DataTrans.getAvatar(ds) + }) + }, + getAvatar (data) { + let artisSet = {} + lodash.forEach(data.artis, (ds, idx) => { + + }) + + } +} +export default DataTrans \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/models/profile/DmgAttr.js b/Yunzai/plugins/miao-plugin/models/profile/DmgAttr.js new file mode 100644 index 0000000000000000000000000000000000000000..769e2bf920dd527d5d1103782648f5dbc32f2faa --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/DmgAttr.js @@ -0,0 +1,230 @@ +/* +* 伤害计算 - 属性计算 +* */ +import { attrMap as attrMapGS } from '../../resources/meta/artifact/index.js' +import { attrMap as attrMapSR } from '../../resources/meta-sr/artifact/index.js' +import { eleBaseDmg } from './DmgCalcMeta.js' +import lodash from 'lodash' +import DmgMastery from './DmgMastery.js' +import { Format } from '#miao' + +let DmgAttr = { + // 计算并返回指定属性值 + getAttrValue (ds = {}) { + return (ds.base || 0) + (ds.plus || 0) + ((ds.base || 0) * (ds.pct || 0) / 100) + }, + + // 获取profile对应attr属性值 + getAttr ({ id, attr, weapon, char, game = 'gs' }) { + let ret = {} + + // 基础属性 + lodash.forEach('atk,def,hp'.split(','), (key) => { + ret[key] = { + base: attr[`${key}Base`] * 1 || 0, + plus: attr[key] * 1 - attr[`${key}Base`] * 1 || 0, + pct: 0 + } + }) + + lodash.forEach((game === 'gs' ? 'mastery,recharge,cpct,cdmg,heal,dmg,phy' : 'speed,recharge,cpct,cdmg,heal,dmg,enemyDmg,effPct,effDef,stance').split(','), (key) => { + ret[key] = { + base: attr[key] * 1 || 0, // 基础值 + plus: 0, // 加成值 + pct: 0, // 百分比加成 + inc: 0 // 提高:护盾增效&治疗增效 + } + }) + + // 技能属性记录 + lodash.forEach((game === 'gs' ? 'a,a2,a3,e,q' : 'a,a2,a3,e,e2,q,t').split(','), (key) => { + ret[key] = { + pct: 0, // 倍率加成 + multi: 0, // 独立倍率乘区加成,宵宫E等 + + plus: 0, // 伤害值提高 + dmg: 0, // 伤害提高 + enemydmg: 0, // 承受伤害提高 + cpct: 0, // 暴击提高 + cdmg: 0, // 爆伤提高 + + def: 0, // 防御降低 + ignore: 0 // 无视防御 + } + }) + + ret.enemy = { + def: 0, // 降低防御 + ignore: 0, // 无视防御 + phy: 0 // 物理防御 + } + + ret.shield = { + base: 100, // 基础 + plus: 0, // 护盾强效 + inc: 100 // 吸收倍率 + } + + ret.weapon = weapon // 武器 + ret.weaponTypeName = char.weaponTypeName // 武器类型 + ret.element = Format.elemName(char.elem) // 元素类型 + ret.refine = ((weapon.affix || ret.refine || 1) * 1 - 1) || 0 // 武器精炼 + ret.multi = 0 // 倍率独立乘区 + ret.kx = 0 // 敌人抗性降低 + if (game === 'gs') { + ret.vaporize = 0 // 蒸发 + ret.melt = 0 // 融化 + ret.burning = 0 // 燃烧 + ret.superConduct = 0 // 超导 + ret.swirl = 0 // 扩散 + ret.electroCharged = 0 // 感电 + ret.shatter = 0 // 碎冰 + ret.overloaded = 0 // 超载 + ret.bloom = 0 // 绽放 + ret.burgeon = 0 // 烈绽放 + ret.hyperBloom = 0 // 超绽放 + ret.aggravate = 0 // 超激化 + ret.spread = 0 // 蔓激化 + ret.fykx = 0 // 敌人反应抗性降低 + } else if (game === 'sr') { + // 技能持续伤害与弱点击破持续伤害 + ret.dot = { + dmg: 0, // 伤害提高 + enemydmg: 0 // 承受伤害提高 + } + } + return ret + }, + + // 获取数据集 + getDs (attr, meta, params) { + return { + ...meta, + attr, + params, + refine: attr.refine, + weaponTypeName: attr.weaponTypeName, + weapon: attr.weapon, + element: Format.elemName(attr.element) || attr.element, + // 计算属性 + calc: DmgAttr.getAttrValue + } + }, + + // 计算属性 + calcAttr ({ originalAttr, buffs, meta, params = {}, incAttr = '', reduceAttr = '', talent = '', game = 'gs' }) { + let attr = lodash.merge({}, originalAttr) + let msg = [] + + let attrMap = game === 'gs' ? attrMapGS : attrMapSR + + if (incAttr && attrMap[incAttr]) { + let aCfg = attrMap[incAttr] + attr[incAttr][aCfg.calc] += aCfg.value + } + if (reduceAttr && attrMap[reduceAttr]) { + let aCfg = attrMap[reduceAttr] + attr[reduceAttr][aCfg.calc] -= aCfg.value + } + + lodash.forEach(buffs, (buff) => { + let ds = DmgAttr.getDs(attr, meta, params) + + ds.currentTalent = talent + + if (buff.isStatic) { + return + } + // 如果存在rule,则进行计算 + if (buff.check && !buff.check(ds)) { + return + } + if (buff.cons) { + if (ds.cons * 1 < buff.cons * 1) { + return + } + } + if (!lodash.isUndefined(buff.maxCons)) { + if (ds.cons * 1 > buff.maxCons * 1) { + return + } + } + if (buff.tree) { + if (!ds.trees[`10${buff.tree}`]) { + return + } + } + + let title = buff.title + + if (buff.mastery) { + let mKey = { + vaporize: '蒸发', + melt: '融化', + swirl: '扩散' + } + let mKey2 = { + aggravate: '超激化', + spread: '蔓激化' + } + + let mastery = Math.max(0, attr.mastery.base + attr.mastery.plus) + buff.data = buff.data || {} + + let key = buff.mastery + if (mKey[key]) { + buff.data['_' + key] = DmgMastery.getMultiple(key, mastery) * 100 + } else if (mKey2[key]) { + let eleNum = DmgMastery.getBasePct(key, attr.element) + let eleBase = 1 + attr[key] / 100 + DmgMastery.getMultiple(key, mastery) + eleBase *= eleBaseDmg[ds.level] + buff.data['_' + key] = DmgMastery.getMultiple(key, mastery) * 100 + buff.data['_' + key + 'num'] = eleNum * eleBase + } + } + + lodash.forEach(buff.data, (val, key) => { + if (lodash.isFunction(val)) { + val = val(ds) + } + + title = title.replace(`[${key}]`, Format.comma(val, 1)) + // 技能提高 + let tRet = /^(a|a2|a3|e|q|t)(Def|Ignore|Dmg|Plus|Pct|Cpct|Cdmg|Multi)$/.exec(key) + if (tRet) { + attr[tRet[1]][tRet[2].toLowerCase()] += val * 1 || 0 + return + } + let aRet = /^(hp|def|atk|mastery|cpct|cdmg|heal|recharge|dmg|phy|shield|speed)(Plus|Pct|Inc)?$/.exec(key) + if (aRet) { + attr[aRet[1]][aRet[2] ? aRet[2].toLowerCase() : 'plus'] += val * 1 || 0 + return + } + if (key === 'enemyDef') { + attr.enemy.def += val * 1 || 0 + return + } + if (key === 'ignore' || key === 'enemyIgnore') { + attr.enemy.ignore += val * 1 || 0 + return + } + + if (['vaporize', 'melt', 'burning', 'superConduct', 'swirl', 'electroCharged', 'shatter', 'overloaded', 'bloom', 'burgeon', 'hyperBloom', 'aggravate', 'spread', 'kx', 'fykx'].includes(key)) { + attr[key] += val * 1 || 0 + return + } + + let dRet = /^(dot)(Dmg|EnemyDmg)$/.exec(key) + if (dRet) { + attr[dRet[1]][dRet[2].toLowerCase()] += val * 1 || 0 + } + }) + msg.push(title) + }) + + return { + attr, msg + } + } +} +export default DmgAttr diff --git a/Yunzai/plugins/miao-plugin/models/profile/DmgBuffs.js b/Yunzai/plugins/miao-plugin/models/profile/DmgBuffs.js new file mode 100644 index 0000000000000000000000000000000000000000..1ed3abdf8839c9c70ef0e87c3c30fbf539905c3e --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/DmgBuffs.js @@ -0,0 +1,109 @@ +/* +* 伤害计算 - Buff计算 +* */ +import lodash from 'lodash' +import { ProfileArtis, ArtifactSet, Weapon } from '../index.js' + +/* +理论参考:www.miyoushe.com/ys/article/32359316 +sort: 各级数值含义及分类规则 +1 默认 常规区数值,不涉及二次转化 + 基于基础区(基础攻击、防御、生命)的数值提升,e.g. 圣遗物、武器直接的百分比攻击力提升 + 固定数值加成,e.g. 万叶二命的200精通加成 + +#其他属性:指除了元素充能和最大生命值以外的区间 +4 基于元素充能的属性转化,e.g. 雷电将军天赋,基于元素充能提升攻击力;薙刀,基于元素充能提升攻击力;绝缘套,基于充能提升q伤害 +5 基于最大生命值向元素精通的转化,e.g. 圣显之钥,基于最大生命值提升元素精通 +6 基于元素精通向元素充能/其他属性(除了元素精通)的转化,e.g. 西福斯的月光,基于元素精通提升元素充能;赤沙之杖,基于元素精通提升攻击力 + *特例,旅行者战技的20充能加成和心海6命40%水伤加成,这两个虽然是固定数值提升,但是数值在额外区,所以sort放在这里 +7 基于其他属性向元素精通的属性转化,e.g. 纳西妲天赋,基于自身元素精通提升在场角色元素精通 + +9 总计值转化 + 基于最大生命值的转化/其他属性的【有限定条件】的向增伤/双爆/伤害值的属性转化, (限定条件:特定技能/召唤物限定 + e.g. 胡桃e,基于最大生命值提升攻击力 + 妮露天赋,基于最大生命值提升丰穰之核伤害 + 赛诺天赋,基于元素精通提升特定技能伤害;八重天赋,基于元素精通提升e伤害; + 纳西妲Q,基于元素精通提升e双爆 + 天空系列武器,基于攻击力造成物理伤害,视作对基础倍率区的直接提升;辰砂之纺锤,基于最大防御力提升e伤害值 + *最大防御力的某些转化也可以算在这里,e.g. 一斗开Q,基于最大防御力提升攻击力 + 基于元素精通提升反应伤害,e.g. 蒸发、融化、激化反应的Buff栏展示需要,实际上不影响具体伤害计算 +10 最终计算区,直接影响具体伤害乘区,可以视作在dmgCalc.js中,实际上没有sort: 10这种情况 +*/ +let DmgBuffs = { + getBuffs (profile, buffs = [], game = 'gs') { + let weaponBuffs = DmgBuffs.getWeaponBuffs(profile.weapon, game) + let artisBuffs = DmgBuffs.getArtisBuffs(profile.artis, game) + buffs = lodash.concat(buffs, weaponBuffs, artisBuffs) + let mKey = { + vaporize: '蒸发', + melt: '融化', + swirl: '扩散' + } + let mKey2 = { + aggravate: '超激化', + spread: '蔓激化' + } + buffs = lodash.filter(buffs, (b) => !!b) + lodash.forEach(buffs, (buff, idx) => { + if (lodash.isString(buff)) { + if (mKey[buff]) { + buff = { + title: `元素精通:${mKey[buff]}伤害提高[_${buff}]%`, + mastery: buff, + sort: 9 + } + buffs[idx] = buff + } else if (mKey2[buff]) { + buff = { + title: `元素精通:${mKey2[buff]}伤害提高[_${buff}]%,造成的伤害值提升[_${buff}num]`, + mastery: buff, + sort: 9 + } + buffs[idx] = buff + } + } + buff.sort = lodash.isUndefined(buff.sort) ? 1 : buff.sort + }) + buffs = lodash.sortBy(buffs, ['sort']) + return buffs + }, + // 圣遗物Buff + getArtisBuffs (artis = {}, game = 'gs') { + let retBuffs = [] + ProfileArtis._eachArtisSet(artis, (sets, num) => { + let buffs = ArtifactSet.getArtisSetBuff(sets.name, num, game) + if (lodash.isPlainObject(buffs)) { + buffs = [buffs] + } + lodash.forEach(buffs, (buff) => { + if (buff && !buff.isStatic) { + retBuffs.push({ + ...buff, + title: `${sets.name}${num}:` + buff.title + }) + } + }) + }) + return retBuffs + }, + + // 武器Buff + getWeaponBuffs (wData, game = 'gs') { + let weapon = Weapon.get(wData.name, game) + if (!weapon) { + return false + } + let affix = wData.refine || wData.affix + let weaponCfg = weapon.getWeaponAffixBuffs(affix, false) + + let ret = [] + lodash.forEach(weaponCfg, (ds) => { + if (ds.isStatic) { + return true + } + ret.push(ds) + }) + return ret + } +} +export default DmgBuffs diff --git a/Yunzai/plugins/miao-plugin/models/profile/DmgCalc.js b/Yunzai/plugins/miao-plugin/models/profile/DmgCalc.js new file mode 100644 index 0000000000000000000000000000000000000000..7234f5deba9d633b6cd933c5daa78960a1dc10c9 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/DmgCalc.js @@ -0,0 +1,281 @@ +/* +* 伤害计算 - 计算伤害 +* */ +import { eleBaseDmg, erTitle, breakBaseDmg } from './DmgCalcMeta.js' +import DmgMastery from './DmgMastery.js' + +let DmgCalc = { + calcRet (fnArgs = {}, data = {}) { + let { + pctNum, // 技能倍率 + talent, // 天赋类型 + ele, // 元素反应 + basicNum, // 基础数值 + mode, // 模式 + dynamicDmg = 0, // 动态增伤 + dynamicCdmg = 0, // 动态暴击伤害 + dynamicEnemyDmg = 0 // 动态易伤 + } = fnArgs + let { + ds, // 数据集 + attr, // 属性 + level, // 面板数据 + enemyLv, // 敌人等级 + showDetail = false, // 是否展示详情 + game + } = data + let calc = ds.calc + + let { atk, dmg, phy, cdmg, cpct, enemyDmg } = attr + + // 攻击区 + let atkNum = calc(atk) + + // 倍率独立乘区 + let multiNum = attr.multi / 100 + + // 增伤区 + let dmgNum = (1 + dmg.base / 100 + dmg.plus / 100 + dynamicDmg / 100) + + if (ele === 'phy') { + dmgNum = (1 + phy.base / 100 + phy.plus / 100) + } + + // 易伤区 + let enemyDmgNum = 1 + if (game === 'sr') { + enemyDmgNum = 1 + enemyDmg.base / 100 + enemyDmg.plus / 100 + dynamicEnemyDmg / 100 + } + + let cpctNum = cpct.base / 100 + cpct.plus / 100 + + // 爆伤区 + let cdmgNum = cdmg.base / 100 + cdmg.plus / 100 + dynamicCdmg / 100 + + let enemyDef = attr.enemy.def / 100 + let enemyIgnore = attr.enemy.ignore / 100 + + let plusNum = 0 + + if (talent && attr[talent]) { + pctNum = pctNum / 100 + + let ds = attr[talent] + + pctNum += ds.pct / 100 + dmgNum += ds.dmg / 100 + enemyDmgNum += game === 'gs' ? 0 : ds.enemydmg / 100 + cpctNum += ds.cpct / 100 + cdmgNum += ds.cdmg / 100 + enemyDef += ds.def / 100 + enemyIgnore += ds.ignore / 100 + multiNum += ds.multi / 100 + plusNum += ds.plus + } + + // 防御区 + let defNum = (level + 100) / ((level + 100) + (enemyLv + 100) * (1 - enemyDef) * (1 - enemyIgnore)) + if (game === 'sr') { + let enemyDefdown = enemyDef + enemyIgnore <= 1 ? enemyDef + enemyIgnore : 1 + defNum = (200 + level * 10) / ((200 + level * 10) + (200 + enemyLv * 10) * (1 - enemyDefdown)) + } + + // 抗性区 + let kx = attr.kx + let kNum = 0.9 + if (game === 'sr') { + kNum = (1 + (kx / 100)) * 0.9 + } else { + if (ele === 'swirl') { + kx = attr.fykx + } + kx = 10 - (kx || 0) + if (kx >= 75) { + kNum = 1 / (1 + 3 * kx / 100) + } else if (kx >= 0) { + kNum = (100 - kx) / 100 + } else { + kNum = 1 - kx / 200 + } + } + + cpctNum = Math.max(0, Math.min(1, cpctNum)) + if (cpctNum === 0) { + cdmgNum = 0 + } + + const isEle = ele !== false && ele !== 'phy' + // 反应区 + let eleNum = 1 + let eleBase = 1 + if (game === 'gs') { + eleNum = isEle ? DmgMastery.getBasePct(ele, attr.element) : 1 + eleBase = isEle ? 1 + attr[ele] / 100 + DmgMastery.getMultiple(ele, calc(attr.mastery)) : 1 + } + + let breakDotBase = 1 + let stanceNum = 1 + if (game === 'sr') { + switch (ele) { + case 'skillDot': { + pctNum = pctNum / 100 + dmgNum += attr.dot.dmg / 100 + enemyDmgNum += attr.dot.enemydmg / 100 + break + } + case 'shock': + case 'burn': + case 'windShear': + case 'bleed': + case 'entanglement': + case 'lightningBreak': + case 'fireBreak': + case 'windBreak': + case 'physicalBreak': + case 'quantumBreak': + case 'imaginaryBreak': { + eleNum = DmgMastery.getBasePct(ele, attr.element) + stanceNum = 1 + calc(attr.stance) / 100 + enemyDmgNum += attr.dot.enemydmg / 100 + break + } + default: + break + } + } + + let dmgBase = (mode === 'basic') ? basicNum + plusNum : atkNum * pctNum * (1 + multiNum) + plusNum + let ret = {} + + switch (ele) { + case 'vaporize': + case 'melt': { + ret = { + dmg: dmgBase * dmgNum * (1 + cdmgNum) * defNum * kNum * eleBase * eleNum, + avg: dmgBase * dmgNum * (1 + cpctNum * cdmgNum) * defNum * kNum * eleBase * eleNum + } + break + } + + case 'burning': + case 'superConduct': + case 'swirl': + case 'electroCharged': + case 'shatter': + case 'overloaded': + case 'bloom': + case 'burgeon': + case 'hyperBloom': { + eleBase *= eleBaseDmg[level] + ret = { avg: eleBase * eleNum * kNum } + break + } + + case 'aggravate': + case 'spread': { + eleBase *= eleBaseDmg[level] + dmgBase += eleBase * eleNum + ret = { + dmg: dmgBase * dmgNum * (1 + cdmgNum) * defNum * kNum, + avg: dmgBase * dmgNum * (1 + cpctNum * cdmgNum) * defNum * kNum + } + break + } + + case 'skillDot': { + ret = { + avg: dmgBase * dmgNum * enemyDmgNum * defNum * kNum + } + break + } + + // 未计算层数(风化、纠缠)和韧性条系数(击破、纠缠) + case 'shock': + case 'burn': + case 'windShear': + case 'bleed': + case 'entanglement': + case 'lightningBreak': + case 'fireBreak': + case 'windBreak': + case 'physicalBreak': + case 'quantumBreak' : + case 'imaginaryBreak':{ + breakDotBase *= breakBaseDmg[level] + ret = { + avg: breakDotBase * eleNum * stanceNum * enemyDmgNum * defNum * kNum + } + break + } + + default: { + ret = { + dmg: dmgBase * dmgNum * enemyDmgNum * (1 + cdmgNum) * defNum * kNum, + avg: dmgBase * dmgNum * enemyDmgNum * (1 + cpctNum * cdmgNum) * defNum * kNum + } + } + } + + if (showDetail) { + console.log('Attr', attr) + console.log({ mode, dmgBase, atkNum, pctNum, multiNum, plusNum, dmgNum, enemyDmgNum, stanceNum, cpctNum, cdmgNum, defNum, eleNum, kNum }) + console.log('Ret', ret) + } + + return ret + }, + getDmgFn (data) { + let { showDetail, attr, ds, game } = data + let { calc } = ds + + let dmgFn = function (pctNum = 0, talent = false, ele = false, basicNum = 0, mode = 'talent', dynamicData = false) { + if (ele) { + ele = erTitle[ele] || ele + } + if (game === 'sr') { + // 星铁meta数据天赋为百分比前数字 + pctNum = pctNum * 100 + } + return DmgCalc.calcRet({ pctNum, talent, ele, basicNum, mode, ...dynamicData }, data) + } + + dmgFn.basic = function (basicNum = 0, talent = false, ele = false, dynamicData = false) { + return dmgFn(0, talent, ele, basicNum, 'basic', dynamicData) + } + + dmgFn.reaction = function (ele = false) { + return dmgFn(0, 'fy', ele, 0, 'basic') + } + + dmgFn.dynamic = function (pctNum = 0, talent = false, dynamicData = false, ele = false) { + return dmgFn(pctNum, talent, ele, 0, 'talent', dynamicData) + } + + // 计算治疗 + dmgFn.heal = function (num) { + if (showDetail) { + console.log(num, calc(attr.heal), attr.heal.inc) + } + return { + avg: num * (1 + calc(attr.heal) / 100 + attr.heal.inc / 100) + } + } + + // 计算护盾 + dmgFn.shield = function (num) { + if (showDetail) { + console.log(num, calc(attr.shield), calc(attr.shield.inc)) + } + return { + avg: num * (calc(attr.shield) / 100) * (attr.shield.inc / 100) + } + } + // 扩散方法 + dmgFn.swirl = function () { + return dmgFn(0, 'fy', 'swirl') + } + + return dmgFn + } +} +export default DmgCalc diff --git a/Yunzai/plugins/miao-plugin/models/profile/DmgCalcMeta.js b/Yunzai/plugins/miao-plugin/models/profile/DmgCalcMeta.js new file mode 100644 index 0000000000000000000000000000000000000000..ddc02881481fe97dac595aeddb819e242434b416 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/DmgCalcMeta.js @@ -0,0 +1,218 @@ +import lodash from 'lodash' + +// 元素反应类型及基数 +export const erType = { + // 增幅反应 + vaporize: { type: 'pct', num: ({ element }) => element === '水' ? 2 : 1.5, title: '蒸发' }, + melt: { type: 'pct', num: ({ element }) => element === '火' ? 2 : 1.5, title: '融化' }, + // 剧变反应 + burning: { type: 'fusion', num: () => 1, title: '燃烧' }, + superConduct: { type: 'fusion', num: () => 2, title: '超导' }, + swirl: { type: 'fusion', num: () => 2.4, title: '扩散' }, + electroCharged: { type: 'fusion', num: () => 4.8, title: '感电' }, + shatter: { type: 'fusion', num: () => 6, title: '碎冰' }, + overloaded: { type: 'fusion', num: () => 8, title: '超载' }, + bloom: { type: 'fusion', num: () => 8, title: '绽放' }, + burgeon: { type: 'fusion', num: () => 12, title: '烈绽放' }, + hyperBloom: { type: 'fusion', num: () => 12, title: '超绽放' }, + // 激化反应 + aggravate: { type: 'bonus', num: () => 4.6, title: '超激化' }, + spread: { type: 'bonus', num: () => 5.0, title: '蔓激化' }, + // 击破持续伤害 + shock: { type: 'breakDot', num: () => 2.0, title: '触电' }, + burn: { type: 'breakDot', num: () => 1.0, title: '灼烧' }, + windShear: { type: 'breakDot', num: () => 1.0, title: '风化' }, + bleed: { type: 'breakDot', num: () => 1.0, title: '裂伤' }, + // 击破附加伤害 + entanglement: { type: 'breakPlus', num: () => 0.6, title: '纠缠' }, + // 击破伤害 + ligntningBreak: { type: 'break', num: () => 1.0, title: '雷击破' }, + fireBreak: { type: 'break', num: () => 2.0, title: '火击破' }, + windBreak: { type: 'break', num: () => 1.5, title: '风击破' }, + physicalBreak: { type: 'break', num: () => 2.0, title: '物理击破' }, + quantumBreak: { type: 'break', num: () => 0.5, title: '量子击破' }, + imaginaryBreak: { type: 'break', num: () => 0.5, title: '虚数击破' } +} +let erTmp = {} +lodash.forEach(erType, (er, key) => { + erTmp[er.title] = key +}) +export const erTitle = erTmp + +// 各等级精通基础伤害 +export const eleBaseDmg = { + 1: 4.291, + 2: 4.634, + 3: 4.976, + 4: 5.319, + 5: 5.661, + 6: 6.162, + 7: 6.660, + 8: 7.217, + 9: 7.842, + 10: 8.536, + 11: 9.300, + 12: 10.165, + 13: 11.112, + 14: 12.141, + 15: 13.437, + 16: 14.770, + 17: 16.105, + 18: 17.431, + 19: 18.781, + 20: 20.146, + 21: 21.528, + 22: 22.926, + 23: 24.311, + 24: 25.703, + 25: 27.102, + 26: 28.300, + 27: 29.526, + 28: 30.745, + 29: 32.432, + 30: 34.073, + 31: 35.668, + 32: 37.257, + 33: 38.854, + 34: 40.456, + 35: 42.277, + 36: 44.130, + 37: 46.018, + 38: 47.927, + 39: 49.889, + 40: 51.846, + 41: 53.850, + 42: 56.041, + 43: 58.376, + 44: 60.838, + 45: 64.016, + 46: 67.136, + 47: 70.382, + 48: 73.753, + 49: 77.267, + 50: 80.900, + 51: 84.189, + 52: 87.633, + 53: 91.121, + 54: 94.655, + 55: 99.650, + 56: 104.100, + 57: 108.597, + 58: 113.238, + 59: 118.152, + 60: 123.221, + 61: 128.392, + 62: 134.776, + 63: 141.378, + 64: 148.135, + 65: 156.111, + 66: 162.868, + 67: 169.874, + 68: 176.949, + 69: 184.168, + 70: 191.410, + 71: 198.693, + 72: 206.169, + 73: 212.789, + 74: 219.436, + 75: 228.557, + 76: 236.687, + 77: 244.853, + 78: 252.806, + 79: 261.198, + 80: 269.361, + 81: 277.499, + 82: 285.744, + 83: 294.092, + 84: 302.546, + 85: 313.459, + 86: 322.238, + 87: 331.371, + 88: 340.864, + 89: 351.274, + 90: 361.713 +} + +// 各等级击破基础伤害 +export const breakBaseDmg = { + 1: 54.00, + 2: 58.00, + 3: 62.00, + 4: 67.53, + 5: 70.51, + 6: 73.52, + 7: 76.57, + 8: 79.64, + 9: 82.74, + 10: 85.87, + 11: 91.49, + 12: 97.07, + 13: 102.59, + 14: 108.06, + 15: 113.47, + 16: 118.84, + 17: 124.15, + 18: 129.41, + 19: 134.62, + 20: 139.77, + 21: 149.33, + 22: 158.80, + 23: 168.18, + 24: 177.46, + 25: 186.65, + 26: 195.75, + 27: 204.75, + 28: 213.66, + 29: 222.48, + 30: 231.20, + 31: 246.43, + 32: 261.18, + 33: 275.47, + 34: 289.32, + 35: 302.73, + 36: 315.71, + 37: 328.29, + 38: 340.47, + 39: 352.26, + 40: 363.67, + 41: 408.12, + 42: 451.79, + 43: 494.68, + 44: 536.82, + 45: 578.22, + 46: 618.92, + 47: 658.91, + 48: 698.23, + 49: 736.89, + 50: 774.90, + 51: 871.06, + 52: 964.87, + 53: 1056.42, + 54: 1145.79, + 55: 1233.06, + 56: 1318.30, + 57: 1401.58, + 58: 1482.96, + 59: 1562.52, + 60: 1640.31, + 61: 1752.32, + 62: 1861.90, + 63: 1969.12, + 64: 2074.07, + 65: 2176.80, + 66: 2277.39, + 67: 2375.91, + 68: 2472.42, + 69: 2566.97, + 70: 2659.64, + 71: 2780.30, + 72: 2898.60, + 73: 3014.60, + 74: 3128.37, + 75: 3239.98, + 76: 3349.47, + 77: 3456.92, + 78: 3562.38, + 79: 3665.91, + 80: 3767.55 +} diff --git a/Yunzai/plugins/miao-plugin/models/profile/DmgMastery.js b/Yunzai/plugins/miao-plugin/models/profile/DmgMastery.js new file mode 100644 index 0000000000000000000000000000000000000000..0c511b5b59f72b8d4e8ab1ad0938afbb8b03bcbb --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/DmgMastery.js @@ -0,0 +1,23 @@ +import { erType } from './DmgCalcMeta.js' + +let DmgMastery = { + getMultiple (type, mastery = 0) { + let typeCfg = erType[type] + if (typeCfg.type === 'pct') { + return (25 / 9) * mastery / (mastery + 1400) + } else if (typeCfg.type === 'fusion') { + return 16 * mastery / (mastery + 2000) + } else if (typeCfg.type === 'bonus') { + return 5 * mastery / (mastery + 1200) + } + return 0 + }, + getBasePct (type, element) { + let typeCfg = erType[type] + if (typeCfg) { + return typeCfg.num({ element }) || 1 + } + return 1 + } +} +export default DmgMastery diff --git a/Yunzai/plugins/miao-plugin/models/profile/ProfileInput.js b/Yunzai/plugins/miao-plugin/models/profile/ProfileInput.js new file mode 100644 index 0000000000000000000000000000000000000000..ef28a546d188dded0b07603beafc68431bc607f4 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/models/profile/ProfileInput.js @@ -0,0 +1,2 @@ +let ProfileInput = {} +export default ProfileInput \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/package.json b/Yunzai/plugins/miao-plugin/package.json new file mode 100644 index 0000000000000000000000000000000000000000..0feebe9bcc4ccd68dcc22357b78373349a84e76a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/package.json @@ -0,0 +1,23 @@ +{ + "name": "miao-plugin", + "version": "2.3.3", + "author": "Yoimiya-Kokomi", + "description": "miao-plugin", + "type": "module", + "scripts": { + }, + "dependencies": { + "image-size": "^1.0.2" + }, + "devDependencies": { + "cheerio": "1.0.0-rc.12", + "request": "^2.88.2" + }, + "imports": { + "#miao": "./components/index.js", + "#miao.models": "./models/index.js" + }, + "pnpm": { + "patchedDependencies": {} + } +} diff --git a/Yunzai/plugins/miao-plugin/resources/admin/imgs/bg.png b/Yunzai/plugins/miao-plugin/resources/admin/imgs/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..e0909eb966fe1d3e92d12de66f2d9707226bb94f --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/admin/imgs/bg.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ae827c9128731922bec26f0eeb26858ed289f28e95f1b62bafff3c944fb39fa +size 2408984 diff --git a/Yunzai/plugins/miao-plugin/resources/admin/imgs/cfg-right.jpg b/Yunzai/plugins/miao-plugin/resources/admin/imgs/cfg-right.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5bf552ad52eef0efd261e3efbf836ac303af058b Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/admin/imgs/cfg-right.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/admin/imgs/cfg-right.png b/Yunzai/plugins/miao-plugin/resources/admin/imgs/cfg-right.png new file mode 100644 index 0000000000000000000000000000000000000000..fcee36757d606d5c8f89b5dfe6431bfe8a87b519 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/admin/imgs/cfg-right.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/admin/index.css b/Yunzai/plugins/miao-plugin/resources/admin/index.css new file mode 100644 index 0000000000000000000000000000000000000000..4098b4cc275df2997d76b5740ce5048757bd190c --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/admin/index.css @@ -0,0 +1,75 @@ +body { + transform: scale(1); + width: 660px; +} +.container { + background: url("./imgs/bg.png") #000144 left top no-repeat; + background-size: 700px auto; + width: 660px; +} +.head-box { + margin: 0 0 80px 0; +} +.cfg-box { + border-radius: 15px; + margin-top: 20px; + margin-bottom: 20px; + padding: 5px 15px; + overflow: hidden; + background: #f5f5f5; + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.15); + position: relative; + background: rgba(35, 38, 57, 0.8); +} +.cfg-group { + color: #ceb78b; + font-size: 18px; + font-weight: bold; + padding: 10px 20px; +} +.cfg-li { + border-radius: 18px; + min-height: 36px; + position: relative; + overflow: hidden; + margin-bottom: 10px; + background: rgba(203, 196, 190, 0); +} +.cfg-line { + color: #4e5769; + line-height: 36px; + padding-left: 20px; + font-weight: bold; + border-radius: 16px; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.5); + background: url("./imgs/cfg-right.jpg") right top #cbc4be no-repeat; + background-size: auto 36px; +} +.cfg-hint { + font-size: 12px; + font-weight: normal; + margin-top: 3px; + margin-bottom: -3px; +} +.cfg-status { + position: absolute; + top: 0; + right: 0; + height: 36px; + width: 160px; + text-align: center; + line-height: 36px; + font-size: 16px; + color: #495366; + font-weight: bold; + border-radius: 0 16px 16px 0; +} +.cfg-status.status-off { + color: #a95151; +} +.cfg-desc { + font-size: 12px; + color: #cbc4be; + margin: 5px 0 5px 20px; +} +/*# sourceMappingURL=index.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/admin/index.html b/Yunzai/plugins/miao-plugin/resources/admin/index.html new file mode 100644 index 0000000000000000000000000000000000000000..21cfa4560cac905ffa8a80c1cd0149739192fdc0 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/admin/index.html @@ -0,0 +1,61 @@ +{{extend defaultLayout}} +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/admin/index.css"/> +{{/block}} +{{block 'main'}} + +<div class="info_box"> + <div class="head-box type{{bgType}}"> + <div class="label">喵喵管理面板</div> + <div class="title">#喵喵设置</div> + </div> +</div> +{{each schema cfgGroup}} +<div class="cfg-box"> + <div class="cfg-group">{{cfgGroup.title}}</div> + <ul class="cfg-ul"> + {{each cfgGroup.cfg cfgItem cfgKey}} + <li class="cfg-li"> + <div class="cfg-line"> + {{cfgItem.title}} + {{if !(cfgItem.miao && isMiao) }} + <span class="cfg-hint"> #喵喵设置{{cfgItem.key}} + {{if cfgItem.type==='num'}} {{cfgItem.def}}{{else}} 开启/关闭{{/if}} + </span> + {{/if}} + {{if cfgItem.type === 'num'}} + <div class="cfg-status">{{cfg[cfgKey]}}</div> + {{else}} + {{if cfg[cfgKey] || (cfgItem.miao && isMiao)}} + <div class="cfg-status">{{cfgItem.miao && isMiao ? '默认开启' : '已开启'}}</div> + {{else}} + <div class="cfg-status status-off">已关闭</div> + {{/if}} + {{/if}} + </div> + {{if cfgItem.desc && cfgItem.showDesc!== false}} + <div class="cfg-desc">{{cfgItem.desc}}</div> + {{/if}} + </li> + {{/each}} + </ul> +</div> +{{/each}} +<div class="cfg-box"> + <div class="cfg-group">其他设置</div> + <ul class="cfg-ul"> + <li class="cfg-li"> + <div class="cfg-line"> + 角色图片扩展包 + <span class="cfg-hint"> #喵喵更新图像</span> + {{if imgPlus}} + <div class="cfg-status">已安装</div> + {{else}} + <div class="cfg-status status-off">未安装</div> + {{/if}} + </div> + <div class="cfg-desc">安装角色的扩展插图,图片较多可能需要一定时间,在返回提示前请勿重复执行</div> + </li> + </ul> +</div> +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/admin/index.less b/Yunzai/plugins/miao-plugin/resources/admin/index.less new file mode 100644 index 0000000000000000000000000000000000000000..5c7acf7418f2539e46dbb32b84f05fe12fd0f5df --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/admin/index.less @@ -0,0 +1,89 @@ +body { + transform: scale(1); + width: 660px; +} + +.container { + background: url("./imgs/bg.png") #000144 left top no-repeat; + background-size: 700px auto; + width:660px; +} + +.head-box { + margin: 0 0 80px 0; +} + +.cfg-box { + border-radius: 15px; + margin-top: 20px; + margin-bottom: 20px; + padding: 5px 15px; + overflow: hidden; + background: #f5f5f5; + box-shadow: 0 5px 10px 0 rgb(0 0 0 / 15%); + position: relative; + background: rgba(35, 38, 57, .8); +} + + +.cfg-group { + color: #ceb78b; + font-size: 18px; + font-weight: bold; + padding: 10px 20px; +} + +.cfg-ul { + +} + +.cfg-li { + border-radius: 18px; + min-height: 36px; + position: relative; + overflow: hidden; + margin-bottom: 10px; + background: rgba(203, 196, 190, 0); +} + +.cfg-line { + color: #4e5769; + line-height: 36px; + padding-left: 20px; + font-weight: bold; + border-radius: 16px; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.5); + background: url("./imgs/cfg-right.jpg") right top #cbc4be no-repeat; + background-size: auto 36px; +} + +.cfg-hint { + font-size: 12px; + font-weight: normal; + margin-top: 3px; + margin-bottom: -3px; +} + +.cfg-status { + position: absolute; + top: 0; + right: 0; + height: 36px; + width: 160px; + text-align: center; + line-height: 36px; + font-size: 16px; + color: #495366; + font-weight: bold; + border-radius: 0 16px 16px 0; +} + +.cfg-status.status-off { + color: #a95151; +} + +.cfg-desc { + font-size: 12px; + color: #cbc4be; + margin: 5px 0 5px 20px; +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/admin/profile.css b/Yunzai/plugins/miao-plugin/resources/admin/profile.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Yunzai/plugins/miao-plugin/resources/admin/profile.html b/Yunzai/plugins/miao-plugin/resources/admin/profile.html new file mode 100644 index 0000000000000000000000000000000000000000..08c77271bbb581192db20fb216639625fa4600e2 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/admin/profile.html @@ -0,0 +1,59 @@ +{{extend defaultLayout}} + +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/admin/index.css"/> +<link rel="stylesheet" type="text/css" href="{{_res_path}}/admin/index.css"/> +<link rel="stylesheet" type="text/css" href="{{_res_path}}/admin/profile.css"/> +{{/block}} + +{{block 'main'}} + +<div class="info_box"> + <div class="head-box type{{bgType}}"> + <div class="label">角色面板管理</div> + <div class="title">#喵喵面板设置</div> + </div> +</div> +<div class="cfg-box"> + <div class="cfg-group">#角色面板开放范围</div> + <ul class="cfg-ul"> + <li class="cfg-li"> + <div class="cfg-line"> + 好友 + <span class="cfg-hint"> #喵喵面板设置好友 + 开启/关闭</span> + {{@friend}} + </div> + </li> + <li class="cfg-li"> + <div class="cfg-line"> + 陌生人 + <span class="cfg-hint"> #喵喵面板设置陌生人 + 开启/关闭</span> + {{@stranger}} + </div> + </li> + <li class="cfg-li"> + <div class="cfg-line"> + 群 + <span class="cfg-hint"> #喵喵面板设置群 + 开启/关闭</span> + {{@group}} + </div> + <div class="cfg-desc">若下方无指定群设置,默认使用此设置</div> + </li> + </ul> +</div> +<div class="cfg-box"> + <div class="cfg-group">指定群设置</div> + <div class="cfg-desc">#喵喵面板设置群123456 + 开启/关闭/删除。对应群号会优先使用</div> + <ul class="cfg-ul"> + {{each groups group}} + <li class="cfg-li"> + <div class="cfg-line"> + {{group.group}} + {{@group.status}} + </div> + </li> + {{/each}} + + </ul> +</div> +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/admin/profile.less b/Yunzai/plugins/miao-plugin/resources/admin/profile.less new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Yunzai/plugins/miao-plugin/resources/character-img/default/01.jpg b/Yunzai/plugins/miao-plugin/resources/character-img/default/01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22ab033ffddc11aa23a61e7f48b34f312de797b3 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character-img/default/01.jpg differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\344\270\203\344\270\203/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\270\203\344\270\203/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..e0f5a341f3bad52f06d7d0c96afbb8b080113c20 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\270\203\344\270\203/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\344\270\275\350\216\216/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\270\275\350\216\216/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..572c2e790f823eede8d0736f7c54f3f70ad3f69f Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\270\275\350\216\216/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\344\271\205\345\262\220\345\277\215/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\271\205\345\262\220\345\277\215/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..5cde7b2ad2767e8ac66f13e6fd20855f1c691917 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\271\205\345\262\220\345\277\215/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\344\271\235\346\235\241\350\243\237\347\275\227/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\271\235\346\235\241\350\243\237\347\275\227/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..a02412e0725d56b325b1411ec15ba13b5be758eb Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\271\235\346\235\241\350\243\237\347\275\227/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\344\272\221\345\240\207/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\272\221\345\240\207/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..5f645a2c942f0a30d30adbea7abda706086ecbec Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\272\221\345\240\207/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\344\272\224\351\203\216/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\272\224\351\203\216/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..71288876ce2a48c2e539650961c108ac24699ed3 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\272\224\351\203\216/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\344\274\220\351\232\276/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\274\220\351\232\276/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..b44ee184bbd5a136c28d5b6332d9d10f2aa96fe0 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\274\220\351\232\276/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\344\274\230\350\217\210/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\274\230\350\217\210/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..2c53c1ea65251099a26853c474b994f50934f7b1 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\344\274\230\350\217\210/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\205\253\351\207\215\347\245\236\345\255\220/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\205\253\351\207\215\347\245\236\345\255\220/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..78e6a1b2c3123530a006768386a399cf29540508 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\205\253\351\207\215\347\245\236\345\255\220/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\207\235\345\205\211/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\207\235\345\205\211/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..60c27836a17356aee50f48db654aae13be498380 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\207\235\345\205\211/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\207\257\344\272\232/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\207\257\344\272\232/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..05ec499a1b6c6473e745cdce0078b9f24700fdf5 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\207\257\344\272\232/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\210\273\346\231\264/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\210\273\346\231\264/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..da26cc0775258bd92682a7ab728aa1c2f5796514 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\210\273\346\231\264/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\214\227\346\226\227/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\214\227\346\226\227/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..172ab9e2b2b32a93f87524be476cafadb7336658 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\214\227\346\226\227/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\215\241\347\232\256\345\241\224\350\257\272/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\215\241\347\232\256\345\241\224\350\257\272/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..bc1f2bb46f13afcb1fcda17798752357f1700634 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\215\241\347\232\256\345\241\224\350\257\272/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\215\241\347\273\264/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\215\241\347\273\264/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..7a8a3cdc1602148afb53d7222c58222b3ebca46c Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\215\241\347\273\264/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\217\257\350\216\211/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\217\257\350\216\211/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..d4336a86626dca211f018379ba2bfe526a13c818 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\217\257\350\216\211/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\223\245\344\274\246\346\257\224\345\250\205/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\223\245\344\274\246\346\257\224\345\250\205/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..5df1afb404292cde71f76eccac82d152ba355170 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\223\245\344\274\246\346\257\224\345\250\205/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\235\216\350\222\202\344\270\235/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\235\216\350\222\202\344\270\235/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..6a324274d32fa1cb036721b5abead64a02cff33e Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\235\216\350\222\202\344\270\235/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\237\203\346\264\233\344\274\212/01.JPG" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\237\203\346\264\233\344\274\212/01.JPG" new file mode 100644 index 0000000000000000000000000000000000000000..b987412b923657fc6ac70565c76d24cf85495b64 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\237\203\346\264\233\344\274\212/01.JPG" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\232\346\211\230\351\233\267/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\232\346\211\230\351\233\267/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..d3723320fe4aaeed6db85c1b2938a9a7ffd3214d Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\232\346\211\230\351\233\267/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\232\350\216\211/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\232\350\216\211/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..b9b1dc0cbe310d2ad287dc0c779c3deef0eecb1e Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\232\350\216\211/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\234\345\205\260/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\234\345\205\260/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..d324e97c74ed4442cf06c587191a719855fc9953 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\234\345\205\260/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\251\347\220\206/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\251\347\220\206/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..d8188f0d40ca20e90921e806fdc3d5987ba45a2a Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\244\251\347\220\206/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\245\263\345\243\253/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\245\263\345\243\253/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..3cb04fa933e9c4addaff1eed8edcf01d102c81b8 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\245\263\345\243\253/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\246\256\351\234\262/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\246\256\351\234\262/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..8d69d4153cdabc96b766cabbf1a3dc6801989b0f Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\246\256\351\234\262/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\256\211\346\237\217/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\256\211\346\237\217/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..43d3943f1aa714379c0e91c77dfbd13cebc5bab0 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\256\211\346\237\217/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\256\265\345\256\253/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\256\265\345\256\253/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..97bd4410ae6944eaacc66ac30855d221dedc3687 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\256\265\345\256\253/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\272\224\350\276\276/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\272\224\350\276\276/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..aa2a20ff9374d9cb53b83efcdfbb2fcdd933005f Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\272\224\350\276\276/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\345\275\222\347\273\210/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\275\222\347\273\210/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..2208f880783dbc2a0118e6ec4c740a98cde9185d Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\345\275\222\347\273\210/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\210\264\345\233\240\346\226\257\351\233\267\345\270\203/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\210\264\345\233\240\346\226\257\351\233\267\345\270\203/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..c1b020bc1c1f702f798f4f856ae3b446f12c6f72 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\210\264\345\233\240\346\226\257\351\233\267\345\270\203/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\211\230\351\251\254/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\211\230\351\251\254/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..cd17ebe6c123882a0c68637ade651054291a2cbf Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\211\230\351\251\254/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\217\220\347\272\263\351\207\214/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\217\220\347\272\263\351\207\214/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..016e13f76db603a50e677187cb0fd963731548eb Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\217\220\347\272\263\351\207\214/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\227\251\346\237\232/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\227\251\346\237\232/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..28a8cca5b7b29d9aeb0623cac73934e67d7d3298 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\227\251\346\237\232/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\236\227\345\260\274/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\236\227\345\260\274/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..63a7110dbddadc3260f4a7d50fa6d552a2945037 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\236\227\345\260\274/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\236\253\345\216\237\344\270\207\345\217\266/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\236\253\345\216\237\344\270\207\345\217\266/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..ef68f869d633774ffe87b10336e4a39a8c2cd2a7 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\236\253\345\216\237\344\270\207\345\217\266/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\237\257\350\216\261/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\237\257\350\216\261/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..75897629146a566015b6073add927f602948b4eb Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\237\257\350\216\261/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\241\221\345\244\232\346\266\205/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\241\221\345\244\232\346\266\205/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..47f38abe40f5f3e1d7614c1b4e1d54125005ef24 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\241\221\345\244\232\346\266\205/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\264\276\350\222\231/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\264\276\350\222\231/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..54b1c16b88392dffbe6619395614dc8d12b0608e Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\264\276\350\222\231/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\265\201\346\265\252\350\200\205/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\265\201\346\265\252\350\200\205/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..e22b978362b8a4ae4fc168bc316c231e0e3eaa74 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\265\201\346\265\252\350\200\205/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\270\251\350\277\252/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\270\251\350\277\252/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..381022ea13e523c32eda5634f46ebc84fb6c5b59 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\270\251\350\277\252/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\346\275\230\345\241\224\347\275\227\346\266\205/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\275\230\345\241\224\347\275\227\346\266\205/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..696db22d75cb0b517d350e4a2885ce4355c92fd6 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\346\275\230\345\241\224\347\275\227\346\266\205/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\203\237\347\273\257/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\203\237\347\273\257/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..c1b7c76c1286a99cffe460961effe66deb252061 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\203\237\347\273\257/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\217\212\347\221\232\345\256\253\345\277\203\346\265\267/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\217\212\347\221\232\345\256\253\345\277\203\346\265\267/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..320f9a5cad0d4f4c183f4362179c7bd4b76a8970 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\217\212\347\221\232\345\256\253\345\277\203\346\265\267/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\217\220\351\234\262\347\217\212/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\217\220\351\234\262\347\217\212/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..2226e20ef9b655ababf0b4bf295bb3c32765dc33 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\217\220\351\234\262\347\217\212/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\217\255\345\260\274\347\211\271/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\217\255\345\260\274\347\211\271/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..2cce59f2d16e1eaba35c520a578f7eccd72c1de4 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\217\255\345\260\274\347\211\271/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\220\263\345\246\256\347\211\271/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\220\263\345\246\256\347\211\271/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..161c5d05c113acef5289936def83ea29edabe84c Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\220\263\345\246\256\347\211\271/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\220\264/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\220\264/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..a26addf3a916282917f7ec84f460bd97c7d7eddf Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\220\264/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\221\266\347\221\266/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\221\266\347\221\266/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..eb644dac463c09339803b311a448f2a5850223ed Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\221\266\347\221\266/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\224\230\351\233\250/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\224\230\351\233\250/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..ed401838b3b1046d66b19ee4c0c5ae080c747d93 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\224\230\351\233\250/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\224\263\351\271\244/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\224\263\351\271\244/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..d3bd82ff4409512c3da29c321b35072871963ff4 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\224\263\351\271\244/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\231\275\346\234\257/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\231\275\346\234\257/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..1dfb851dfb9ef3550e7289c0ba050c07ab777d1d Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\231\275\346\234\257/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\232\256\350\200\266\347\275\227/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\232\256\350\200\266\347\275\227/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..388b261482a2c52b2a298d312c7bf412a82d7f5e Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\232\256\350\200\266\347\275\227/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\240\202\347\263\226/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\240\202\347\263\226/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..a6609052cb56a6b1a0296c59d1232ea34f64da83 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\240\202\347\263\226/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\245\236\351\207\214\347\273\253\344\272\272/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\245\236\351\207\214\347\273\253\344\272\272/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..aaf31dea46dc790c76450359ac0b880b4d5ab3e5 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\245\236\351\207\214\347\273\253\344\272\272/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\245\236\351\207\214\347\273\253\345\215\216/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\245\236\351\207\214\347\273\253\345\215\216/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..0595e2de68a8a4a5e1bbdb4efe6056d6d2831d2b Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\245\236\351\207\214\347\273\253\345\215\216/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\251\272/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\251\272/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..d74548a000195853ba91f7123d83f2bd0af2329b Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\251\272/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\261\263\345\215\241/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\261\263\345\215\241/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..aeeacfd5df3d10a43459164ba7bb3668a2315691 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\261\263\345\215\241/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\272\263\350\245\277\345\246\262/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\272\263\350\245\277\345\246\262/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..7ab68bd257872240aaba3491ec4f55290ffece4d Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\272\263\350\245\277\345\246\262/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\273\256\350\211\257\350\211\257/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\273\256\350\211\257\350\211\257/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..65e44118476f0509ba442c76b33ccfd6512ff5e2 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\273\256\350\211\257\350\211\257/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\347\275\227\350\216\216\350\216\211\344\272\232/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\275\227\350\216\216\350\216\211\344\272\232/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..1a778674979fd3e41620b3061881ba43885760f0 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\347\275\227\350\216\216\350\216\211\344\272\232/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\203\241\346\241\203/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\203\241\346\241\203/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..02fbf0a06028f30a74f00a349f48b89e16ff797d Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\203\241\346\241\203/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\211\276\345\260\224\346\265\267\346\243\256/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\211\276\345\260\224\346\265\267\346\243\256/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..450b55459fb550763ea05d4cc04ee78de4bf80b7 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\211\276\345\260\224\346\265\267\346\243\256/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\212\231\345\256\201\345\250\234/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\212\231\345\256\201\345\250\234/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..eeaefca62ee1e6be091fff9c47466ae95ccfc702 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\212\231\345\256\201\345\250\234/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\212\255\350\212\255\346\213\211/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\212\255\350\212\255\346\213\211/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..fc7a7a01ac8d3ef74adcce51a218120815a4947f Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\212\255\350\212\255\346\213\211/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\215\222\346\263\267\344\270\200\346\226\227/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\215\222\346\263\267\344\270\200\346\226\227/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..312830ef3e0eb6ffc42c651118ef4ae438187327 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\215\222\346\263\267\344\270\200\346\226\227/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\215\247/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\215\247/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..83e096be9f26fe86288a60eab01ae00fee09fbb5 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\215\247/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\216\253\345\250\234/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\216\253\345\250\234/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..3e5eef413337ba3b2e5bc5050f6554b968f7c566 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\216\253\345\250\234/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\216\261\344\276\235\346\213\211/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\216\261\344\276\235\346\213\211/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..ffb0dcf70d0e647525d9cc6c55c0e7d2beb81014 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\216\261\344\276\235\346\213\211/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\216\261\346\254\247\346\226\257\345\210\251/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\216\261\346\254\247\346\226\257\345\210\251/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..046c39e6a365666aaad85c51efb5fd56e0d119de Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\216\261\346\254\247\346\226\257\345\210\251/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\217\262\347\261\263\345\260\274/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\217\262\347\261\263\345\260\274/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..d9a5a072fc5a2c3a056a1129db5644853744630b Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\217\262\347\261\263\345\260\274/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\217\262\350\260\242\345\260\224/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\217\262\350\260\242\345\260\224/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..15e4e9bbe5d1d7e3c5f3679b7cff59ec20c161b5 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\217\262\350\260\242\345\260\224/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\220\215\345\247\245\345\247\245/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\220\215\345\247\245\345\247\245/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..f559e8acff8e9492f6a45b2f3b387caaff7814e9 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\220\215\345\247\245\345\247\245/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\241\214\347\247\213/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\241\214\347\247\213/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..a15519ded775a78c4c8e05e659d28691856c345d Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\241\214\347\247\213/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\257\272\350\211\276\345\260\224/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\257\272\350\211\276\345\260\224/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..38688640ed9aec6b7db628f7e8a813ce0bb2eb14 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\257\272\350\211\276\345\260\224/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\265\233\350\257\272/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\265\233\350\257\272/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..1c72a61d1267522e39fd2be277efb1f20c556b63 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\265\233\350\257\272/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\276\233\347\204\261/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\276\233\347\204\261/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..ba4c183895feb07aa8768c2f41898e8301806fef Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\276\233\347\204\261/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\276\276\350\276\276\345\210\251\344\272\232/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\276\276\350\276\276\345\210\251\344\272\232/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..1bcb859ea0f9fcdf0f91a50382d858b3252cc568 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\276\276\350\276\276\345\210\251\344\272\232/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\277\252\345\215\242\345\205\213/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\277\252\345\215\242\345\205\213/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..9d074468cf7af18776645aa24f756e3c8b40ca96 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\277\252\345\215\242\345\205\213/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\277\252\345\245\245\345\250\234/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\277\252\345\245\245\345\250\234/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..7084b5e5853ac8762fd8b15b76f361377e2153ec Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\277\252\345\245\245\345\250\234/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\350\277\252\345\270\214\351\233\205/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\277\252\345\270\214\351\233\205/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..2bfe575d5b529fa3d37f9e79d17ddda7b223e129 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\350\277\252\345\270\214\351\233\205/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\202\243\347\273\264\350\216\261\347\211\271/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\202\243\347\273\264\350\216\261\347\211\271/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..8c3fc8b7918b226a61f2312dc5016c67acbf8b37 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\202\243\347\273\264\350\216\261\347\211\271/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\207\215\344\272\221/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\207\215\344\272\221/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..199d19e01f36830608b9e2d756d4e1701357f91b Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\207\215\344\272\221/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\222\237\347\246\273/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\222\237\347\246\273/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..f35ca381c58338879e1187a86560a6b03aae1429 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\222\237\347\246\273/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\230\277\350\225\276\345\245\207\350\257\272/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\230\277\350\225\276\345\245\207\350\257\272/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..c908a8463064064e930c978089f6f7d6ff9d0c8f Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\230\277\350\225\276\345\245\207\350\257\272/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\230\277\350\264\235\345\244\232/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\230\277\350\264\235\345\244\232/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..bfdd5c7f60c4d38e8d92c45d53c250c602c0d23f Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\230\277\350\264\235\345\244\232/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\233\267\346\263\275/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\233\267\346\263\275/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..7b3cfa387123a7bce03f45d05e2c463665aa553f Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\233\267\346\263\275/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\233\267\347\224\265\345\260\206\345\206\233/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\233\267\347\224\265\345\260\206\345\206\233/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..4be17b052ecae2baa19b7af554bc9374f6f711ce Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\233\267\347\224\265\345\260\206\345\206\233/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\246\231\350\217\261/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\246\231\350\217\261/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..02a18cd31da6c36e22203c00c4abb170e820d9f6 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\246\231\350\217\261/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\255\210/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\255\210/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..6673560011575632342d5b5d91f27021f4e3cea5 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\255\210/01.jpg" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/character-img/\351\271\277\351\207\216\351\231\242\345\271\263\350\227\217/01.jpg" "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\271\277\351\207\216\351\231\242\345\271\263\350\227\217/01.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..b5eeeaf6672daca29297998c46ac9f7a4398caaa Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/character-img/\351\271\277\351\207\216\351\231\242\345\271\263\350\227\217/01.jpg" differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/artis-list.css b/Yunzai/plugins/miao-plugin/resources/character/artis-list.css new file mode 100644 index 0000000000000000000000000000000000000000..0a49b87aef183174cb8ec9435378c8dede0b30d5 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/artis-list.css @@ -0,0 +1,37 @@ +.container { + width: 790px; +} +.uid { + margin: 20px 10px 10px; + text-shadow: 0 0 3px #000, 2px 2px 4px rgba(0, 0, 0, 0.7); + text-align: right; + color: #fff; +} +.artis { + width: 790px; +} +.artis .item { + height: 190px; + margin-bottom: 10px; + overflow: hidden; +} +.artis .item .avatar { + position: absolute; + right: 0; + top: 24px; + width: 38px; + height: 38px; + border-radius: 50%; + overflow: hidden; + z-index: 3; +} +.artis .item.arti .arti-icon { + right: 10px; + width: 75px; + height: 75px; +} +.artis .item .avatar img { + max-width: 100%; + max-height: 100%; +} +/*# sourceMappingURL=artis-list.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/artis-list.html b/Yunzai/plugins/miao-plugin/resources/character/artis-list.html new file mode 100644 index 0000000000000000000000000000000000000000..fb94a855c47981686d8207ca21ee5834abdb0c0e --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/artis-list.html @@ -0,0 +1,41 @@ +{{extend elemLayout}} + +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/profile-detail.css"/> +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/artis-list.css"/> +{{/block}} + +{{block 'main'}} +<div class="uid">UID {{uid}}</div> + +<div class="artis"> + + {{each artis ds}} + <div class="item arti"> + {{if ds && ds.name && ds.main && ds.main.key && ds.main.key!="undefined"}} + <div class="avatar"> + <img src="{{_res_path}}{{ds.side}}" onerror="whenError(this)"/> + </div> + <div class="arti-icon"> + <div class="img" style="background-image:url({{_res_path}}{{ds.img}})"></div> + </div> + <div class="head"> + <strong>{{ds.name}}</strong> + <span class="mark mark-{{ds.markClass}}"><span>{{ds.mark}}分</span> - {{ds.markClass}}</span> + </div> + <ul class="detail attr"> + <li class="arti-main"><span class="title">{{artisKeyTitle[ds.main?.key]}}</span><span class="val">+{{ds.main?.value}}</span> + </li> + {{each ds.attrs attr}} + {{if attr && attr.key}} + <li class="{{ds.charWeight[attr.key]*1 > 79.9 ?`great`:(ds.charWeight[attr.key]*1>0 ? `useful`:`nouse`)}}"> + <span class="title">{{if attr.eff}}<i class="eff">{{attr.eff || ''}}</i>{{/if}}{{if attr.upNum}}<i class="up-num up-{{attr.upNum}}"></i>{{/if}}{{artisKeyTitle[attr.key]}}</span> + <span class="val">+{{attr.value}}</span></li> + {{/if}} + {{/each}} + </ul> + {{/if}} + </div> + {{/each}} +</div> +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/artis-list.less b/Yunzai/plugins/miao-plugin/resources/character/artis-list.less new file mode 100644 index 0000000000000000000000000000000000000000..f38a3eae8d9e4ea413116da46140cbb7c8347387 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/artis-list.less @@ -0,0 +1,43 @@ +.container { + width: 790px; +} + +.uid { + margin: 20px 10px 10px; + text-shadow: 0 0 3px #000, 2px 2px 4px rgba(0, 0, 0, .7); + text-align: right; + color: #fff; +} + + +.artis { + width: 790px; +} + +.artis .item { + height: 190px; + margin-bottom: 10px; + overflow: hidden; +} + +.artis .item .avatar { + position: absolute; + right: 0; + top: 24px; + width: 38px; + height: 38px; + border-radius: 50%; + overflow: hidden; + z-index: 3; +} + +.artis .item.arti .arti-icon { + right: 10px; + width: 75px; + height: 75px; +} + +.artis .item .avatar img { + max-width: 100%; + max-height: 100%; +} diff --git a/Yunzai/plugins/miao-plugin/resources/character/artis-mark.css b/Yunzai/plugins/miao-plugin/resources/character/artis-mark.css new file mode 100644 index 0000000000000000000000000000000000000000..55f9e87b73bc40738e8c2860c7ffb0914d7a1cca --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/artis-mark.css @@ -0,0 +1,95 @@ +body, +.container { + width: 650px; +} +.container > .cont { + margin-left: 15px; +} +.basic .detail .cont { + margin: 10px 0; +} +.basic:after { + display: none; +} +.arti-stat { + width: 100%; + margin-right: 0; +} +.mark-table { + text-align: center; + font-size: 14px; + line-height: 27px; +} +.mark-table .thead > div { + height: 35px; + line-height: 35px; + vertical-align: middle; + width: 16%; +} +.mark-table .thead > div.th { + width: 20%; +} +.mark-table .thead > div .text { + line-height: 23px; + display: block; +} +.mark-table .thead > div .desc { + font-size: 12px; + display: block; + line-height: 18px; +} +.mark-table .th { + min-width: initial; + padding-right: 0; + text-align: center; +} +.mark-table .td { + font-weight: normal; +} +.cont-msg li { + font-size: 12px; +} +.arti-icon { + width: 30px; +} +.artis { + margin-top: -280px; + width: 650px; + position: relative; + z-index: 2; + padding: 0 10px; +} +.artis .no-bg { + opacity: 0; +} +.artis ul.detail li span { + width: initial; +} +.artis ul.detail li span.mark { + text-align: right; + padding-right: 10px; +} +.artis ul.detail li span.mark:after { + content: "分"; + font-size: 12px; + display: inline-block; + transform: scale(0.8); + margin-right: -1px; +} +.artis .mark-calc { + background: rgba(0, 0, 0, 0.35); + border-radius: 0 0 5px 5px; +} +.artis .mark-calc li.result { + background: rgba(0, 0, 0, 0.7); + height: 30px; + line-height: 30px; +} +.artis .mark-calc li.result .mark { + font-size: 18px; +} +.artis .item { + height: inherit; + width: 200px; +} +/*# sourceMappingURL=artis-mark.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/artis-mark.html b/Yunzai/plugins/miao-plugin/resources/character/artis-mark.html new file mode 100644 index 0000000000000000000000000000000000000000..266711ed402704f55a6d82eb9c32c441a0d144e0 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/artis-mark.html @@ -0,0 +1,228 @@ +{{extend elemLayout}} + +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/profile-detail.css"/> +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/artis-mark.css"/> +{{/block}} + +{{set talent = data.talent}} +{{set dataSource = data.dataSource}} +{{set mark = function(w){ return w > 0 ? ( 46.6 * w / 100 ).toFixed(1) : "-" }; }} + + +{{block 'main'}} +{{set ad = artisDetail}} +<div class="basic"> + <div class="main-pic" + style="background-image:url({{_res_path}}{{splash}})"></div> + <div class="detail"> + <div class="char-name">{{data.name}}</div> + <div class="char-lv">UID {{uid}} - Lv.{{data.level}} + <span class="cons cons-{{data.cons}}">{{data.cons}}命</span></div> + <div class="cont"> + <div class="item arti-stat"> + <div class="arti-class-title">评分规则:{{charCfg.classTitle}}</div> + <div class="arti-stat-ret"> + <div><strong class="mark-{{artisDetail.markClass}}">{{ad.markClass}}</strong><span>圣遗物评级</span></div> + <div><strong>{{ad.mark}}</strong><span>圣遗物总分</span></div> + </div> + </div> + </div> + </div> +</div> + + +<div class="artis"> + <% for(let idx = 1; idx<=(game==='gs'?5:6); idx++) { + let ds = ad?.artis[idx] + %> + {{if idx === 1 && game === 'gs'}} + <div class="item no-bg"></div> + {{/if}} + <div class="item arti {{idx}}"> + {{if ds && ds.name && ds.main && ds.main.key && ds.main.key!="undefined"}} + <div class="arti-icon"> + <div class="img" style="background-image:url({{_res_path}}{{ds.img}})"></div> + <span>+{{ds.level}}</span> + </div> + <div class="head"> + <strong>{{ds.name}}</strong> + <span class="mark mark-{{ds.markClass}}"><span>{{ds.mark}}分</span> - {{ds.markClass}}</span> + </div> + <ul class="detail attr"> + <li class="arti-main"> + <span class="title">{{artisKeyTitle[ds.main.key]}}</span> + <span class="val">+{{ds.main.value}}</span> + {{if idx >1 }} + <span class="mark">{{ mark( ds.main.mark / 6 ) }}</span> + {{else}} + <span class="val"> - </span> + {{/if}} + </li> + {{each ds.attrs attr}} + {{if attr.key}} + <li class="{{ad.charWeight[attr.key]*1 > 79.9 ?`great`:(ad.charWeight[attr.key]*1>0 ? `useful`:`nouse`)}}"><span + class="title">{{if attr.eff}}<i class="eff">{{attr.eff || ''}}</i>{{/if}}{{artisKeyTitle[attr.key]}} </span><span + class="val">+{{attr.value}}</span> + <span class="mark">{{ ( 46.6 / 6 / 100 * attr._mark ).toFixed(1) }}</span> + </li> + {{/if}} + {{/each}} + </ul> + <ul class="detail attr mark-calc"> + <li style="display:none;"></li> + <li> + <span class="title">总分对齐</span> + <span class="val"> + *{{( 66 / (46.6/6/100 * charCfg.posMaxMark[idx]) * 100).toFixed(1)}}% + </span> + </li> + {{if idx>2 || game==='sr' }} + <li> + <span class="title">最优主词缀</span> + <span class="val"> + {{if game==='sr' && idx<=2 }} - {{else}} + {{if ds.main.title === '充能效率'}} + *100% + {{else}} + {{set mainWeight = charCfg?.attrs[ds.main?.key===data.elem?'dmg':ds.main?.key]?.weight || 0}} + *{{(50 + 50 * mainWeight / charCfg.posMaxMark["m"+idx] ).toFixed(0)}}% + {{/if}}{{/if}} + </span> + </li> + {{/if}} + + <li class="result"> + <span class="title">最终得分</span> + <span class="mark">{{ds.mark}}</span> + </li> + </ul> + {{/if}} + </div> + <% } %> +</div> + +{{if changeProfile}} +<div class="cont"> + <div class="cont-footer dmg-desc"> + <strong>该面板为非实际数据。当前替换命令:</strong> {{changeProfile}} + </div> +</div> +{{/if}} + +<!-- 词条规则 --> +<div class="cont"> + <div class="cont-title"> + {{data.name}}评分规则: {{charCfg.classTitle}} + </div> + <div class="cont-table mark-table"> + <div class="tr thead"> + <div class="th">属性</div> + <div>评分权重</div> + <div>词条成长</div> + <div>每点得分</div> + <div>副词条最高分</div> + <div>主词条最高分</div> + </div> + {{each attrMap ds key}} + {{set keyCfg = charCfg.attrs[key]||{} }} + {{if ds.type!== "plus" && keyCfg?.weight > 0}} + <div class="tr"> + <div class="th">{{ds.title}}</div> + <div class="td">{{keyCfg?.weight}}</div> + <div class="td">{{ds.text}}</div> + <div class="td">{{charCfg.attrs[key]?.mark > 0 ? (46.6/6 / 100 * charCfg.attrs[key]?.mark).toFixed(2) : "-"}} + </div> + <div class="td"> + {{if ['元素伤害','物伤加成','治疗加成'].includes(ds.title)}} +     - + {{else}} + {{ mark(keyCfg?.weight) }} + {{/if}} + </div> + <div class="td"> {{ mark(keyCfg?.weight / 3 ) }}</div> + </div> + {{/if}}{{/each}} + </div> + <ul class="cont-msg"> + <li>每个角色有不同的词条评分权重(已隐藏权重为0的词条),后续会逐步扩充不同流派的规则</li> + <li>以权重值100的单词条理论最高分46.6分为基准,根据权重值及当前词条成长计算每点得分</li> + <li><strong>词条得分:</strong> 词条数值 * 当前词条每点得分。小攻击、小防御、小生命折算为对应百分比词条进行计分</li> + <li><strong>原始总分(对齐前):</strong>计算所有副词条的评分之和,沙杯头三个位置附加25%的主词条评分</li> + </ul> +</div> + +<!-- 位置规则 --> +<div class="cont"> + <div class="cont-title"> + 圣遗物评分计算 + </div> + <div class="cont-table mark-table"> + <div class="tr thead"> + + <div class="th">位置</div> + {{if game === 'gs'}} + <div>生之花</div> + <div>死之羽</div> + <div>时之沙</div> + <div>空之杯</div> + <div>理之冠</div> + {{else}} + <div>帽子</div> + <div>手套</div> + <div>衣服</div> + <div>靴子</div> + <div>球</div> + <div>绳</div> + {{/if}} + </div> + <div class="tr"> + <div class="th">最高分(对齐前)</div> + {{each charCfg.posMaxMark m key}} + {{if key.length === 1}} + <div>{{ mark( m / 6 )}}</div> + {{/if}} + {{/each}} + </div> + <div class="tr"> + <div class="th">总分对齐比例</div> + {{each charCfg.posMaxMark m key}} + {{if key.length === 1}} + <div>{{( 66 / (46.6/6/100 * m) * 100).toFixed(1)}}%</div> + {{/if}} + {{/each}} + </div> + <div class="tr"> + <div class="th">最优主词缀权重</div> + <div>-</div> + <div>-</div> + <div>{{charCfg.posMaxMark.m3}}</div> + <div>{{charCfg.posMaxMark.m4}}</div> + <div>{{charCfg.posMaxMark.m5}}</div> + </div> + </div> + <ul class="cont-msg"> + <li><strong>总分对齐比例: </strong>根据<strong>{{data.name}}</strong>不同圣遗物位置可选词条及评分,计算理论最高原始词条总分。为使不同角色不同位置最终总分对齐,规定圣遗物满分为66分。理论总分对齐比例 + = 66 / 理论最高原始分 * 100% + </li> + <li><strong>最优主词缀比例: </strong>对主词条词缀非最优的圣遗物进行评分惩罚。若装备的圣遗物主词条不是当前位置的最高权重主词条或元素杯属性不符,则依据权重差值比例进行分数扣减,最多扣减50%。主词缀为充能时不进行扣减 + </li> + <li><strong>最终得分:</strong>圣遗物最终得分 = 原始总分 * 总分对齐比例 * 最优主词缀比例</li> + <li><strong>得分级别:</strong>ACE²(>56分) / ACE(>49分) / SSS(>42分) / SS(>35分) / S(>28分) / A / B / C / D + </li> + </ul> +</div> + + +<div class="cont"> + <div class="cont-title">圣遗物评分补充说明</div> + <ul class="cont-msg"> + <li>圣遗物评分的目标是对角色圣遗物词条进行一个快速的评估,一般来说评分更高的圣遗物可能会更匹配角色</li> + <li>但实际情况下圣遗物各词条的提升并非线性,且需考虑各的词条平衡,故评分仅供参考,请勿过分追求高评分</li> + <li>如需更精准的词条评估请使用 <strong>#{{data.name}}伤害</strong>命令进行伤害及词条侧重分析</li> + <li>当前评分为<strong>喵喵版评分规则</strong>,根据角色实际需求侧重,对不同角色会使用不同的评分逻辑。</li> + <li>喵喵逻辑与通用的评分不同,请勿横向比较分值。当前评分逻辑仍在完善中,如有问题请反馈给喵喵</li> + <li>目前为角色通用逻辑,后期会补充同角色不同流派(例如血牛钟离、暴力芭芭拉)的判定及评分逻辑,以使评分更加精准</li> + </ul> +</div> +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/artis-mark.less b/Yunzai/plugins/miao-plugin/resources/character/artis-mark.less new file mode 100644 index 0000000000000000000000000000000000000000..94472d35571c476823bf7913b538bbfc287641d7 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/artis-mark.less @@ -0,0 +1,124 @@ +body, .container { + width: 650px; +} + +.container > .cont { + margin-left: 15px; +} + +.basic { + .detail { + .cont { + margin: 10px 0; + } + } + + &:after { + display: none; + } +} + +.arti-stat { + width: 100%; + margin-right: 0; +} + +.mark-table { + text-align: center; + font-size: 14px; + line-height: 27px; + + .thead > div { + height: 35px; + line-height: 35px; + vertical-align: middle; + width: 16%; + + &.th { + width: 20%; + } + + .text { + line-height: 23px; + display: block; + } + + .desc { + font-size: 12px; + display: block; + line-height: 18px; + } + } + + .th { + min-width: initial; + padding-right: 0; + text-align: center; + } + + .td { + font-weight: normal; + } +} + +.cont-msg { + li { + font-size: 12px; + } +} + +.arti-icon { + width: 30px; +} + +.artis { + margin-top: -280px; + width: 650px; + position: relative; + z-index: 2; + padding: 0 10px; + + .no-bg { + opacity: 0; + } + + ul.detail li span { + width: initial; + + &.mark { + text-align: right; + padding-right: 10px; + + &:after { + content: "分"; + font-size: 12px; + display: inline-block; + transform: scale(.8); + margin-right: -1px; + + } + } + } + + .mark-calc { + background: rgba(0, 0, 0, 0.35); + border-radius: 0 0 5px 5px; + + li.result { + background: rgba(0, 0, 0, 0.7); + height: 30px; + line-height: 30px; + + .mark { + font-size: 18px; + } + } + } + + .item { + height: inherit; + width: 200px; + } + + +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/avatar-list.css b/Yunzai/plugins/miao-plugin/resources/character/avatar-list.css new file mode 100644 index 0000000000000000000000000000000000000000..db82237c36a3b5aaad13e7d0aad980f04da61ff7 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/avatar-list.css @@ -0,0 +1,227 @@ +.container { + width: 740px; + background-size: cover; +} +.head-box { + margin-top: 0; +} +.user-banner { + height: 90px; + background-size: auto 100%; + background-position: right center; + background-repeat: no-repeat; + background-color: #f0ece4; + border-radius: 50px; + padding: 1px; + margin: 5px 0; + display: flex; + white-space: nowrap; + position: relative; +} +.user-banner .face { + width: 70px; + height: 70px; + margin: 10px; + border-radius: 50%; + box-shadow: 0 0 1px #000, 0 0 5px rgba(0, 0, 0, 0.5); + border: 3px solid #fff; + overflow: hidden; + background: url('../common/item/bg5.png'); + background-size: cover; +} +.user-banner .face span { + display: block; + width: 64px; + height: 64px; + background-size: auto 100%; + background-repeat: no-repeat; +} +.user-banner .user-info { + padding: 15px 5px; + color: #414e64; + text-shadow: 0 0 2px #f0ece4, 0 0 5px #f0ece4; +} +.user-banner .user-info .name { + height: 34px; + line-height: 34px; +} +.user-banner .user-info .name strong { + font-size: 24px; +} +.user-banner .user-info .name span { + padding-left: 5px; +} +.user-banner .user-info .uid { + height: 22px; + line-height: 22px; + font-size: 16px; +} +.user-banner .stat { + position: absolute; + right: 0; + top: 0; + display: flex; + margin: 16px; + border-radius: 29px; + height: 58px; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.4); + overflow: hidden; +} +.user-banner .stat-li { + padding: 7px; + width: 70px; + height: 58px; + text-align: center; + position: relative; + text-shadow: 0 0 1px #fff; +} +.user-banner .stat-li:nth-child(odd) { + background: rgba(255, 255, 255, 0.65); +} +.user-banner .stat-li:nth-child(even) { + background: rgba(220, 220, 220, 0.5); +} +.user-banner .stat-li:first-child { + width: 80px; + padding-left: 17px; +} +.user-banner .stat-li:last-child { + width: 80px; + padding-right: 17px; +} +.user-banner .stat-li strong { + font-size: 22px; + display: block; +} +.user-banner .stat-li span { + display: block; + font-size: 14px; + color: #414e64; +} +.exploration { + display: flex; + flex-wrap: wrap; + margin: 10px 0; + justify-content: center; +} +.exploration .item { + width: 93px; + height: 116.25px; + background: url('./imgs/exploration.webp') no-repeat; + background-size: auto 100%; + border-radius: 4px; + margin: 3px; + text-align: center; + color: #fff; + align-items: center; +} +.exploration .item strong { + font-size: 22px; + display: block; + height: 30px; + line-height: 30px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, 0.5); + font-weight: normal; +} +.exploration .item span { + margin-top: 58px; + font-size: 14px; + height: 20px; + line-height: 20px; + display: block; + text-shadow: 0 0 1px rgba(0, 0, 0, 0.5); +} +.chest-list { + margin: 10px 0; + overflow: hidden; + background: rgba(0, 0, 0, 0.6); + padding: 0 15px; + display: flex; + justify-content: center; +} +.chest-list .chest { + width: 20%; + display: flex; + padding: 15px 0; +} +.chest-list .chest:nth-child(even) { + background: rgba(50, 50, 50, 0.5); +} +.chest-list .chest .value { + font-size: 24px; + line-height: 40px; + height: 40px; + padding-right: 8px; + text-align: right; + width: 70px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, 0.5); +} +.chest-list .chest .detail { + width: 60px; + height: 40px; + font-size: 14px; +} +.chest-list .chest .info { + display: flex; + height: 20px; + line-height: 20px; +} +.chest-list .chest .icon { + display: inline-block; + width: 18px; + height: 18px; + margin: 1px; + background: url('./imgs/chest.webp') no-repeat; + background-size: auto 100%; + vertical-align: center; +} +.chest-list .chest .max { + padding-left: 3px; + color: #aaa; +} +.chest-list .chest .title { + height: 20px; + display: flex; + color: #d3bc8e; +} +.cont-title { + padding: 8px 15px; +} +.avatar-cont-main { + overflow: hidden; +} +.avatar-cont { + background: rgba(0, 0, 0, 0.5); + padding: 0; + margin: 10px 0; +} +.avatar-list { + display: flex; + flex-wrap: wrap; + padding: 8px; + border-radius: 10px; +} +.avatar-list .avatar-card { + margin: 5px; +} +.cont-notice { + text-align: right; +} +.cont-notice strong { + color: #d3bc8e; +} +.cont-notice span { + padding: 0 3px; + color: #aaa; +} +.ck-notice { + text-align: center; + color: rgba(255, 255, 255, 0.9); + font-size: 13px; +} +.ck-notice strong { + color: #d3bc8e; + padding: 0 2px; + font-weight: normal; +} +/*# sourceMappingURL=avatar-list.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/avatar-list.html b/Yunzai/plugins/miao-plugin/resources/character/avatar-list.html new file mode 100644 index 0000000000000000000000000000000000000000..a98b2e95862dc77f53ce950e4071171546db1626 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/avatar-list.html @@ -0,0 +1,99 @@ +{{extend elemLayout}} + +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/avatar-list.css"/> +<link rel="stylesheet" type="text/css" href="{{_res_path}}/common/tpl.css?v=1.0"/> +{{/block}} + + +{{block 'main'}} +<div class="user-banner" style="background-image:url({{_res_path}}{{face?.banner}})"> + <div class="face"> + <span style="background-image:url({{_res_path}}{{face?.qFace||face?.face}})"></span> + </div> + <div class="user-info"> + <div class="name"> + <strong>{{face.name}}</strong> + {{if face.level && face.level > 1}} Lv.{{face.level}}{{/if}} + </div> + <div class="uid"> + {{if uid}}<span> #{{uid}}</span>{{/if}} + {{ if info.activeDay}}{{info.activeDay}} {{/if}} + </div> + </div> + {{if info && info.stats}} + <div class="stat"> + {{each info?.statMap title key}} + {{if info.stats[key] }} + <div class="stat-li"> + <strong>{{info.stats[key]}}</strong> + <span>{{title}}</span> + </div> + {{/if}} + {{/each}} + </div> + {{/if}} +</div> + +{{if !isSelfCookie}} +<div class="ck-notice">未绑定CK或CK失效,信息可能不完全。发送<strong>#体力帮助</strong>查看CK绑定方法,发送<strong>#更新面板</strong>更新游戏内角色展柜信息</div> +{{/if}} + + +{{if info && info.exploration && info.exploration['蒙德']}} +{{set citys = ['蒙德','龙脊雪山','璃月','层岩巨渊','稻妻','渊下宫','须弥'] }} +<div class="exploration"> + {{each citys city idx}} + <div class="item city-{{idx+1}}" style="background-position:{{idx}}0% 0"> + <span>{{city}}</span> + <strong>{{ (info.exploration[city]||0)/10 || '0'}}%</strong> + </div> + {{/each}} +</div> +{{/if}} + + +{{if info?.stats?.commonChest}} +{{set ds = info?.stats}} +<div class="cont chest-list"> + {{each info?.chestMap cfg idx}} + <div class="chest"> + <div class="value">{{ds[cfg.key]}}</div> + <div class="detail"> + <div class="info"> + <div class="icon" style="background-position:{{idx*2}}0% 0"></div> + <div class="max">{{cfg.max>ds[cfg.key]?cfg.max:ds[cfg.key]}}</div> + </div> + <div class="title">{{cfg.title}}</div> + </div> + </div> + {{/each}} +</div> +{{/if}} + + +<div class="cont avatar-cont"> + <div class="cont-title">角色列表</div> + <div class="avatar-list"> + {{each avatars avatar idx}} + <% include(_tpl_path+'/avatar-card.html', [avatar,{_res_path, cardType:'mini'}]) %> + {{/each}} + </div> + <div class="cont-footer cont-notice"> + {{set ut = updateTime }} + {{if ut.profile || ut.mys}} + <strong>数据更新时间</strong> + {{if ut.profile}} + <span>#更新面板:{{ut.profile}}</span> + {{/if}} + {{if ut.mys}} + <span>米游社:{{ut.mys}}</span> + {{/if}} + {{else}} + 未绑定CK或CK失效,信息可能不完全。发送<strong>#体力帮助</strong>查看CK绑定方法,发送<strong>#更新面板</strong>更新游戏内角色展柜信息 + {{/if}} + </div> +</div> + + +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/avatar-list.less b/Yunzai/plugins/miao-plugin/resources/character/avatar-list.less new file mode 100644 index 0000000000000000000000000000000000000000..3f605a745b25061b3ff0caa0a2c6d2d60bcd5960 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/avatar-list.less @@ -0,0 +1,276 @@ + +.container { + width: 740px; + background-size: cover; +} + +.head-box { + margin-top: 0; +} + + +.user-banner { + height: 90px; + background-size: auto 100%; + background-position: right center; + background-repeat: no-repeat; + background-color: #f0ece4; + border-radius: 50px; + padding: 1px; + margin: 5px 0; + display: flex; + white-space: nowrap; + position: relative; + + .face { + width: 70px; + height: 70px; + margin: 10px; + border-radius: 50%; + box-shadow: 0 0 1px #000, 0 0 5px rgba(0, 0, 0, .5); + border: 3px solid #fff; + overflow: hidden; + background: url('../common/item/bg5.png'); + background-size: cover; + + span { + display: block; + width: 64px; + height: 64px; + background-size: auto 100%; + background-repeat: no-repeat; + } + } + + .user-info { + padding: 15px 5px; + color: #414e64; + text-shadow: 0 0 2px #f0ece4, 0 0 5px #f0ece4; + + .name { + height: 34px; + line-height: 34px; + + strong { + font-size: 24px; + } + + span { + padding-left: 5px; + } + } + + .uid { + height: 22px; + line-height: 22px; + font-size: 16px; + } + } + + .stat { + position: absolute; + right: 0; + top: 0; + display: flex; + margin: 16px; + border-radius: 29px; + height: 58px; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, .4); + overflow: hidden; + } + + .stat-li { + @width: 70px; + @padding: 10px; + + padding: 7px; + width: @width; + height: 58px; + text-align: center; + position: relative; + text-shadow: 0 0 1px #fff; + + + &:nth-child(odd) { + background: rgba(255, 255, 255, .65); + } + + &:nth-child(even) { + background: rgba(220, 220, 220, .5); + } + + &:first-child { + width: @width+@padding; + padding-left: 7px+@padding; + } + + &:last-child { + width: @width+@padding; + padding-right: 7px+@padding; + } + + + strong { + font-size: 22px; + display: block; + } + + span { + display: block; + font-size: 14px; + color: #414e64; + } + } +} + + +.exploration { + display: flex; + flex-wrap: wrap; + margin: 10px 0; + justify-content: center; + + .item { + width: 93px; + height: 93*1.25px; + background: url('./imgs/exploration.webp') no-repeat; + background-size: auto 100%; + border-radius: 4px; + margin: 3px; + text-align: center; + color: #fff; + align-items: center; + + strong { + font-size: 22px; + display: block; + height: 30px; + line-height: 30px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, .5); + font-weight: normal; + } + + span { + margin-top: 58px; + font-size: 14px; + height: 20px; + line-height: 20px; + display: block; + text-shadow: 0 0 1px rgba(0, 0, 0, .5); + } + } +} + +.chest-list { + margin: 10px 0; + overflow: hidden; + background: rgba(0, 0, 0, .6); + padding: 0 15px; + display: flex; + justify-content: center; + + .chest { + width: 20%; + display: flex; + padding: 15px 0; + + &:nth-child(even) { + background: rgba(50, 50, 50, .5); + } + + .value { + font-size: 24px; + line-height: 40px; + height: 40px; + padding-right: 8px; + text-align: right; + width: 70px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, .5); + } + + .detail { + width: 60px; + height: 40px; + font-size: 14px; + } + + .info { + display: flex; + height: 20px; + line-height: 20px; + } + + .icon { + display: inline-block; + width: 18px; + height: 18px; + margin: 1px; + background: url('./imgs/chest.webp') no-repeat; + background-size: auto 100%; + vertical-align: center; + } + + .max { + padding-left: 3px; + color: #aaa; + } + + .title { + height: 20px; + display: flex; + color: #d3bc8e; + } + + + } +} + +.cont-title { + padding: 8px 15px; +} + +.avatar-cont-main { + overflow: hidden; +} + +.avatar-cont { + background: rgba(0, 0, 0, .5); + padding: 0; + margin: 10px 0; +} + +.avatar-list { + display: flex; + flex-wrap: wrap; + padding: 8px; + border-radius: 10px; + + .avatar-card { + margin: 5px; + } +} + +.cont-notice { + text-align: right; + + strong { + color: #d3bc8e; + } + + span { + padding: 0 3px; + color: #aaa; + } +} + +.ck-notice { + text-align: center; + color: rgba(255, 255, 255, .9); + font-size: 13px; + + strong { + color: #d3bc8e; + padding: 0 2px; + font-weight: normal; + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/character-card.css b/Yunzai/plugins/miao-plugin/resources/character/character-card.css new file mode 100644 index 0000000000000000000000000000000000000000..7fb3c9e291d75b6aa453e9216dae0a0b0f499608 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/character-card.css @@ -0,0 +1,411 @@ +.font-YS { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.font-NZBZ { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} +body { + font-size: 16px; + color: #fff; + transform: scale(1.25); + transform-origin: 0 0; +} +.container { + position: relative; + background-color: #1234; + width: 100%; + padding: 0; +} +.container img.bg { + width: 100%; + margin-bottom: -1px; + display: block; +} +.info { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: rgba(0, 0, 0, 0.5); +} +.char-title { + padding: 5px 10px; + background-repeat: no-repeat; + position: absolute; + left: 0; + top: 0; + text-shadow: 0 0 3px #000, 3px 3px 5px #000; +} +.char-title .char-name { + padding-left: 10px; + display: inline-block; + white-space: nowrap; + position: relative; +} +.char-title .char-name > * { + vertical-align: bottom; +} +.char-title .char-name strong { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; + font-size: 60px; + letter-spacing: 5px; + font-weight: normal; +} +.char-title .char-name .cons { + font-size: 20px; + padding: 3px 8px; + border-radius: 8px; + margin: 10px 0; + text-shadow: 0 0 1px #000; +} +.char-title .char-name:after { + content: ""; + display: block; + position: absolute; + background-image: linear-gradient(to right, rgba(255, 255, 255, 0.5) 20%, rgba(255, 255, 255, 0.5) 80%, rgba(255, 255, 255, 0) 100%); + right: -50px; + min-width: 360px; + height: 1px; + left: -50px; + opacity: 1; + transition: width 0.3s 0.1s, opacity 0.3s 0.1s; + box-shadow: 0 0 2px 0 #000; + bottom: 1px; +} +.char-title .char-lv { + font-size: 20px; + height: 25px; + line-height: 25px; + letter-spacing: 0; + padding-left: 10px; +} +.crown { + width: 30px; + height: 30px; + margin-left: 15px; + display: inline-block; + background-size: contain; + vertical-align: bottom; + background-image: url("./imgs/crown.png"); +} +.crown.crown_0 { + background-image: none; +} +.crown.crown_2 { + width: 60px; +} +.crown.crown_3 { + width: 90px; +} +.detail { + font-size: 26px; + margin: 10px 5px 2px 5px; +} +/******** left mode **********/ +.no-info { + position: absolute; + padding: 5px 10px; + bottom: 30px; + right: 10px; + font-size: 16px; + background: rgba(0, 0, 0, 0.5); + text-shadow: 1px 1px 1px #000; + border-radius: 5px; +} +.notice-cont { + color: #ccc; + font-size: 14px; + text-align: center; +} +.bottom_mode .no-info { + bottom: 25px; +} +.char-talents { + display: flex; +} +.char-detail { + display: flex; + margin: 0; + border-radius: 0; + padding: 4px; +} +.char-detail > .cont { + position: relative; + width: 200px; + height: 90px; + margin: 4px; +} +.weapon-cont { + width: 180px; + text-shadow: 1px 1px 1px #000; +} +.weapon-cont .img { + width: 80px; + height: 80px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; +} +.weapon-cont .star { + height: 20px; + width: 100px; + background: url("../common/item/star-ltr.png") no-repeat; + background-size: 100px 100px; + transform: scale(0.8); + transform-origin: -5px center; + display: inline-block; + margin: 1px 0 -2px; +} +.weapon-cont .star.star-2 { + background-position: 0 -20px; +} +.weapon-cont .star.star-3 { + background-position: 0 -40px; +} +.weapon-cont .star.star-4 { + background-position: 0 -60px; +} +.weapon-cont .star.star-5 { + background-position: 0 -80px; +} +.weapon-cont .weapon-info { + padding: 0; + position: absolute; + top: 10px; + left: 80px; +} +.weapon-cont .weapon-info strong { + font-size: 18px; + display: block; +} +.talent-cont { + display: flex; + padding: 0 5px; +} +.talent-cont .talent-item, +.talent-cont .talent-icon { + width: 100px; + height: 80px; +} +.talent-cont .talent-item { + position: relative; +} +.talent-cont .talent-icon { + width: 60px; + height: 60px; + display: table; + position: relative; + margin: 7px -5px 13x; + border-radius: 50%; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; + z-index: 90; +} +.talent-cont .talent-icon img, +.talent-cont .talent-icon .talent-icon-img { + width: 46%; + height: 46%; + position: absolute; + top: 50%; + left: 50%; + margin: -22% 0 0 -23%; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} +.talent-cont .talent-icon span { + background: #fff; + width: 34px; + height: 25px; + line-height: 25px; + font-size: 16px; + text-align: center; + border-radius: 5px; + position: absolute; + bottom: -25px; + left: 50%; + margin-left: -15px; + color: #000; + box-shadow: 0 0 5px 0 #000; +} +.talent-cont .talent-icon.talent-plus span { + background: #2e353e; + color: #ffdfa0; + font-weight: bold; + box-shadow: 0 0 1px 0 #d3bc8e, 1px 1px 2px 0 rgba(0, 0, 0, 0.5); +} +.talent-cont .talent-icon.talent-crown:after { + content: ""; + display: block; + width: 20px; + height: 20px; + background: url("../character/imgs/crown.png") no-repeat; + background-size: contain; + position: absolute; + left: 50%; + top: -5px; + margin-left: -10px; +} +.artis-cont { + text-shadow: 1px 1px 1px #000; +} +.artis-cont .artis-sets { + height: 28px; + line-height: 28px; + text-align: center; + background: rgba(0, 0, 0, 0.3); + font-size: 14px; +} +.artis-cont .artis-list { + display: flex; + flex-wrap: wrap; + height: 65px; +} +.artis-cont .artis-list .item { + height: 65px; + padding-top: 3px; + width: 20%; + box-shadow: 0 0 1px 0 rgba(255, 255, 255, 0.5); +} +.artis-cont .artis-list .item .item-icon { + width: 90%; + height: 35px; + margin: 4px 5%; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} +.artis-cont .artis-list .item .lv { + display: block; + font-size: 14px; + text-align: center; +} +.artis-cont .artis-list .item .lv:before { + content: "Lv."; + font-size: 12px; + display: inline-block; + transform: scale(0.8); + transform-origin: right 10px; + margin-left: -2px; +} +.artis-cont .artis-list .item:nth-child(odd) { + background: rgba(0, 0, 0, 0.2); +} +.artis-cont .artis-list .item:nth-child(even) { + background: rgba(134, 118, 85, 0.15); +} +.artis-cont .artis-list .item.no-item { + background: url('../common/item/artifact-icon.webp') center no-repeat; + background-size: 60% auto; +} +.copyright { + font-size: 12px; + position: absolute; + bottom: 0; + margin: 0; + right: 0; + height: 25px; + left: 0; + line-height: 25px; + padding: 0 10px; + background: rgba(0, 0, 0, 0.5); + text-align: right; + z-index: 4; +} +.copyright.data-source { + border-top: 1px solid rgba(255, 255, 255, 0.3); + left: 0; + text-align: left; + background: none; + z-index: 5; +} +.bottom-mode .char-title { + padding-top: 20px; +} +.bottom-mode .char-lv { + padding-top: 5px; +} +.bottom-mode .char-detail { + position: absolute; + bottom: 25px; + left: 0; + right: 0; + padding: 4px 0; + box-shadow: none; +} +.bottom-mode .char-detail > .cont { + background: none; + box-shadow: none; + backdrop-filter: none; + margin: 5px 0 0; +} +.bottom-mode .char-detail > .cont.left-line:after, +.bottom-mode .char-detail > .cont.right-line:after { + content: ""; + display: block; + width: 1px; + height: 50px; + background: rgba(255, 255, 255, 0.5); + position: absolute; + top: 20px; + right: 5px; +} +.bottom-mode .char-detail > .cont.right-line:after { + display: none; + right: initial; + left: 0; +} +.bottom-mode .char-detail .notice-cont { + padding-top: 40px; +} +.bottom-mode .char-detail .artis-cont { + margin-right: 10px; +} +.bottom-mode .char-detail .artis-cont .item { + box-shadow: none; +} +.bottom-mode .char-detail .talent-cont .talent-item { + padding-top: 5px; +} +.left-mode { + width: auto; +} +.left-mode .container { + width: auto; +} +.left-mode .copyright.data-source { + border-top: 1px solid rgba(255, 255, 255, 0.3); +} +.left-mode .char-detail { + position: absolute; + bottom: 25px; + left: 0; + padding: 4px 0; + background: none; + box-shadow: none; + backdrop-filter: none; + display: block; +} +.left-mode .char-detail > .cont { + margin-top: 8px; + background-size: 100% 150%; +} +.left-mode .char-detail .notice-cont { + height: 30px; + line-height: 30px; + background-size: 100% 200%; +} +.left-mode .char-detail .talent-cont .talent-item { + padding-top: 8px; +} +.left-mode .char-detail .talent-cont .talent-item span { + bottom: -20px; +} +/*# sourceMappingURL=character-card.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/character-card.html b/Yunzai/plugins/miao-plugin/resources/character/character-card.html new file mode 100644 index 0000000000000000000000000000000000000000..df8eac680b3df101a7fd9d99b29863099ea89507 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/character-card.html @@ -0,0 +1,96 @@ +{{extend defaultLayout}} + +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/common/common.css"/> +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/character-card.css"/> +{{@widthStyle}} +{{/block}} + +{{block 'main'}} +<div> + <div class="char-title"> + <div class="char-name"> + <strong>{{data.sName||data.name}}</strong> + {{if data.fetter}} <span class="fetter fetter{{data.fetter}}"></span> {{/if}} + {{if typeof(data.cons)!=='undefined'}} <span class="cons cons-{{data.cons}}">{{data.cons}}命</span> {{/if}} + </div> + <div class="char-lv"> + <span>Uid:{{uid}}</span> + {{if data.level}}<span>Lv.{{data.level}}</span>{{/if}} + </div> + </div> + {{if data.level}} + {{set w = data.weapon }} + + <div class="char-detail cont"> + + <div class="cont weapon-cont left-line"> + <div class="img" style="background-image:url({{_res_path}}{{w.img}})"></div> + <div class="weapon-info"> + <strong>{{w.name.length > 4 ? (w.abbr||w.name) : w.name}}</strong> + <div class="star star-{{w.star}}"></div> + <div>Lv.{{w.leve || w.level}} <span + class="affix affix-{{w.affix}}">精{{w.affix}}</span></div> + </div> + </div> + + {{set talent = data.talent }} + {{set keys = ['a','e','q'] }} + {{ if talent && talent.a && talent.a.level}} + <div class="cont talent-cont elem-{{data.elem}}"> + {{each keys key}} + <div class="talent-item"> + <div class="talent-icon + {{talent[key].level > talent[key].original ? `talent-plus`:``}} + {{talent[key].original >= 10 ? `talent-crown`:``}}"> + <div class="talent-icon-img" + style="background-image:url({{_res_path}}{{data.imgs[key]}})"></div> + <span>{{talent[key].level}}</span> + </div> + + </div> + {{/each}} + </div> + {{else}} + <div class="cont notice-cont"> + 请绑定CK以获取天赋信息 + </div> + {{/if}} + + <div class="cont artis-cont right-line"> + {{set idxs = [1,2,3,4,5] }} + <div class="artis-list"> + {{each idxs idx}} + {{if data.artis && data.artis[idx]}} + {{set arti = data.artis[idx]}} + <div class="item"> + <div class="item-icon" style="background-image:url({{_res_path}}{{arti.img}})"></div> + <span class="lv">{{arti.level}}</span> + </div> + {{else}} + <div class="item no-item"></div> + {{/if}} + + {{/each}} + </div> + <div class="artis-sets">{{data.artisSet?.sName||'圣遗物'}}</div> + </div> + </div> + + <div class="copyright data-source"> + 数据源:{{ {miao:'喵喵API', 'enka':'Enka.Network', 'mgg':'MiniGG-API', mys:'米游社', 'hutao':'Hutao-Enka', 'homo':'Mihomo' + }[data.source]||data.source }} {{data.updateTime}} + </div> + {{else}} + {{if custom}} + <div class="no-info">自定义角色暂无角色信息</div> + {{else if !isRelease}} + <div class="no-info">角色尚未实装,暂无信息</div> + {{else}} + <div class="no-info">未能获取到角色信息,请将角色放置在米游社角色展柜中</div> + {{/if}} + {{/if}} + <div><img src="{{_res_path}}{{bg.img}}" title="{{name}}" class="bg"></div> +</div> + +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/character-card.less b/Yunzai/plugins/miao-plugin/resources/character/character-card.less new file mode 100644 index 0000000000000000000000000000000000000000..a6160c9b37b9180d3210a5f6df37424c07aef232 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/character-card.less @@ -0,0 +1,493 @@ +@import "../common/base.less"; + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} + + +body { + font-size: 16px; + color: #fff; + transform: scale(1.25); + transform-origin: 0 0; +} + +.container { + position: relative; + background-color: #1234; + width: 100%; + padding: 0; +} + +.container img.bg { + width: 100%; + margin-bottom: -1px; + display: block; +} + +.info { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: rgba(0, 0, 0, 0.5) +} + +.char-title { + padding: 5px 10px; + background-repeat: no-repeat; + position: absolute; + left: 0; + top: 0; + text-shadow: 0 0 3px #000, 3px 3px 5px #000; + + + .char-name { + padding-left: 10px; + display: inline-block; + white-space: nowrap; + position: relative; + + & > * { + vertical-align: bottom; + } + + strong { + .font-NZBZ; + font-size: 60px; + letter-spacing: 5px; + font-weight: normal; + } + + .cons { + font-size: 20px; + padding: 3px 8px; + border-radius: 8px; + margin: 10px 0; + text-shadow: 0 0 1px #000; + } + + + &:after { + content: ""; + display: block; + position: absolute; + background-image: linear-gradient(to right, rgba(255, 255, 255, 0.5) 20%, rgba(255, 255, 255, 0.5) 80%, rgba(255, 255, 255, 0) 100%); + right: -50px; + min-width: 360px; + height: 1px; + left: -50px; + opacity: 1; + transition: width 0.3s 0.1s, opacity 0.3s 0.1s; + box-shadow: 0 0 2px 0 #000; + bottom: 1px; + } + } + + .char-lv { + font-size: 20px; + height: 25px; + line-height: 25px; + letter-spacing: 0; + padding-left: 10px; + } +} + +.crown { + width: 30px; + height: 30px; + margin-left: 15px; + display: inline-block; + background-size: contain; + vertical-align: bottom; + background-image: url("./imgs/crown.png"); + + &.crown_0 { + background-image: none; + } + + &.crown_2 { + width: 60px; + } + + &.crown_3 { + width: 90px; + } +} + +.detail { + font-size: 26px; + margin: 10px 5px 2px 5px; +} + + +/******** left mode **********/ +.no-info { + position: absolute; + padding: 5px 10px; + bottom: 30px; + right: 10px; + font-size: 16px; + background: rgba(0, 0, 0, 0.5); + text-shadow: 1px 1px 1px #000; + border-radius: 5px; +} + +.notice-cont { + color: #ccc; + font-size: 14px; + text-align: center; +} + +.bottom_mode .no-info { + bottom: 25px; +} + +.char-talents { + display: flex; +} + +.char-detail { + display: flex; + margin: 0; + border-radius: 0; + padding: 4px; + + & > .cont { + position: relative; + width: 200px; + height: 90px; + margin: 4px; + } +} + +.weapon-cont { + width: 180px; + text-shadow: 1px 1px 1px #000; + + .img { + width: 80px; + height: 80px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + } + + .star { + height: 20px; + width: 100px; + background: url("../common/item/star-ltr.png") no-repeat; + background-size: 100px 100px; + transform: scale(0.8); + transform-origin: -5px center; + display: inline-block; + margin: 1px 0 -2px; + + + &.star-2 { + background-position: 0 -20px; + } + + &.star-3 { + background-position: 0 -40px; + } + + &.star-4 { + background-position: 0 -60px; + } + + &.star-5 { + background-position: 0 -80px; + } + } + + .weapon-info { + padding: 0; + position: absolute; + top: 10px; + left: 80px; + + strong { + font-size: 18px; + display: block; + } + } + +} + +.talent-cont { + display: flex; + padding: 0 5px; + + + .talent-item, .talent-icon { + width: 100px; + height: 80px; + } + + .talent-item { + position: relative; + } + + .talent-icon { + width: 60px; + height: 60px; + display: table; + position: relative; + margin: 7px -5px 13x; + border-radius: 50%; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; + z-index: 90; + + img, + .talent-icon-img { + width: 46%; + height: 46%; + position: absolute; + top: 50%; + left: 50%; + margin: -22% 0 0 -23%; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + } + + span { + background: #fff; + width: 34px; + height: 25px; + line-height: 25px; + font-size: 16px; + text-align: center; + border-radius: 5px; + position: absolute; + bottom: -25px; + left: 50%; + margin-left: -15px; + color: #000; + box-shadow: 0 0 5px 0 #000; + } + + &.talent-plus span { + background: #2e353e; + color: #ffdfa0; + font-weight: bold; + box-shadow: 0 0 1px 0 #d3bc8e, 1px 1px 2px 0 rgba(0, 0, 0, 0.5); + } + + &.talent-crown:after { + content: ""; + display: block; + width: 20px; + height: 20px; + background: url("../character/imgs/crown.png") no-repeat; + background-size: contain; + position: absolute; + left: 50%; + top: -5px; + margin-left: -10px; + } + } +} + +.artis-cont { + text-shadow: 1px 1px 1px #000; + + .artis-sets { + height: 28px; + line-height: 28px; + text-align: center; + background: rgba(0, 0, 0, .3); + font-size: 14px; + } + + .artis-list { + display: flex; + flex-wrap: wrap; + height: 65px; + + .item { + height: 65px; + padding-top: 3px; + width: 20%; + box-shadow: 0 0 1px 0 rgba(255, 255, 255, .5); + + .item-icon { + width: 90%; + height: 35px; + margin: 4px 5%; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + } + + .lv { + display: block; + font-size: 14px; + text-align: center; + + &:before { + content: "Lv."; + font-size: 12px; + display: inline-block; + transform: scale(.8); + transform-origin: right 10px; + margin-left: -2px; + } + } + + &:nth-child(odd) { + background: rgba(0, 0, 0, .2); + } + + &:nth-child(even) { + background: rgba(134, 118, 85, 0.15); + } + + &.no-item { + background: url('../common/item/artifact-icon.webp') center no-repeat; + background-size: 60% auto; + } + } + } +} + +.copyright { + font-size: 12px; + position: absolute; + bottom: 0; + margin: 0; + right: 0; + height: 25px; + left: 0; + line-height: 25px; + padding: 0 10px; + background: rgba(0, 0, 0, 0.5); + text-align: right; + z-index: 4; + + &.data-source { + border-top: 1px solid rgba(255, 255, 255, .3); + left: 0; + text-align: left; + background: none; + z-index: 5; + } +} + +.bottom-mode { + + .char-title { + padding-top: 20px; + } + + .char-lv { + padding-top: 5px; + } + + .char-detail { + position: absolute; + bottom: 25px; + left: 0; + right: 0; + padding: 4px 0; + box-shadow: none; + + & > .cont { + background: none; + box-shadow: none; + backdrop-filter: none; + margin: 5px 0 0; + + &.left-line, + &.right-line { + &:after { + content: ""; + display: block; + width: 1px; + height: 50px; + background: rgba(255, 255, 255, .5); + position: absolute; + top: 20px; + right: 5px; + } + } + + &.right-line:after { + display: none; + right: initial; + left: 0; + } + } + + .notice-cont { + padding-top: 40px; + } + + .artis-cont { + margin-right: 10px; + + .item { + box-shadow: none; + } + } + + .talent-cont { + .talent-item { + padding-top: 5px; + } + } + } +} + +.left-mode { + width: auto; + + .container { + width: auto; + } + + .copyright { + + &.data-source { + border-top: 1px solid rgba(255, 255, 255, .3); + } + } + + .char-detail { + position: absolute; + bottom: 25px; + left: 0; + padding: 4px 0; + background: none; + box-shadow: none; + backdrop-filter: none; + display: block; + + & > .cont { + margin-top: 8px; + background-size: 100% 150%; + } + + .notice-cont { + height: 30px; + line-height: 30px; + background-size: 100% 200%; + } + + .talent-cont { + .talent-item { + padding-top: 8px; + + span { + bottom: -20px; + } + } + } + } +} diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/bg-01.jpg b/Yunzai/plugins/miao-plugin/resources/character/imgs/bg-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6726b9ac303f94c8615e87a5f602e4c80a08a23e Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/bg-01.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/chest.webp b/Yunzai/plugins/miao-plugin/resources/character/imgs/chest.webp new file mode 100644 index 0000000000000000000000000000000000000000..b56793ed388859403334c85f7177cb6553117c2a Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/chest.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/crown-sr.webp b/Yunzai/plugins/miao-plugin/resources/character/imgs/crown-sr.webp new file mode 100644 index 0000000000000000000000000000000000000000..8017b3976d44f4bd8b415f4613f6a07ec3fdf156 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/crown-sr.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/crown.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/crown.png new file mode 100644 index 0000000000000000000000000000000000000000..14cbafa4f5237123fc05ae9be80554f3206bc740 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/crown.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/dmg-rank-bg.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/dmg-rank-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..32491dcdcd34edf73da410b9eb5b3ab2126d8f10 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/dmg-rank-bg.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/exploration.webp b/Yunzai/plugins/miao-plugin/resources/character/imgs/exploration.webp new file mode 100644 index 0000000000000000000000000000000000000000..363ea21af510e20ce7cbb45856469573de90a017 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/exploration.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/help.jpg b/Yunzai/plugins/miao-plugin/resources/character/imgs/help.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1d9377fd648c60f4ef5e0be41f156ea8993b673f Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/help.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/icon-sr.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/icon-sr.png new file mode 100644 index 0000000000000000000000000000000000000000..e9ab31aec100161cc727cfc989bd564cb917f2b2 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/icon-sr.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/icon.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..06df16edfa1a2032e2f0c9e1aa0af9fe98ec66ff Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/icon.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/main-01.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/main-01.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e891885151ae9166125ac2a9a3a6e4846bf9a1 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/main-01.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/mark-icon.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/mark-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..330bbc288b8b295c14040ccc7591b2ca31a2ad79 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/mark-icon.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/mark-icon2.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/mark-icon2.png new file mode 100644 index 0000000000000000000000000000000000000000..84990b52654fcee8cbdf3385e1c98b39e1f2dc34 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/mark-icon2.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/mark-rank-bg.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/mark-rank-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..118e8d35494661941803d9db8b3e483b199cf16d Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/mark-rank-bg.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/star.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/star.png new file mode 100644 index 0000000000000000000000000000000000000000..99f2bd6681e23682a4200f659686b1dc8d8ed7e0 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/star.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/up-num-icon0.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/up-num-icon0.png new file mode 100644 index 0000000000000000000000000000000000000000..a7865996e157e07a84eb584ca2db9ae77038bd31 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/up-num-icon0.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/up-num-icon1.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/up-num-icon1.png new file mode 100644 index 0000000000000000000000000000000000000000..634757003eab3b1706f18946ed4f159b317eb41e Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/up-num-icon1.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/imgs/up-num-icon2.png b/Yunzai/plugins/miao-plugin/resources/character/imgs/up-num-icon2.png new file mode 100644 index 0000000000000000000000000000000000000000..9d91fcb5db2317ccb3001369cfcb8673adbfc785 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/character/imgs/up-num-icon2.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/character/profile-detail.css b/Yunzai/plugins/miao-plugin/resources/character/profile-detail.css new file mode 100644 index 0000000000000000000000000000000000000000..1f9d31d8ee6ae965c692abf8043974e2b70845f6 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/profile-detail.css @@ -0,0 +1,1085 @@ +.font-YS { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.font-NZBZ { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +body { + width: 600px; +} +.container { + width: 600px; + padding: 0; + background-size: cover; + overflow: hidden; +} +.basic { + position: relative; + margin-bottom: 10px; +} +.basic:after { + content: ""; + display: block; + position: absolute; + left: 8px; + top: 115px; + bottom: 0; + right: 8px; + box-shadow: 0 0 2px 0 #fff; + border-radius: 5px; + z-index: 1; +} +.main-pic { + width: 1400px; + height: 500px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + margin-left: -545px; + position: relative; + z-index: 2; +} +.detail { + position: absolute; + right: 20px; + top: 20px; + color: #fff; + z-index: 3; +} +.char-name { + font-size: 50px; + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; + text-shadow: 0 0 3px #000, 2px 2px 4px rgba(0, 0, 0, 0.7); + text-align: right; +} +.char-lv { + margin-bottom: 20px; + text-shadow: 0 0 3px #000, 2px 2px 4px rgba(0, 0, 0, 0.7); + text-align: right; +} +.char-lv .cons { + margin-left: 5px; + vertical-align: bottom; +} +.char-attr { + backdrop-filter: blur(2px); + background: rgba(0, 0, 0, 0.2); + border-radius: 8px; + overflow: hidden; +} +.char-attr li { + width: 300px; + font-size: 17px; + list-style: none; + height: 32px; + line-height: 32px; + text-shadow: 0 0 1px rgba(0, 0, 0, 0.5); + display: flex; + padding-left: 3px; +} +.char-attr li:nth-child(even) { + background: rgba(0, 0, 0, 0.4); +} +.char-attr li:nth-child(odd) { + background: rgba(50, 50, 50, 0.4); +} +.char-attr li .weight { + width: 36px; +} +.char-attr li .weight span { + display: block; + width: 30px; + border-radius: 5px; + font-size: 12px; + height: 18px; + line-height: 18px; + background: rgba(0, 0, 0, 0.5); + text-align: center; + margin: 7px auto 0; +} +.char-attr li .weight span.gold { + color: #ffe699; +} +.char-attr li .icon { + width: 26px; + padding: 2px 5px; +} +.char-attr li .icon i { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("./imgs/icon.png"); + background-size: auto 16px; +} +.char-attr li .title { + width: 75px; + text-shadow: 0 0 1px rgba(0, 0, 0, 0.8), 1px 1px 3px rgba(0, 0, 0, 0.5); +} +.char-attr li .value { + width: 100px; + text-align: right; + font-weight: normal; + padding-right: 10px; + text-shadow: 0 0 1px rgba(0, 0, 0, 0.8), 1px 1px 3px rgba(0, 0, 0, 0.5); +} +.char-attr li .value2 { + font-weight: normal; + width: 70px; + text-align: right; + font-size: 12px; + padding: 4px 10px 0 0; + background: rgba(0, 0, 0, 0.2); +} +.char-attr li .value2 span { + display: block; + height: 13px; + line-height: 13px; + transform-origin: right center; +} +.char-attr li .value2 .base { + color: #eee; +} +.char-attr li .value2 .plus { + color: #90e800; +} +.i-hp { + background-position: -16px 0; +} +.i-atk { + background-position: -32px 0; +} +.i-def { + background-position: -48px 0; +} +.i-mastery { + background-position: -64px 0; +} +.i-cpct { + background-position: -80px 0; +} +.i-cdmg { + background-position: -96px 0; +} +.i-stance { + background-position: -64px 0; +} +.i-recharge { + background-position: -112px 0; +} +.i-dmg { + background-position: -128px 0; +} +.i-heal { + background-position: -144px 0; +} +.i-speed { + background-position: -160px 0; +} +.i-effPct { + background-position: -176px 0; +} +.i-effDef { + background-position: -192px 0; +} +.detail.attr li:nth-child(even) { + background: rgba(0, 0, 0, 0.4); +} +.detail.attr li:nth-child(odd) { + background: rgba(50, 50, 50, 0.4); +} +.detail.attr li strong { + display: inline-block; + position: absolute; + right: 85px; + text-align: right; + font-weight: normal; +} +.detail.attr li span { + position: absolute; + right: 0; + text-align: left; + width: 75px; + display: inline-block; + color: #90e800; + font-size: 15px; +} +.talent-icon { + width: 100px; + height: 100px; + padding: 5px; + display: table; + border-radius: 50%; + position: relative; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; + z-index: 90; +} +.talent-icon img, +.talent-icon .talent-icon-img { + width: 46%; + height: 46%; + position: absolute; + top: 50%; + left: 50%; + margin: -22% 0 0 -23%; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} +.talent-icon strong { + background: #fff; + width: 34px; + height: 26px; + line-height: 26px; + font-size: 17px; + text-align: center; + border-radius: 5px; + position: absolute; + bottom: 2px; + left: 50%; + margin-left: -15px; + color: #000; + box-shadow: 0 0 5px 0 #000; +} +.talent-icon.talent-plus strong { + background: #2e353e; + color: #ffdfa0; + font-weight: bold; + box-shadow: 0 0 1px 0 #d3bc8e, 1px 1px 2px 0 rgba(0, 0, 0, 0.5); +} +.talent-icon.talent-crown:after { + content: ""; + display: block; + width: 28px; + height: 28px; + background: url("../character/imgs/crown.png") no-repeat; + background-size: contain; + position: absolute; + left: 50%; + top: 0; + margin-left: -14px; +} +.char-talents { + display: flex; + width: 300px; + margin: 0 0 10px 0; +} +.char-cons { + display: flex; + width: 250px; + position: absolute; + bottom: 5px; + left: 20px; +} +.char-cons .talent-item, +.char-talents .talent-item { + flex: 1; +} +.char-cons .talent-icon { + width: 50px; + height: 50px; + margin: 0 -5px; +} +.char-cons .talent-icon.off { + filter: grayscale(100%); + opacity: 0.4; +} +.elem_anemo .talent-icon { + background-image: url(../common/bg/talent-anemo.png); +} +.elem_anemo .container { + background-image: url(../common/bg/bg-anemo.jpg); +} +.elem_cryo .talent-icon { + background-image: url(../common/bg/talent-cryo.png); +} +.elem_cryo .container { + background-image: url(../common/bg/bg-cryo.jpg); +} +.elem_electro .talent-icon { + background-image: url(../common/bg/talent-electro.png); +} +.elem_electro .container { + background-image: url(../common/bg/bg-electro.jpg); +} +.elem_geo .talent-icon { + background-image: url(../common/bg/talent-geo.png); +} +.elem_geo .container { + background-image: url(../common/bg/bg-geo.jpg); +} +.elem_hydro .talent-icon { + background-image: url(../common/bg/talent-hydro.png); +} +.elem_hydro .container { + background-image: url(../common/bg/bg-hydro.jpg); +} +.elem_pyro .talent-icon { + background-image: url(../common/bg/talent-pyro.png); +} +.elem_pyro .container { + background-image: url(../common/bg/bg-pyro.jpg); +} +.data-info { + position: absolute; + bottom: -10px; + right: 15px; + font-size: 12px; + color: rgba(255, 255, 255, 0.85); + text-align: right; + text-shadow: 1px 1px 1px #000; + z-index: 2; + line-height: 20px; + padding-right: 5px; +} +.data-info .time { + margin-left: 5px; +} +/*** dmg ***/ +.cont { + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 100%; + margin: 5px 15px 5px 10px; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8); + overflow: hidden; + color: #fff; + font-size: 16px; +} +.dmg-cont { + display: table; + width: calc(100% - 25px); + margin-top: 10px; + margin-bottom: 10px; +} +.dmg-mode .dmg-list .cont-footer { + display: none; +} +.cont-title { + background: rgba(0, 0, 0, 0.4); + color: #d3bc8e; + padding: 10px 20px; + text-align: left; +} +.cont-title span { + font-size: 12px; + color: #aaa; + margin-left: 10px; + font-weight: normal; +} +.cont-footer { + padding: 10px 15px; + font-size: 12px; + background: rgba(0, 0, 0, 0.5); + font-weight: normal; +} +.cont-table { + display: table; + width: 100%; +} +.dmg-cont .tr { + display: table-row; +} +.dmg-cont .tr:nth-child(even) { + background: rgba(0, 0, 0, 0.4); +} +.dmg-cont .tr:nth-child(odd) { + background: rgba(50, 50, 50, 0.4); +} +.dmg-cont .tr > div { + display: table-cell; + box-shadow: 0 0 1px 0 #fff; +} +.dmg-cont .tr > div.value-full { + display: table; + width: 200%; +} +.dmg-cont .tr > div.value-none { + box-shadow: none; +} +.dmg-cont .thead { + text-align: center; +} +.dmg-cont .thead > div { + color: #d3bc8e; + background: rgba(0, 0, 0, 0.4); + line-height: 40px; + height: 40px; +} +.dmg-cont .title, +.dmg-cont .th { + color: #d3bc8e; + padding-right: 15px; + text-align: right; + background: rgba(0, 0, 0, 0.4); + min-width: 100px; +} +.profile-mode .dmg-idx { + display: none !important; +} +.profile-mode .dmg-title { + width: 33.3333%; +} +.dmg-mode .dmg-idx, +.weapon-mode .dmg-idx { + display: table-cell; + width: 5%; + min-width: initial; + padding-right: 0; + text-align: center; +} +.dmg-mode .dmg-title, +.weapon-mode .dmg-title { + width: 31%; + min-width: initial; + text-align: left; + padding-left: 10px; + padding-right: 0; +} +.dmg .value { + text-align: center; + color: #fff; + display: block; + height: 40px; + font-size: 18px; + line-height: 40px; + width: 32%; +} +.dmg-notice { + font-size: 12px; + text-align: right; + color: #f5f5f5; + margin-right: 15px; +} +/*** artis***/ +.artis { + display: flex; + width: 600px; + flex-wrap: wrap; + margin-bottom: 5px; + padding: 0 5px; +} +.artis .item { + width: 185px; + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 100%; + margin: 5px; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8); + overflow: hidden; +} +.artis .item .arti-icon { + width: 60px; + height: 60px; + position: absolute; + left: 2px; + top: 3px; +} +.artis .item .arti-icon span { + position: absolute; + right: 2px; + bottom: 0; + margin-left: 5px; + background: rgba(0, 0, 0, 0.5); + border-radius: 5px; + height: 18px; + line-height: 18px; + padding: 0 3px; + color: #fff; + font-size: 12px; + display: block; +} +.artis .item .arti-icon .img { + width: 50px; + height: 50px; + margin: 5px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} +.artis .head { + color: #fff; + padding: 12px 0 8px 68px; +} +.artis .head strong { + font-size: 15px; + display: block; + white-space: nowrap; + overflow: hidden; +} +.artis .head span { + font-size: 14px; +} +.mark-ACE, +.mark-ACE² { + color: #e85656; + font-weight: bold; +} +.mark-SSS, +.mark-SS { + color: #ffe699; + font-weight: bold; +} +.mark-S, +.mark-A { + color: #d699ff; + font-weight: bold; +} +.arti-main { + color: #fff; + padding: 6px 15px; +} +.artis ul.detail { + width: 100%; + padding: 0; + position: initial; + display: table; +} +.artis ul.detail li { + padding: 0 3px; + font-size: 14px; + position: relative; + width: 100%; + display: table-row; + line-height: 26px; + height: 26px; + white-space: nowrap; +} +.artis ul.detail li span { + position: initial; + display: table-cell; + color: #fff; +} +.artis ul.detail li span.title { + text-align: left; + padding-left: 30px; + font-size: 14px; +} +.artis ul.detail li span.title i.eff { + position: absolute; + display: block; + left: 3px; + top: 4px; + font-size: 12px; + font-style: normal; + background: rgba(0, 0, 0, 0.5); + border-radius: 5px; + height: 18px; + line-height: 18px; + width: 23px; + text-align: center; +} +.artis ul.detail li span.title i.up-num { + position: absolute; + display: block; + left: 91px; + top: 9px; + height: 8px; + width: 50px; + background-image: url('./imgs/up-num-icon1.png'); + background-position: 0 0; + background-repeat: no-repeat; + background-size: auto 500%; +} +.artis ul.detail li span.title i.up-num.up-5 { + background-position: 0 -8px; +} +.artis ul.detail li span.title i.up-num.up-4 { + background-position: 0 -16px; +} +.artis ul.detail li span.title i.up-num.up-3 { + background-position: 0 -24px; +} +.artis ul.detail li span.title i.up-num.up-2 { + background-position: 0 -32px; +} +.artis ul.detail li span.title i.up-num.up-1 { + background: none !important; +} +.artis ul.detail li span.val { + text-align: right; + padding-right: 10px; + font-size: 14px; +} +.artis ul.detail li.great span.title { + color: #ffe699; +} +.artis ul.detail li.great span.title i.up-num { + background-image: url("./imgs/up-num-icon2.png"); + background-size: auto 500%; +} +.artis ul.detail li.nouse span { + color: #888; +} +.artis ul.detail li.nouse span i.up-num { + background-image: url("./imgs/up-num-icon0.png"); + background-size: auto 500%; +} +.artis ul.detail li.arti-main { + font-size: 16px; + padding: 3px 3px; + font-weight: bold; +} +.artis .weapon .star { + height: 20px; + width: 100px; + background: url("../common/item/star.png") no-repeat; + background-size: 100px 100px; + transform: scale(0.8); + transform-origin: 100px 10px; + display: inline-block; + display: none; +} +.artis .weapon .star.star-2 { + background-position: 0 -20px; +} +.artis .weapon .star.star-3 { + background-position: 0 -40px; +} +.artis .weapon .star.star-4 { + background-position: 0 -60px; +} +.artis .weapon .star.star-5 { + background-position: 0 -80px; +} +.artis .weapon { + height: 96px; + overflow: visible; + margin-bottom: 10px; +} +.artis .weapon .img { + width: 106px; + height: 106px; + top: -10px; + right: -10px; + position: absolute; + z-index: 2; + background-position: center; + background-size: contain; + background-repeat: no-repeat; +} +.artis .weapon .head { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + padding: 15px 0 10px 15px; + z-index: 3; + border-radius: 10px; + background: linear-gradient(to right, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7), rgba(25, 25, 25, 0.5), rgba(25, 25, 25, 0), rgba(25, 25, 25, 0)); +} +.artis .weapon .head strong { + font-size: 15px; + margin-bottom: 3px; +} +.artis .weapon .head > span { + display: block; +} +.artis .weapon span.info { + font-size: 14px; + margin-bottom: 8px; +} +.artis .weapon .affix { + color: #000; + padding: 0 7px; + border-radius: 4px; + font-size: 14px; + width: 40px; + margin-right: 5px; +} +.artis .weapon .affix-1 { + box-shadow: 0 0 4px 0 #a3a3a3 inset; + background: #ebebebaa; +} +.artis .weapon .affix-2 { + box-shadow: 0 0 4px 0 #51b72fbd inset; + background: #ddffdeaa; +} +.artis .weapon .affix-3 { + box-shadow: 0 0 4px 0 #396cdecf inset; + background: #ddebffaa; +} +.artis .weapon .affix-4 { + box-shadow: 0 0 4px 0 #c539debf inset; + background: #ffddf0aa; +} +.artis .weapon .affix-5 { + box-shadow: 0 0 4px 0 #deaf39 inset; + background: #fff6dd; +} +.artis .weapon .weapon-attr { + font-size: 14px; + text-shadow: 0 0 1px #000, 1px 1px 2px rgba(0, 0, 0, 0.7); + display: flex; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 26px; + width: 100%; + background: rgba(0, 0, 0, 0.2); + line-height: 26px; + border-radius: 0 0 10px 10px; + text-align: center; + padding: 0 5px 0 10px; +} +.artis .weapon .weapon-attr div { + width: 50%; +} +.artis .weapon .weapon-attr div span { + color: #ffe699; + font-weight: bold; +} +.artis .arti-stat { + height: 84px; +} +.arti-class-title { + height: 25px; + line-height: 20px; + font-size: 12px; + color: #fff; + padding: 5px 10px 0; + text-align: center; + color: rgba(255, 255, 255, 0.9); + text-shadow: 0 0 2px #000; +} +.arti-stat-ret { + height: 55px; + padding: 0 10px 5px; + width: 100%; + display: table; +} +.arti-stat-ret > div { + display: table-cell; + text-align: center; + color: #fff; +} +.arti-stat-ret strong { + display: block; + height: 35px; + font-size: 30px; + line-height: 35px; +} +.dmg-msg { + font-size: 13px; + font-weight: normal; +} +.dmg-msg .thead > div { + text-align: left; + padding-left: 10px; +} +.dmg-msg .th { + text-align: left; + padding-left: 10px; +} +.dmg-msg .tr .td { + padding: 8px 10px; +} +.dmg-msg .info { + font-size: 12px; + text-align: left; + padding-left: 10px; + font-weight: normal; +} +.dmg-calc .thead > div { + line-height: initial; +} +.dmg-calc .cont-table div { + vertical-align: middle; + text-align: center; + white-space: nowrap; +} +.dmg-calc .title { + text-align: center; + padding-right: 0; + min-width: 70px; +} +.dmg-calc .td { + padding: 5px 0; +} +.dmg-calc strong { + font-weight: normal; + display: block; +} +.dmg-calc span { + font-size: 12px; + color: #aaa; +} +.dmg-calc .na, +.dmg-calc .eq { + background: rgba(50, 50, 50, 0.5); +} +.dmg-calc .na { + color: #888; +} +.dmg-calc .lt { + background: rgba(23, 112, 41, 0.5); +} +.dmg-calc .gt { + background: rgba(112, 23, 23, 0.5); +} +.dmg-desc { + color: #aaa; +} +.dmg-desc ul { + padding-left: 10px; +} +.dmg-desc ul li { + color: #aaa; +} +.dmg-desc strong { + color: #d3bc8e; + display: inline; + padding: 0 3px; + font-weight: normal; +} +.arti-stat span { + font-size: 13px; + line-height: 20px; + color: #bbb; +} +.game-sr .artis-weapon { + display: none; +} +.game-sr .char-lv { + margin-bottom: 25px; +} +.game-sr .char-attr .icon i { + background-image: url('./imgs/icon-sr.png'); +} +.artis .item.arti { + overflow: visible; +} +.artis .item.arti .head { + position: relative; + border-radius: 10px 10px 0 0; + text-shadow: 0 0 1px #000, 1px 1px 2px rgba(0, 0, 0, 0.7); + padding: 15px 10px 5px 15px; + background: linear-gradient(to right, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7), rgba(25, 25, 25, 0.3), rgba(25, 25, 25, 0), rgba(25, 25, 25, 0)); +} +.artis .item.arti .arti-icon { + left: auto; + right: 0; + top: -12px; + width: 90px; + height: 90px; +} +.artis .item.arti .arti-icon .img { + width: 100%; + height: 100%; + margin: 0; + -webkit-mask: linear-gradient(45deg, #0000 0, #0005 30%, #000 50%); +} +.artis .item.arti .arti-icon span { + top: 50px; + right: 8px; + background: rgba(0, 0, 0, 0.8); +} +.artis ul.detail { + backdrop-filter: blur(2px); + border-radius: 0 0 10px 10px; + overflow: hidden; +} +.artis ul.detail li.arti-main { + background: rgba(25, 25, 25, 0.5); +} +.artis ul.detail li.arti-main .title { + padding-left: 15px; +} +.sr-weapon { + margin: 0 15px 5px 10px; + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 150%; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8); + overflow: hidden; + display: table; + color: #fff; + min-height: 120px; + width: calc(100% - 25px); +} +.sr-weapon .weapon-img { + display: table-cell; + width: 185px; + height: 100%; + min-height: 120px; + background-size: 100% auto; + background-position: 0 5%; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8); +} +.sr-weapon .weapon-info { + display: table-cell; + padding: 10px 10px 5px 15px; +} +.sr-weapon .weapon-title span { + font-size: 14px; +} +.sr-weapon .weapon-title strong { + color: #d3bc8e; + font-weight: normal; +} +.sr-weapon .weapon-attr { + font-size: 12px; + height: 25px; + line-height: 25px; + display: flex; +} +.sr-weapon .weapon-attr .attr { + padding-left: 22px; + padding-right: 7px; + margin-right: 10px; + position: relative; + line-height: 22px; + height: 22px; + font-size: 12px; + color: #ffe699; + display: inline-block; + border-radius: 4px; + background: rgba(0, 0, 0, 0.5); + text-align: center; +} +.sr-weapon .weapon-attr .attr span { + font-size: 12px; + display: none; +} +.sr-weapon .weapon-attr .attr:before { + content: ""; + display: inline-block; + width: 22px; + height: 22px; + background-size: auto 100%; + background-position: top center; + vertical-align: middle; + position: absolute; + left: 0; + top: 0; +} +.sr-weapon .weapon-attr .i-hp:before { + background-image: url('../meta-sr/public/icons/attr-hp.webp'); +} +.sr-weapon .weapon-attr .i-atk:before { + background-image: url('../meta-sr/public/icons/attr-atk.webp'); +} +.sr-weapon .weapon-attr .i-def:before { + background-image: url('../meta-sr/public/icons/attr-def.webp'); +} +.sr-weapon .weapon-desc { + margin-top: 7px; + font-size: 12px; + font-weight: normal; + color: #fff; + white-space: break-spaces; + text-shadow: 0 0 1px rgba(0, 0, 0, 0.7), 1px 1px 3px rgba(0, 0, 0, 0.4); +} +.sr-weapon .weapon-desc nobr { + color: #ffe699; + display: inline-block; + border-radius: 4px; + font-size: 12px; + height: 16px; + line-height: 16px; + background: rgba(0, 0, 0, 0.5); + text-align: center; + padding: 0 3px; + margin: 0 2px; +} +.sr-talent { + margin: 0 15px 10px 10px; + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 150%; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8); + overflow: hidden; + display: flex; + color: #fff; + height: 72px; + width: calc(100% - 25px); + padding: 8px 10px; +} +.sr-talent .char-talents { + transform-origin: center left; + margin: 0; + width: 260px; +} +.sr-talent .char-talents .talent-item { + margin: 0 -3px; +} +.sr-talent .char-talents .talent-icon { + width: 60px; + height: 60px; +} +.sr-talent .char-talents .talent-icon strong { + font-size: 13px; + width: 22px; + height: 20px; + line-height: 20px; + margin-left: -11px; + border-radius: 4px; +} +.sr-talent .char-talents .talent-icon span { + position: absolute; + top: -3px; + font-size: 12px; + left: 0; + right: 0; + text-align: center; + color: #fff; + text-shadow: 0 0 3px #000, 1px 1px 1px #000; +} +.sr-talent .char-talents .talent-icon.talent-crown:after { + width: 22px; + height: 22px; + margin: 2px 0 0 5px; + background-image: url('../character/imgs/crown-sr.webp'); + display: none; +} +.sr-talent .char-trees { + width: 290px; + padding-left: 10px; + position: relative; +} +.sr-talent .char-trees .talent-icon { + margin: 0 -5px; +} +.sr-talent .char-trees .talent-icon.off { + filter: grayscale(100%); + opacity: 0.4; +} +.sr-talent .char-trees:before { + content: ""; + display: block; + width: 1px; + height: 30px; + background: rgba(255, 255, 255, 0.8); + position: absolute; + left: 0; + top: 15px; +} +.sr-talent .char-trees .talent-item { + width: 40px; +} +.sr-talent .char-trees .talent-item .talent-icon { + margin: 0; +} +.sr-talent .char-trees .tree-item { + width: 20px; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; +} +.sr-talent .char-trees .tree-item .talent-icon { + width: 30px; + height: 30px; + margin: 0 -5px; +} +.copyright.ad { + font-size: 12px; +} +/*# sourceMappingURL=profile-detail.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/profile-detail.html b/Yunzai/plugins/miao-plugin/resources/character/profile-detail.html new file mode 100644 index 0000000000000000000000000000000000000000..bf82ab8178192cd6a5c04ef3b8d10613a1d83bf4 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/profile-detail.html @@ -0,0 +1,363 @@ +{{extend elemLayout}} + +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/profile-detail.css"/> +{{/block}} + +{{set weapon = data.weapon}} + +{{set dataSource = data.dataSource}} +{{set talentMap = game === 'sr' ? {a: '普攻', e: '战技', t:'天赋', q: '爆发'} : {a: '普攻', e: '战技', q: '爆发'} }} +{{set {imgs, costumeSplash} = data }} +{{set imgs = imgs || {} }} +{{set gameHash = game === 'gs' ? '#':'*' }} + +{{block 'main'}} +<div class="game-{{game}}"> + <div class="basic"> + <div class="main-pic" + style="background-image:url({{_res_path}}{{costumeSplash||imgs?.splash}})"></div> + <div class="detail"> + <div class="char-name">{{data.name}}</div> + <div class="char-lv">UID {{uid}} - Lv.{{data.level}} + <span class="cons cons-{{data.cons}}">{{data.cons}}命</span></div> + <div> + {{if mode !== 'weapon'}} + {{if game === 'gs'}} + <div class="char-talents"> + {{each talentMap tName key}} + {{set talent = data.talent[key] || {} }} + <div class="talent-item"> + <div class="talent-icon + {{talent.level > talent.original ? `talent-plus`:``}} + {{talent.original >= 10 ? `talent-crown`:``}}"> + <div class="talent-icon-img" + style="background-image:url({{_res_path}}{{imgs[key]}})"></div> + <strong>{{talent.level}}</strong> + </div> + </div> + {{/each}} + </div> + {{/if}} + <ul class="char-attr"> + {{set attrMap = game === 'sr' ? { + hp:'生命值',atk:'攻击力',def:'防御力',speed:'速度',cpct:'暴击率',cdmg:'暴击伤害',dmg:'伤害加成',stance:'击破特攻',effPct:'效果命中',effDef:'效果抵抗', + heal:'治疗加成' + }:{ + hp:'生命值',atk:'攻击力',def:'防御力',mastery:'元素精通',cpct:'暴击率',cdmg:'暴击伤害',recharge:'元素充能',dmg:'伤害加成' + } }} + {{set cw = artisDetail?.charWeight || {} }} + {{each attrMap title key}} + <li> + + <div class="icon"><i class="i-{{key}}"></i></div> + + <div class="title">{{title}}</div> + <div class="weight"> + {{if cw[key]}} + <span class="{{cw[key]>=80?'gold':'normal'}}">{{cw[key]}}</span> + {{/if}} + </div> + <div class="value"> + {{attr[key]}} + </div> + <div class="value2"> + <span class="base">{{attr[key+'Base']}}</span> + <span class="plus">+{{attr[key+'Plus']}}</span> + </div> + + </li> + {{/each}} + </ul> + {{else}} + <div class="char-weapon"> + <div class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></div> + <div class="head"> + <strong>{{weapon.name}}</strong> + <div class="star star-{{weapon.star}}"></div> + <span><span class="affix affix-{{weapon.affix}}">精{{weapon.affix}}</span> Lv.{{weapon.leve || weapon.level}} </span> + </div> + </div> + {{/if}} + </div> + </div> + <div class="char-cons"> + {{set cons = [1,2,3,4,5,6]}} + {{each cons idx}} + <div class="cons-item"> + <div class="talent-icon {{idx * 1 > data.cons * 1 ? 'off' : '' }}"> + <div class="talent-icon-img" style="background-image:url({{_res_path}}{{imgs[`cons${idx}`]}})"></div> + </div> + </div> + {{/each}} + </div> + + <div class="data-info"> + {{if data.dataSource}} + <span>数据源:{{ {change:"面板变换"}[data.dataSource]||data.dataSource }}</span> + {{/if}} + {{if data.updateTime}} + <span class="time">{{data.updateTime}}</span> + {{/if}} + </div> + </div> + + {{if changeProfile}} + <div class="cont"> + <div class="cont-footer dmg-desc"> + <strong>该面板为非实际数据。当前替换命令:</strong> {{changeProfile}} + </div> + </div> + {{/if}} + + <!-- 【 武器+圣遗物列表】 --> + <div> + {{if game === 'sr'}} + <div class="sr-talent"> + <div class="char-talents"> + {{each talentMap tName key}} + {{set talent = data.talent[key] || {} }} + <div class="talent-item"> + <div class="talent-icon + {{talent.level > talent.original ? `talent-plus`:``}} + {{talent.original >= 10 ? `talent-crown`:``}}"> + <div class="talent-icon-img" style="background-image:url({{_res_path}}{{imgs[key]}})"></div> + <strong>{{talent.level}}</strong> + <span>{{tName}}</span> + </div> + </div> + {{/each}} + </div> + + <div class="char-talents char-trees"> + + {{each data.treeData tCfg}} + {{if tCfg?.type === 'talent' }} + <div class="talent-item"> + <div class="talent-icon {{tCfg.value ? '':'off'}}"> + <div class="talent-icon-img" style="background-image:url({{_res_path}}{{tCfg.img}})"></div> + </div> + </div> + {{else}} + <div class="tree-item"> + {{each tCfg tIdx}} + <div class="talent-icon {{tIdx.value ? '':'off'}}"> + <div class="talent-icon-img" style="background-image:url({{_res_path}}{{tIdx.img}})"></div> + </div> + {{/each}} + </div> + {{/if}} + {{/each}} + + </div> + </div> + + {{if weapon && weapon.name}} + <div class="sr-weapon"> + <div class="weapon-img" style="background-image:url({{_res_path}}{{weapon.splash}})"></div> + <div class="weapon-info"> + <div class="weapon-title"> + <strong>{{weapon.name}}</strong> + <span>Lv.{{weapon.level}}</span> + <span>叠影{{weapon.affix}}阶</span> + </div> + <div class="weapon-attr"> + {{set a = weapon.attrs}} + <div class="attr i-hp"><span>生命</span>{{a.hp}}</div> + <div class="attr i-atk"><span>攻击</span>{{a.atk}}</div> + <div class="attr i-def"><span>防御</span>{{a.def}}</div> + </div> + <div class="weapon-desc">{{@weapon.desc?.desc}}</div> + </div> + </div> + {{/if}} + {{/if}} + {{if mode === "profile"}} + {{set ad = artisDetail}} + <div class="artis"> + {{ if game === 'gs' }} + <div class="artis-weapon"> + <div class="item weapon"> + <div class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></div> + <div class="head"> + <strong>{{weapon.name}}</strong> + <span class="info"><span + class="affix affix-{{weapon.affix}}">精{{weapon.affix}}</span> Lv.{{weapon.leve || weapon.level}} </span> + <div class="weapon-attr"> + <div><span>攻击</span> +{{weapon.attrs.atkBase}}</div> + {{each weapon.attrs v k}} {{if k!== 'atkBase' }} + {{ set titleMap = {atkPct:'攻击',mastery:'精通',dmg:'伤害',hpPct:'生命',defPct:'防御', + cpct:'暴击', cdmg:'爆伤', phy:'物伤', recharge:'充能', heal:'治疗', shield:'护盾'} }} + <div><span>{{ titleMap[k] }}</span> +{{v}}</div> + {{/if}} {{/each}} + </div> + </div> + </div> + <div class="item arti-stat"> + <div class="arti-class-title">评分规则:{{ad.classTitle}}</div> + <div class="arti-stat-ret"> + <div><strong class="mark-{{ad.markClass}}">{{ad.markClass}}</strong><span>圣遗物评级</span></div> + <div><strong>{{ad.mark}}</strong><span>圣遗物总分</span></div> + </div> + </div> + </div> + {{/if}} + + {{each ad.artis ds idx}} + <div class="item arti"> + {{if ds && ds.name && ds.main && ds.main.key && ds.main.key!="undefined"}} + <div class="arti-icon"> + <div class="img" style="background-image:url({{_res_path}}{{ds.img}})"></div> + <span>+{{ds.level}}</span> + </div> + <div class="head"> + <strong>{{ds.abbr || ds.name}}</strong> + <span class="mark mark-{{ds.markClass}}"><span>{{ds.mark}}分</span> - {{ds.markClass}}</span> + </div> + <ul class="detail attr"> + <li class="arti-main"><span class="title">{{artisKeyTitle[ds.main?.key]}}</span><span class="val">+{{ds.main.value}}</span> + </li> + {{each ds.attrs attr}} + {{if attr && attr.key}} + <li class="{{ad.charWeight[attr.key]*1 > 79.9 ?`great`:(ad.charWeight[attr.key]*1>0 ? `useful`:`nouse`)}}"> + <span class="title">{{if attr.eff}}<i class="eff">{{attr.eff || ''}}</i>{{/if}}{{if attr.upNum}}<i + class="up-num up-{{attr.upNum}}"></i>{{/if}}{{artisKeyTitle[attr.key] || attr.key}}</span> + <span class="val">+{{attr.value}}</span> + </li> + {{/if}} + {{/each}} + </ul> + {{/if}} + </div> + {{/each}} + </div> + {{/if}} + </div> + + + <!-- 【 伤害表格 】 --> + {{ set {dmgRet, dmgCfg, enemyLv, enemyName, dmgMsg, dmgData} = dmgCalc }} + <div> + {{if game === 'gs'}} + {{if mode === "profile"}} + <div class="cont"> + <div class="cont-footer dmg-desc"> + 当前评分为<strong>喵喵版评分规则</strong>,分值仅供参考与娱乐。可使用<strong>{{gameHash}}{{data.abbr}}圣遗物</strong>来查看评分详情 + </div> + </div> + {{/if}} + {{else}} + <div class="cont"> + <div class="cont-footer dmg-desc"> + <strong>圣遗物评分功能尚未完全完成,分值可能不准确,请淡定...</strong> + </div> + </div> + {{/if}} + + {{if dmgData?.length > 0}} + <div class="dmg-cont dmg-list cont"> + <div class="cont-title"> + 伤害计算<span>目标为{{enemyLv}}级{{enemyName||'小宝'}}{{if game==='gs'}},如需调整等级可使用 #敌人等级{{enemyLv}} 来进行设置{{/if}}</span> + </div> + <div class="cont-table"> + <div class="tr thead"> + <div class="title dmg-idx">#</div> + <div class="title dmg-title">伤害类型</div> + <div>暴击伤害</div> + <div>期望伤害</div> + </div> + {{each dmgData dmg idx}} + <div class="dmg tr"> + <div class="title dmg-idx">{{idx+1}}</div> + <div class="title dmg-title">{{dmg.title}}</div> + {{if !dmg.dmg || dmg.dmg === "NaN"}} + <div class="value value-full">{{dmg.avg}}{{dmg.unit}}</div> + <div class="value value-none"></div> + {{else}} + <div class="value">{{dmg.dmg}}{{dmg.unit}}</div> + <div class="value">{{dmg.avg}}{{dmg.unit}}</div> + {{/if}} + </div> + {{/each}} + </div> + <div class="cont-footer dmg-desc"> + 使用命令<strong>{{gameHash}}{{data.abbr}}伤害</strong>可以查看伤害详情,使用命令<strong>#角色面板帮助</strong>可查看帮助说明 + </div> + </div> + {{/if}} + </div> + + <!-- 【 伤害变化详情 】 --> + <div> + {{if mode === "dmg"}} + {{if dmgCfg && dmgCfg.attr && dmgCfg.attr.length>0 && dmgRet}} + <div class="dmg-calc dmg-cont cont"> + <div class="cont-title"> + 词条伤害计算<span>{{gameHash}}{{data.abbr}}伤害{{dmgCfg.userIdx+1}}: 当前计算为[{{dmgCfg.title}}]</span> + </div> + <div class="cont-table"> + <div class="tr thead "> + <div class="td">词条变化</div> + {{each dmgCfg.attr attr}} + <div class="td"> + <strong>{{attr?.title}}</strong> + <span>+{{attr?.text}}</span> + </div> + {{/each}} + </div> + {{each dmgRet row rowIdx}} + <div class="tr"> + <div class="title"> + <strong>{{dmgCfg.attr[rowIdx].title}}</strong> + <span>-{{dmgCfg.attr[rowIdx].text}}</span> + </div> + {{each row cell colIdx}} + {{if cell.type === "na"}} + <div class="td na"> + <strong>-</strong> + <span>{{dmgCfg.basicRet.avg}}{{(dmgCfg.basicRet.dmg&&dmgCfg.basicRet.dmg!="NaN")?`/${dmgCfg.basicRet.dmg}`:''}}</span> + </div> + {{else}} + <div class="td {{cell.type}}"> + <strong>{{cell.val}}</strong> + + <span>{{cell.avg}}{{cell.dmg!="NaN"?`/${cell.dmg}`:''}}</span> + </div> + {{/if}} + {{/each}} + </div> + {{/each}} + </div> + <div class="cont-footer dmg-desc"> + <ul> + <li> + 大数字的含义为圣遗物副词条置换后<strong>平均伤害</strong>的变化,下方的详情数字为<strong>平均伤害</strong>/<strong>暴击伤害</strong>。 + </li> + <li>关于<strong>平均伤害</strong>:是将暴击率计算在内的伤害期望,能反映综合的输出能力,不等于实际伤害数字。</li> + <li>可用于评估当前面板下圣遗物副词条的侧重方向。实际游戏情况更加复杂,结果供参考~</li> + <li>如需更换计算的伤害类型,可使用命令 <strong>{{gameHash}}{{data.abbr}}伤害+序号</strong>来切换,序号参见伤害计算板块</li> + </ul> + </div> + </div> + {{/if}} + + <div class="dmg-cont dmg-msg cont"> + <div class="cont-title">Buff列表<span>部分Buff的触发条件以及层数可能影响实际伤害结果</span></div> + <div class="cont-table"> + {{each dmgMsg msg}} + <div class="tr"> + <div class="th">{{msg[0]}}</div> + <div class="td">{{msg[1]}}</div> + </div> + {{/each}} + </div> + </div> + {{/if}} + </div> +</div> + +{{if game === 'sr' && data.dataSource === '喵喵Api'}} +<div class="copyright ad">关注微信公众号“星铁工具箱”获得更多信息</div> +{{/if}} + +{{/block}} diff --git a/Yunzai/plugins/miao-plugin/resources/character/profile-detail.less b/Yunzai/plugins/miao-plugin/resources/character/profile-detail.less new file mode 100644 index 0000000000000000000000000000000000000000..58a6ed9fb2af7f542cd401349e784665c2da3e3e --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/profile-detail.less @@ -0,0 +1,1349 @@ +@import "../common/base.less"; + +body { + width: 600px; +} + +.container { + width: 600px; + padding: 0; + background-size: cover; + overflow: hidden; +} + + +.basic { + position: relative; + margin-bottom: 10px; +} + +.basic:after { + content: ""; + display: block; + position: absolute; + left: 8px; + top: 115px; + bottom: 0; + right: 8px; + box-shadow: 0 0 2px 0 #fff; + border-radius: 5px; + z-index: 1; +} + +.main-pic { + width: 1400px; + height: 500px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + margin-left: -545px; + position: relative; + z-index: 2; +} + +.detail { + position: absolute; + right: 20px; + top: 20px; + color: #fff; + z-index: 3; +} + +.char-name { + font-size: 50px; + .font-NZBZ; + text-shadow: 0 0 3px #000, 2px 2px 4px rgba(0, 0, 0, .7); + text-align: right; +} + +.char-lv { + margin-bottom: 20px; + text-shadow: 0 0 3px #000, 2px 2px 4px rgba(0, 0, 0, .7); + text-align: right; + + .cons { + margin-left: 5px; + vertical-align: bottom; + } +} + +@i: 16px; + +.char-attr { + backdrop-filter: blur(2px); + background: rgba(0, 0, 0, .2); + border-radius: 8px; + overflow: hidden; + + li { + width: 300px; + font-size: 17px; + list-style: none; + height: 32px; + line-height: 32px; + text-shadow: 0 0 1px rgba(0, 0, 0, .5); + display: flex; + padding-left: 3px; + + &:nth-child(even) { + background: rgba(0, 0, 0, .4) + } + + &:nth-child(odd) { + background: rgba(50, 50, 50, .4) + } + + .weight { + width: 36px; + + span { + display: block; + width: 30px; + border-radius: 5px; + font-size: 12px; + height: 18px; + line-height: 18px; + background: rgba(0, 0, 0, .5); + text-align: center; + margin: 7px auto 0; + + &.gold { + color: #ffe699; + } + } + } + + .icon { + width: @i+10px; + padding: 2px 5px; + + i { + display: inline-block; + height: @i; + width: @i; + background-image: url("./imgs/icon.png"); + background-size: auto @i; + } + } + + .title { + width: 75px; + text-shadow: 0 0 1px rgba(0, 0, 0, .8), 1px 1px 3px rgb(0 0 0 / 50%); + } + + .value { + width: 100px; + text-align: right; + font-weight: normal; + padding-right: 10px; + text-shadow: 0 0 1px rgba(0, 0, 0, .8), 1px 1px 3px rgb(0 0 0 / 50%); + } + + .value2 { + font-weight: normal; + width: 70px; + text-align: right; + font-size: 12px; + padding: 4px 10px 0 0; + background: rgba(0, 0, 0, .2); + + span { + display: block; + height: 13px; + line-height: 13px; + transform-origin: right center; + } + + .base { + color: #eee; + } + + .plus { + color: #90e800; + } + } + + + } +} + +.i-hp { + background-position: @i*-1 0; +} + +.i-atk { + background-position: @i*-2 0; +} + +.i-def { + background-position: @i*-3 0; +} + +.i-mastery { + background-position: @i*-4 0; +} + + +.i-cpct { + background-position: @i*-5 0; +} + +.i-cdmg { + background-position: @i*-6 0; +} + +.i-stance { + background-position: @i*-4 0; +} + +.i-recharge { + background-position: @i*-7 0; +} + +.i-dmg { + background-position: @i*-8 0; +} + +.i-heal { + background-position: @i*-9 0; +} + +.i-speed { + background-position: @i*-10 0; +} + +.i-effPct { + background-position: @i*-11 0; +} + +.i-effDef { + background-position: @i*-12 0; +} + +.detail.attr { + li { + &:nth-child(even) { + background: rgba(0, 0, 0, .4) + } + + &:nth-child(odd) { + background: rgba(50, 50, 50, .4) + } + + strong { + display: inline-block; + position: absolute; + right: 85px; + text-align: right; + font-weight: normal; + } + + span { + position: absolute; + right: 0; + text-align: left; + width: 75px; + display: inline-block; + color: #90e800; + font-size: 15px; + } + } +} + +.talent-icon { + width: 100px; + height: 100px; + padding: 5px; + display: table; + border-radius: 50%; + position: relative; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; + z-index: 90; + + img, + .talent-icon-img { + width: 46%; + height: 46%; + position: absolute; + top: 50%; + left: 50%; + margin: -22% 0 0 -23%; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + } + + strong { + background: #fff; + width: 34px; + height: 26px; + line-height: 26px; + font-size: 17px; + text-align: center; + border-radius: 5px; + position: absolute; + bottom: 2px; + left: 50%; + margin-left: -15px; + color: #000; + box-shadow: 0 0 5px 0 #000; + } + + &.talent-plus strong { + background: #2e353e; + color: #ffdfa0; + font-weight: bold; + box-shadow: 0 0 1px 0 #d3bc8e, 1px 1px 2px 0 rgba(0, 0, 0, 0.5); + } + + &.talent-crown:after { + content: ""; + display: block; + width: 28px; + height: 28px; + background: url("../character/imgs/crown.png") no-repeat; + background-size: contain; + position: absolute; + left: 50%; + top: 0; + margin-left: -14px; + } +} + +.char-talents { + display: flex; + width: 300px; + margin: 0 0 10px 0; +} + +.char-cons { + display: flex; + width: 250px; + position: absolute; + bottom: 5px; + left: 20px; +} + +.char-cons .talent-item, +.char-talents .talent-item { + flex: 1; +} + +.char-cons .talent-icon { + width: 50px; + height: 50px; + margin: 0 -5px +} + +.char-cons .talent-icon.off { + filter: grayscale(100%); + opacity: .4; +} + + +.elem_anemo .talent-icon { + background-image: url(../common/bg/talent-anemo.png) +} + +.elem_anemo .container { + background-image: url(../common/bg/bg-anemo.jpg); +} + + +.elem_cryo .talent-icon { + background-image: url(../common/bg/talent-cryo.png) +} + +.elem_cryo .container { + background-image: url(../common/bg/bg-cryo.jpg); +} + + +.elem_electro .talent-icon { + background-image: url(../common/bg/talent-electro.png) +} + +.elem_electro .container { + background-image: url(../common/bg/bg-electro.jpg); +} + + +.elem_geo .talent-icon { + background-image: url(../common/bg/talent-geo.png) +} + +.elem_geo .container { + background-image: url(../common/bg/bg-geo.jpg); +} + + +.elem_hydro .talent-icon { + background-image: url(../common/bg/talent-hydro.png) +} + +.elem_hydro .container { + background-image: url(../common/bg/bg-hydro.jpg); +} + + +.elem_pyro .talent-icon { + background-image: url(../common/bg/talent-pyro.png) +} + +.elem_pyro .container { + background-image: url(../common/bg/bg-pyro.jpg); +} + +.data-info { + position: absolute; + bottom: -10px; + right: 15px; + font-size: 12px; + color: rgba(255, 255, 255, .85); + text-align: right; + text-shadow: 1px 1px 1px #000; + z-index: 2; + line-height: 20px; + padding-right: 5px; + + .time { + margin-left: 5px; + } +} + + +/*** dmg ***/ +.cont { + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 100%; + margin: 5px 15px 5px 10px; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, .8); + overflow: hidden; + color: #fff; + font-size: 16px; +} + +.dmg-cont { + display: table; + width: calc(100% - 25px); + margin-top: 10px; + margin-bottom: 10px; +} + +.dmg-mode .dmg-list .cont-footer { + display: none; +} + +.cont-title { + background: rgba(0, 0, 0, .4); + color: #d3bc8e; + padding: 10px 20px; + text-align: left; +} + +.cont-title span { + font-size: 12px; + color: #aaa; + margin-left: 10px; + font-weight: normal; +} + +.cont-footer { + padding: 10px 15px; + font-size: 12px; + background: rgba(0, 0, 0, 0.5); + font-weight: normal; +} + +.cont-table { + display: table; + width: 100%; +} + +.dmg-cont .tr { + display: table-row; +} + +.dmg-cont .tr:nth-child(even) { + background: rgba(0, 0, 0, .4); +} + +.dmg-cont .tr:nth-child(odd) { + background: rgba(50, 50, 50, .4); +} + +.dmg-cont .tr > div { + display: table-cell; + box-shadow: 0 0 1px 0 #fff; +} + +.dmg-cont .tr > div.value-full { + display: table; + width: 200%; +} + +.dmg-cont .tr > div.value-none { + box-shadow: none; +} + +.dmg-cont .thead { + text-align: center; +} + +.dmg-cont .thead > div { + color: #d3bc8e; + background: rgba(0, 0, 0, .4); + line-height: 40px; + height: 40px; +} + + +.dmg-cont .title, +.dmg-cont .th { + color: #d3bc8e; + padding-right: 15px; + text-align: right; + background: rgba(0, 0, 0, .4); + min-width: 100px; +} + +.profile-mode .dmg-idx { + display: none !important; +} + +.profile-mode .dmg-title { + width: 33.3333%; +} + +.dmg-mode, +.weapon-mode { + .dmg-idx { + display: table-cell; + width: 5%; + min-width: initial; + padding-right: 0; + text-align: center; + } + + .dmg-title { + width: 31%; + min-width: initial; + text-align: left; + padding-left: 10px; + padding-right: 0; + } +} + + +.dmg .value { + text-align: center; + color: #fff; + display: block; + height: 40px; + font-size: 18px; + line-height: 40px; + width: 32% +} + +.dmg-notice { + font-size: 12px; + text-align: right; + color: #f5f5f5; + margin-right: 15px; +} + + +/*** artis***/ +.artis { + display: flex; + width: 600px; + flex-wrap: wrap; + margin-bottom: 5px; + padding: 0 5px; + + + .item { + width: 185px; + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 100%; + margin: 5px; + //height: 200px; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, .8); + overflow: hidden; + + + .arti-icon { + width: 60px; + height: 60px; + position: absolute; + left: 2px; + top: 3px; + + + span { + position: absolute; + right: 2px; + bottom: 0; + margin-left: 5px; + background: rgba(0, 0, 0, .5); + border-radius: 5px; + height: 18px; + line-height: 18px; + padding: 0 3px; + color: #fff; + font-size: 12px; + display: block; + } + + .img { + width: 50px; + height: 50px; + margin: 5px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + } + } + + } + + .head { + color: #fff; + padding: 12px 0 8px 68px; + + strong { + font-size: 15px; + display: block; + white-space: nowrap; + overflow: hidden; + //font-font: YS; + } + + span { + font-size: 14px; + } + + .mark { + } + } +} + +.mark-ACE, +.mark-ACE² { + color: #e85656; + font-weight: bold; +} + +.mark-SSS, +.mark-SS { + color: #ffe699; + font-weight: bold; +} + +.mark-S, +.mark-A { + color: #d699ff; + font-weight: bold; +} + +.arti-main { + color: #fff; + padding: 6px 15px; +} + + +.artis ul.detail { + width: 100%; + padding: 0; + position: initial; + display: table; +} + +.artis ul.detail li { + padding: 0 3px; + font-size: 14px; + position: relative; + width: 100%; + display: table-row; + line-height: 26px; + height: 26px; + white-space: nowrap; + + span { + position: initial; + display: table-cell; + color: #fff; + + &.title { + text-align: left; + padding-left: 30px; + font-size: 14px; + + i.eff { + position: absolute; + display: block; + left: 3px; + top: 4px; + font-size: 12px; + font-style: normal; + background: rgba(0, 0, 0, 0.5); + border-radius: 5px; + height: 18px; + line-height: 18px; + width: 23px; + text-align: center; + } + + i.up-num { + position: absolute; + display: block; + left: 91px; + top: 9px; + height: 8px; + width: 50px; + background-image: url('./imgs/up-num-icon1.png'); + background-position: 0 0; + background-repeat: no-repeat; + background-size: auto 500%; + + + &.up-5 { + background-position: 0 -8px; + } + + &.up-4 { + background-position: 0 -16px; + } + + &.up-3 { + background-position: 0 -24px; + } + + &.up-2 { + background-position: 0 -32px; + } + + &.up-1 { + background: none !important; + } + } + } + + &.val { + text-align: right; + padding-right: 10px; + font-size: 14px; + } + } + + + &.great span.title { + color: #ffe699; + + i.up-num { + background-image: url("./imgs/up-num-icon2.png"); + background-size: auto 500%; + } + } + + &.nouse span { + color: #888; + + i.up-num { + background-image: url("./imgs/up-num-icon0.png"); + background-size: auto 500%; + } + } + + &.arti-main { + font-size: 16px; + padding: 3px 3px; + font-weight: bold; + } +} + + +.artis .weapon .star { + height: 20px; + width: 100px; + background: url("../common/item/star.png") no-repeat; + background-size: 100px 100px; + transform: scale(0.8); + transform-origin: 100px 10px; + display: inline-block; + display: none; +} + +.artis .weapon .star.star-2 { + background-position: 0 -20px; +} + +.artis .weapon .star.star-3 { + background-position: 0 -40px; +} + +.artis .weapon .star.star-4 { + background-position: 0 -60px; +} + +.artis .weapon .star.star-5 { + background-position: 0 -80px; +} + + +.artis .weapon { + height: 96px; + overflow: visible; + margin-bottom: 10px; + + + .img { + width: 106px; + height: 106px; + top: -10px; + right: -10px; + position: absolute; + z-index: 2; + background-position: center; + background-size: contain; + background-repeat: no-repeat; + } + + .head { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + padding: 15px 0 10px 15px; + z-index: 3; + border-radius: 10px; + background: linear-gradient(to right, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7), rgba(25, 25, 25, 0.5), rgba(25, 25, 25, 0), rgba(25, 25, 25, 0)); + + strong { + font-size: 15px; + margin-bottom: 3px; + } + + & > span { + display: block; + + } + } + + span.info { + font-size: 14px; + margin-bottom: 8px; + } + + .affix { + color: #000; + padding: 0 7px; + border-radius: 4px; + font-size: 14px; + width: 40px; + margin-right: 5px; + } + + .affix-1 { + box-shadow: 0 0 4px 0 #a3a3a3 inset; + background: #ebebebaa; + } + + .affix-2 { + box-shadow: 0 0 4px 0 #51b72fbd inset; + background: #ddffdeaa; + } + + .affix-3 { + box-shadow: 0 0 4px 0 #396cdecf inset; + background: #ddebffaa; + } + + .affix-4 { + box-shadow: 0 0 4px 0 #c539debf inset; + background: #ffddf0aa; + } + + .affix-5 { + box-shadow: 0 0 4px 0 #deaf39 inset; + background: #fff6dd; + } + + .weapon-attr { + font-size: 14px; + text-shadow: 0 0 1px #000, 1px 1px 2px rgba(0, 0, 0, 0.7); + display: flex; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 26px; + width: 100%; + background: rgba(0, 0, 0, .2); + line-height: 26px; + border-radius: 0 0 10px 10px; + text-align: center; + padding: 0 5px 0 10px; + + div { + width: 50%; + + span { + color: #ffe699; + font-weight: bold; + } + } + } +} + +.artis .arti-stat { + height: 84px; +} + +.arti-class-title { + height: 25px; + line-height: 20px; + font-size: 12px; + color: #fff; + padding: 5px 10px 0; + text-align: center; + color: rgba(255, 255, 255, .9); + text-shadow: 0 0 2px #000; +} + +.arti-stat-ret { + height: 55px; + padding: 0 10px 5px; + width: 100%; + display: table; + + & > div { + display: table-cell; + text-align: center; + color: #fff; + } + + strong { + display: block; + height: 35px; + font-size: 30px; + line-height: 35px; + } +} + +.dmg-msg { + font-size: 13px; + font-weight: normal; +} + +.dmg-msg .thead > div { + text-align: left; + padding-left: 10px; +} + +.dmg-msg .th { + text-align: left; + padding-left: 10px; +} + +.dmg-msg .tr .td { + padding: 8px 10px; +} + +.dmg-msg .info { + font-size: 12px; + text-align: left; + padding-left: 10px; + font-weight: normal; +} + + +.dmg-calc { + +} + +.dmg-calc .thead { + +} + +.dmg-calc .thead > div { + line-height: initial; +} + +.dmg-calc .cont-table div { + vertical-align: middle; + text-align: center; + white-space: nowrap; +} + +.dmg-calc .title { + text-align: center; + padding-right: 0; + min-width: 70px; + +} + +.dmg-calc .td { + padding: 5px 0; +} + +.dmg-calc strong { + font-weight: normal; + display: block; +} + +.dmg-calc span { + font-size: 12px; + color: #aaa; +} + +.dmg-calc .na, +.dmg-calc .eq { + background: rgba(50, 50, 50, .5); +} + +.dmg-calc .na { + color: #888; +} + +.dmg-calc .lt { + background: rgba(23, 112, 41, 0.5); +} + +.dmg-calc .gt { + background: rgba(112, 23, 23, 0.5); +} + +.dmg-desc { + color: #aaa; +} + +.dmg-desc ul { + padding-left: 10px; +} + +.dmg-desc ul li { + color: #aaa; +} + +.dmg-desc strong { + color: #d3bc8e; + display: inline; + padding: 0 3px; + font-weight: normal; +} + + +.arti-stat span { + font-size: 13px; + line-height: 20px; + color: #bbb; +} + +.game-sr { + + .artis-weapon { + display: none; + } + + .char-lv { + margin-bottom: 25px; + } + + .char-attr { + .icon i { + background-image: url('./imgs/icon-sr.png'); + } + } +} + +.artis { + .item.arti { + overflow: visible; + + .head { + position: relative; + border-radius: 10px 10px 0 0; + text-shadow: 0 0 1px #000, 1px 1px 2px rgba(0, 0, 0, 0.7); + padding: 15px 10px 5px 15px; + background: linear-gradient(to right, rgba(0, 0, 0, .7), rgba(0, 0, 0, .7), rgba(25, 25, 25, .3), rgba(25, 25, 25, .0), rgba(25, 25, 25, 0)); + } + + .arti-icon { + left: auto; + right: 0; + top: -12px; + width: 90px; + height: 90px; + + .img { + width: 100%; + height: 100%; + margin: 0; + -webkit-mask: linear-gradient(45deg, #0000 0, #0005 30%, #000 50%); + } + + span { + top: 50px; + right: 8px; + background: rgba(0, 0, 0, .8); + } + } + } + + ul.detail { + backdrop-filter: blur(2px); + border-radius: 0 0 10px 10px; + overflow: hidden; + + li.arti-main { + background: rgba(25, 25, 25, .5); + + .title { + padding-left: 15px; + } + } + } +} + +.sr-weapon { + margin: 0 15px 5px 10px; + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 150%; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, .8); + overflow: hidden; + display: table; + color: #fff; + min-height: 120px; + width: calc(100% - 25px); + + .weapon-img { + display: table-cell; + width: 185px; + height: 100%; + min-height: 120px; + background-size: 100% auto; + background-position: 0 5%; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, .8); + } + + .weapon-info { + display: table-cell; + padding: 10px 10px 5px 15px; + } + + .weapon-title { + + span { + font-size: 14px; + } + + strong { + color: #d3bc8e; + font-weight: normal; + } + } + + .weapon-attr { + font-size: 12px; + height: 25px; + line-height: 25px; + display: flex; + + .attr { + padding-left: 22px; + padding-right: 7px; + margin-right: 10px; + position: relative; + line-height: 22px; + height: 22px; + font-size: 12px; + + color: #ffe699; + display: inline-block; + border-radius: 4px; + + + background: rgba(0, 0, 0, 0.5); + text-align: center; + + span { + font-size: 12px; + display: none; + } + + &:before { + content: ""; + display: inline-block; + width: 22px; + height: 22px; + background-size: auto 100%; + background-position: top center; + vertical-align: middle; + position: absolute; + left: 0; + top: 0; + } + } + + .i-hp:before { + background-image: url('../meta-sr/public/icons/attr-hp.webp') + } + + .i-atk:before { + background-image: url('../meta-sr/public/icons/attr-atk.webp') + } + + .i-def:before { + background-image: url('../meta-sr/public/icons/attr-def.webp') + } + } + + .weapon-desc { + margin-top: 7px; + font-size: 12px; + font-weight: normal; + color: #fff; + white-space: break-spaces; + text-shadow: 0 0 1px rgba(0, 0, 0, 0.7), 1px 1px 3px rgba(0, 0, 0, 0.4); + + nobr { + color: #ffe699; + display: inline-block; + border-radius: 4px; + font-size: 12px; + height: 16px; + line-height: 16px; + background: rgba(0, 0, 0, 0.5); + text-align: center; + padding: 0 3px; + margin: 0 2px; + } + } +} + +.sr-talent { + margin: 0 15px 10px 10px; + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 150%; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, .8); + overflow: hidden; + display: flex; + color: #fff; + height: 72px; + width: calc(100% - 25px); + padding: 8px 10px; + + + .char-talents { + transform-origin: center left; + margin: 0; + width: 260px; + + + .talent-item { + margin: 0 -3px; + } + + .talent-icon { + width: 60px; + height: 60px; + + strong { + font-size: 13px; + width: 22px; + height: 20px; + line-height: 20px; + margin-left: -11px; + border-radius: 4px; + } + + span { + position: absolute; + top: -3px; + font-size: 12px; + left: 0; + right: 0; + text-align: center; + color: #fff; + text-shadow: 0 0 3px #000, 1px 1px 1px #000; + } + + &.talent-crown:after { + width: 22px; + height: 22px; + margin: 2px 0 0 5px; + background-image: url('../character/imgs/crown-sr.webp'); + display: none; + } + } + } + + .char-trees { + width: 290px; + padding-left: 10px; + position: relative; + + .talent-icon { + margin: 0 -5px; + + &.off { + filter: grayscale(100%); + opacity: .4; + } + } + + &:before { + content: ""; + display: block; + width: 1px; + height: 30px; + background: rgba(255, 255, 255, .8); + position: absolute; + left: 0; + top: 15px; + } + + .talent-item { + width: 40px; + + .talent-icon { + margin: 0; + } + } + + .tree-item { + width: 20px; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + + .talent-icon { + width: 30px; + height: 30px; + margin: 0 -5px; + } + + .talent-icon-img { + + } + } + } + +} + +.copyright.ad { + font-size: 12px; +} diff --git a/Yunzai/plugins/miao-plugin/resources/character/profile-list.css b/Yunzai/plugins/miao-plugin/resources/character/profile-list.css new file mode 100644 index 0000000000000000000000000000000000000000..097f034e98edb6a088635457ec395c810c17559d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/profile-list.css @@ -0,0 +1,158 @@ +body, +.container { + width: 650px; +} +.container > .cont { + margin-left: 15px; +} +.head-box { + margin-top: 10px; +} +.head-box .label { + font-size: 14px; +} +.char-list { + display: flex; + flex-wrap: wrap; + padding: 10px; +} +.char-item { + margin: 5px 0; + width: 75px; + position: relative; +} +.char-item .name { + margin-top: 5px; + display: block; + font-size: 14px; + color: #fff; + text-align: center; + text-shadow: 0 0 1px #000; + white-space: nowrap; +} +.char-item .name .cons { + padding: 1px 4px; + font-size: 12px; + transform: scale(0.8); + margin: -2px 0 0 1px; + vertical-align: middle; + opacity: 0.9; +} +.char-item.new-char .name:before { + content: ""; + display: inline-block; + width: 8px; + height: 8px; + background: #90e800; + border-radius: 50%; + margin-right: 3px; +} +.char-item .group-rank { + position: absolute; + background: url('./imgs/dmg-rank-bg.png') left top no-repeat; + background-size: auto 100%; + left: 0; + top: 0; + margin-top: -5px; + width: 74px; + height: 74px; +} +.char-item .group-rank.rank-type-mark { + background-image: url('./imgs/mark-rank-bg.png'); +} +.char-item .group-rank span { + position: absolute; + font-size: 12px; + width: 16px; + height: 16px; + bottom: 0; + left: 50%; + margin-left: -7px; + text-align: center; + transform: scale(0.8); + display: none; + text-shadow: 0 0 2px #b26f08; +} +.char-item .group-rank.rank-1 { + background-position: 25% 0; +} +.char-item .group-rank.rank-2 { + background-position: 50% 0; +} +.char-item .group-rank.rank-3 { + background-position: 75% 0; +} +.char-item .group-rank.rank-4 { + background-position: 100% 0; +} +.char-item .group-rank.rank-4 span { + display: block; +} +.char-icon { + width: 64px; + height: 64px; + border-radius: 50%; + border: 2px solid #fff; + box-shadow: 1px 1px 3px 0 #000; + overflow: visible; + margin: 0 5px 0 6px; +} +.char-icon .img { + background-size: auto 100%; + background-position: top center; + overflow: hidden; + border-radius: 50%; +} +.cont-footer { + display: flex; + background: rgba(0, 0, 0, 0.4); + width: 100%; +} +.cont-footer span { + width: 50%; +} +.cont-footer .serv { + text-align: right; +} +.cont-footer .new-tip:before { + content: ""; + display: inline-block; + width: 8px; + height: 8px; + background: #90e800; + border-radius: 50%; + margin-right: 3px; +} +.group-rank-icon { + width: 16px; + height: 16px; + background: url("./imgs/mark-icon.png"); + background-size: auto 100%; + display: inline-block; + vertical-align: bottom; + margin: -1px 3px -1px 0; +} +.group-rank-icon.mark-icon { + background-position: 100% 0; +} +.cont-title { + padding: 8px 5px 10px; + background: rgba(0, 0, 0, 0.4); +} +.cont-title span { + color: #fff; + width: 50%; +} +.cont-title .rank-time { + font-size: 12px; + color: #aaa; + display: inline-block; + transform: scale(0.85); + transform-origin: 0 50%; + white-space: nowrap; +} +.no-rank .group-rank, +.no-rank.group-rank-tip { + display: none; +} +/*# sourceMappingURL=profile-list.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/profile-list.html b/Yunzai/plugins/miao-plugin/resources/character/profile-list.html new file mode 100644 index 0000000000000000000000000000000000000000..1a9ab9e66b084ed5a3b325ce0352ecaf3a86300f --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/profile-list.html @@ -0,0 +1,65 @@ +{{extend elemLayout}} + +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/profile-detail.css"/> +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/profile-list.css"/> +{{/block}} + + +{{block 'main'}} +{{set demo = chars[0]?.abbr || "雷神" }} +<div class="head-box"> + <div class="title">#面板列表 + <div class="label">UID:{{uid}}</div> + </div> + {{if msg}} + <div class="label">{{msg}}</div> + {{/if}} + <div class="label">你可以使用<span>#{{demo}}面板</span>、<span>#{{demo}}伤害</span>、<span>#{{demo}}圣遗物</span>命令来查看面板信息了</div> +</div> +<div class="cont group-rank-tip {{groupRank?'has-rank':'no-rank'}}"> + <div class="cont-title"> + {{if !allowRank}} + <span> <i class="group-rank-icon dmg-icon"></i>本面板暂未参与排名,参与要求:{{rankCfg.limitTxt}} </span> + {{else}} + <span> + <i class="group-rank-icon dmg-icon"></i>综合练度排名 + <i class="group-rank-icon mark-icon"></i>圣遗物评分排名 + </span> + <span class="rank-time"> + 排名:本群内 {{rankCfg.time}} 后,通过 #面板 命令查看过的角色数据 + </span> + {{/if}} + </div> +</div> +<div class="cont {{groupRank?'has-rank':'no-rank'}}"> + <div class="char-list"> + {{each chars char}} + <div class="char-item {{char.isNew&&hasNew ?'new-char':''}}"> + <div class="item-icon char-icon star{{char.star}}"> + <span class="img" + style="background-image:url({{_res_path}}{{char.face}})"></span> + </div> + <span class="name">{{char.abbr}}<span class="cons cons-{{char.cons}}">{{char.cons}}</span></span> + {{if char.groupRank}} + {{set gr = char.groupRank}} + {{set rank = gr.rank >= (rankCfg.number || 15) ? 10:(gr.rank <=3 ? gr.rank : 4)}} + <div class="group-rank rank-{{rank}} rank-type-{{gr.rankType}}"> + <span>{{gr.rank}}</span> + </div> + {{/if}} + </div> + {{/each}} + </div> + <div class="cont-footer"> + {{if hasNew}} + <span class="new-tip">本次更新角色</span> + {{else}} + <span>{{if updateTime.profile }} 更新时间:{{updateTime.profile }} {{/if}}</span> + {{/if}} + <span class="serv"> + 当前更新服务:{{servName}} + </span> + </div> +</div> +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/profile-list.less b/Yunzai/plugins/miao-plugin/resources/character/profile-list.less new file mode 100644 index 0000000000000000000000000000000000000000..f0de3bbc8d0c14e6c78a61218e50a57f67b2b14d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/profile-list.less @@ -0,0 +1,188 @@ +body, .container { + width: 650px; +} + +.container > .cont { + margin-left: 15px; +} + +.head-box { + margin-top: 10px; + + .label { + font-size: 14px; + } +} + +.char-list { + display: flex; + flex-wrap: wrap; + padding: 10px; +} + +.char-item { + margin: 5px 0; + width: 75px; + position: relative; + + .name { + margin-top: 5px; + display: block; + font-size: 14px; + color: #fff; + text-align: center; + text-shadow: 0 0 1px #000; + white-space: nowrap; + + .cons { + padding: 1px 4px; + font-size: 12px; + transform: scale(.8); + margin: -2px 0 0 1px; + vertical-align: middle; + opacity: .9; + } + } + + &.new-char { + .name:before { + content: ""; + display: inline-block; + width: 8px; + height: 8px; + background: #90e800; + border-radius: 50%; + margin-right: 3px; + } + } + + .group-rank { + position: absolute; + background: url('./imgs/dmg-rank-bg.png') left top no-repeat; + background-size: auto 100%; + left: 0; + top: 0; + margin-top: -5px; + width: 74px; + height: 74px; + + &.rank-type-mark { + background-image: url('./imgs/mark-rank-bg.png'); + } + + span { + position: absolute; + font-size: 12px; + width: 16px; + height: 16px; + bottom: 0; + left: 50%; + margin-left: -7px; + text-align: center; + transform: scale(.8); + display: none; + text-shadow: 0 0 2px #b26f08; + + } + + &.rank-1 { + background-position: 25% 0; + } + + &.rank-2 { + background-position: 50% 0; + } + + &.rank-3 { + background-position: 75% 0; + } + + &.rank-4 { + background-position: 100% 0; + + span { + display: block; + } + } + } +} + +.char-icon { + width: 64px; + height: 64px; + border-radius: 50%; + border: 2px solid #fff; + box-shadow: 1px 1px 3px 0 #000; + overflow: visible; + margin: 0 5px 0 6px; + + .img { + background-size: auto 100%; + background-position: top center; + overflow: hidden; + border-radius: 50%; + } +} + +.cont-footer { + display: flex; + background: rgba(0, 0, 0, .4); + width: 100%; + + span { + width: 50%; + } + + .serv { + text-align: right; + } + + .new-tip:before { + content: ""; + display: inline-block; + width: 8px; + height: 8px; + background: #90e800; + border-radius: 50%; + margin-right: 3px; + } +} + +.group-rank-icon { + width: 16px; + height: 16px; + background: url("./imgs/mark-icon.png"); + background-size: auto 100%; + display: inline-block; + vertical-align: bottom; + margin: -1px 3px -1px 0; + + &.mark-icon { + background-position: 100% 0; + } +} + +.cont-title { + padding: 8px 5px 10px; + background: rgba(0, 0, 0, .4); + + span { + color: #fff; + width: 50%; + } + + .rank-time { + font-size: 12px; + color: #aaa; + display: inline-block; + transform: scale(.85); + transform-origin: 0 50%; + white-space: nowrap; + } +} + + +.no-rank .group-rank, +.no-rank.group-rank-tip { + display: none; +} diff --git a/Yunzai/plugins/miao-plugin/resources/character/profile-stat.css b/Yunzai/plugins/miao-plugin/resources/character/profile-stat.css new file mode 100644 index 0000000000000000000000000000000000000000..3409b88c2e16487dfed2be07beaf139c6f148840 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/profile-stat.css @@ -0,0 +1,373 @@ +body { + background: url('./imgs/bg-01.jpg') left center; + background-size: 100% auto; +} +.container { + background: url('./imgs/main-01.png') center -25px no-repeat; + background-size: 100% auto; +} +.head-box { + margin-top: 0; +} +#profile-stat { + display: table; + border-collapse: collapse; + width: calc(100% + 30px); + margin: 0 -15px -5px; + overflow: hidden; +} +#profile-stat .item-banner { + display: flex; + flex-direction: row; + align-items: center; + height: 36px; +} +#profile-stat .item-banner .item-icon { + z-index: 10; +} +#profile-stat .level { + border-radius: 3px 0 0 3px; + width: 25px; + white-space: nowrap; + display: inline-block; +} +#profile-stat .level:before { + content: "Lv"; + display: inline-block; + font-size: 12px; + transform: scale(0.7); + transform-origin: right 55%; + margin-left: -3px; +} +.cont { + font-size: 14px; + background: none; + /* + .star(1, rgba(171, 171, 171, .5)); + .star(2, rgba(208, 255, 190, .5)); + .star(3, rgba(190, 208, 255, .5)); + .star(4, rgba(223, 190, 255, .5)); + .star(5, rgba(255, 228, 180, .5)); + */ +} +.cont .cons, +.cont .level { + height: 22px; + line-height: 22px; + display: inline-block; + width: 19px; + padding: 0; + text-align: center; + vertical-align: middle; + font-size: 13px; + position: relative; +} +.cont .cons { + width: 16px; + text-shadow: 0 0 2px rgba(0, 0, 0, 0.5); +} +.cont .fetter { + width: 32px; + height: 32px; +} +.cont .item-name { + padding-left: 5px; + text-align: left; + text-shadow: 0 0 1px rgba(255, 255, 255, 0.8); +} +.cont .tr.thead { + background: rgba(0, 0, 0, 0.4); + font-weight: bold; +} +.cont .tr.thead > div { + box-shadow: 0 0 1px 0 rgba(255, 255, 255, 0.7); + text-align: center; +} +.cont .tr.thead .td-talent { + color: #d3bc8e; +} +.cont .tr { + color: #333; + white-space: nowrap; +} +.cont .tr .td { + box-shadow: 0 0 1px 0 rgba(100, 100, 100, 0.3) inset; +} +.cont .tr .td.star1 { + background: rgba(200, 200, 200, 0.35); +} +.cont .tr .td.star1 .item-name { + color: #333; +} +.cont .tr .td.star2 { + background: rgba(168, 255, 133, 0.35); +} +.cont .tr .td.star2 .item-name { + color: #333; +} +.cont .tr .td.star3 { + background: rgba(137, 168, 255, 0.35); +} +.cont .tr .td.star3 .item-name { + color: #333; +} +.cont .tr .td.star4 { + background: rgba(195, 134, 255, 0.35); +} +.cont .tr .td.star4 .item-name { + color: #720465; +} +.cont .tr .td.star5 { + background: rgba(255, 212, 132, 0.35); +} +.cont .tr .td.star5 .item-name { + color: #6f4b00; +} +.cont .tr.thead { + background: rgba(0, 0, 0, 0.5) !important; +} +.cont .tr.thead > div { + color: #d3bc8e !important; +} +.cont .tr:nth-child(odd) { + background: #ffffff; +} +.cont .tr:nth-child(even) { + background: #f0f0f0; +} +.cont .tr > div { + text-align: center; + height: 36px; + vertical-align: middle; + line-height: 36px; + box-shadow: 0 0 1px 0 rgba(255, 255, 255, 0.7); +} +.cont .tr > div * { + vertical-align: middle; +} +.cont .tr .td-idx { + width: 30px; +} +.cont .tr .td-name { + text-align: left; + width: 100px; + padding-left: 3px; +} +.cont .tr .td-name .item-name { + width: 50px; +} +.cont .tr .td-name .char-icon { + width: 30px; + height: 30px; + border-radius: 5px; + display: inline-block; + overflow: visible; + background: none; +} +.cont .tr .td-name .char-icon .img { + width: 30px; + height: 30px; + position: relative; + top: 0; + left: 0; + border-radius: 0 0 6px 6px; +} +.cont .tr .td-lv { + width: 35px; +} +.cont .tr .td-fetter { + width: 40px; + text-align: center; +} +.cont .tr .td-cons { + width: 40px; + text-align: center; +} +.cont .tr .td-talent { + width: 35px; + box-shadow: 0 0 1px 0 rgba(150, 150, 150, 0.5); +} +.cont .tr .td-weapon { + text-align: left; + padding-left: 3px; +} +.cont .tr .td-weapon .level { + font-size: 12px; + transform: scale(0.9); + text-align: left; +} +.cont .tr .td-weapon .cons { + transform: scale(0.8); + margin-right: -2px; + font-size: 12px; + padding: 0; + height: 16px; + line-height: 16px; + width: 14px; +} +.cont .tr .td-weapon .weapon-icon { + border-radius: 0; + background: none; +} +.cont .tr .td-weapon .item-name { + padding-left: 2px; + padding-right: 10px; + font-size: 12px; +} +.cont .tr .weapon-icon { + width: 28px; + display: inline-block; + overflow: visible; +} +.cont .tr .weapon-icon .img { + width: 28px; + height: 36px; + margin: 0; +} +.cont .tr .talent-plus { + font-weight: bold; + color: #006cc7; + font-size: 15px; + text-shadow: 0px 0px 1px #fff; +} +.cont .tr .lv1 { + background: rgba(60, 63, 65, 0.3); +} +.cont .tr .lv1.talent-plus { + color: #333; +} +.cont .tr .lv2 { + background: rgba(23, 184, 58, 0.5); +} +.cont .tr .lv2.talent-plus { + color: #005800; +} +.cont .tr .lv3 { + background: rgba(27, 128, 212, 0.5); +} +.cont .tr .lv3.talent-plus { + color: #333; +} +.cont .tr .lv4 { + background: rgba(146, 90, 255, 0.55); +} +.cont .tr .lv4.talent-plus { + color: #720465; +} +.cont .tr .lv5 { + background: url("../common/item/crown-o.png") center center no-repeat rgba(255, 36, 26, 0.55); + background-size: contain; +} +.cont .tr .lv5.talent-plus { + color: #b70000; +} +.cont .td-artis { + width: 115px; + text-align: left; +} +.cont .td-artis.class-ACE, +.cont .td-artis.class-ACE² { + background: rgba(255, 228, 180, 0.5); +} +.cont .td-artis.class-ACE .artis-mark-class, +.cont .td-artis.class-ACE² .artis-mark-class { + background: #ff5722; +} +.cont .td-artis.class-SSS, +.cont .td-artis.class-SS { + background: rgba(223, 190, 255, 0.5); +} +.cont .td-artis.class-SSS .artis-mark-class, +.cont .td-artis.class-SS .artis-mark-class { + background: #531ba9cf; +} +.cont .td-artis.class-S, +.cont .td-artis.class-A { + background: rgba(190, 208, 255, 0.5); +} +.cont .td-artis.class-S .artis-mark-class, +.cont .td-artis.class-A .artis-mark-class { + background: #3955b7; +} +.cont .td-artis.class-B, +.cont .td-artis.class-C, +.cont .td-artis.class-D { + background: rgba(171, 171, 171, 0.5); +} +.cont .td-artis.class-B .artis-mark-class, +.cont .td-artis.class-C .artis-mark-class, +.cont .td-artis.class-D .artis-mark-class { + background: #aaa; +} +.cont .avatar-artis { + margin-left: 5px; + text-align: left; + position: relative; + z-index: 10; +} +.cont .avatar-artis .artis { + position: relative; + width: 30px; + height: 30px; + box-shadow: 0 0 1px 0 #ffe4b4; + display: inline-block; +} +.cont .avatar-artis .artis.no-artis { + background: #bbb; +} +.cont .avatar-artis .no-artis { + background: url(../common/item/artifact-icon.webp) center no-repeat; + background-size: auto 80%; +} +.cont .avatar-artis.artis2 .img { + position: absolute; + transform: scale(0.7); + width: 92%; + height: 92%; + margin: 4%; +} +.cont .avatar-artis.artis2 .img:first-child { + transform-origin: left top; +} +.cont .avatar-artis.artis2 .img:last-child { + transform-origin: right bottom; +} +.cont .artis-mark-class { + width: 28px; + font-size: 12px; + border-radius: 5px; + display: inline-block; + text-align: center; + background: rgba(51, 51, 51, 0.68); + height: 20px; + line-height: 20px; + box-shadow: 0 0 1px 0 #ffe4b4; + position: relative; + z-index: 9; + margin: 0 -2px; + transform: scale(0.7); + color: #fff; +} +.cont .artis-na { + padding-left: 12px; + white-space: nowrap; + transform: scale(0.8); + transform-origin: left center; + color: #888; + font-size: 12px; + margin-right: -60px; +} +.cont-notice { + background: rgba(0, 0, 0, 0.7); + font-size: 13px; + text-align: right; + padding: 8px 12px 8px 8px; +} +.cont-notice strong { + color: #d3bc8e; + font-weight: normal; +} +.cont-notice span { + margin-left: 5px; +} +/*# sourceMappingURL=profile-stat.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/profile-stat.html b/Yunzai/plugins/miao-plugin/resources/character/profile-stat.html new file mode 100644 index 0000000000000000000000000000000000000000..9f109141963c21621bfe646e110f110e35cf77e1 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/profile-stat.html @@ -0,0 +1,118 @@ +{{extend defaultLayout}} + +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/profile-stat.css"/> +{{/block}} + + +{{block 'main'}} +<div class="head-box"> + <div class="title">#面板练度统计</div> + <div class="label">UID:{{uid}} 共{{avatars.length }}名角色</div> +</div> +<div id="profile-stat"> + <div class="cont"> + <div class="cont-table"> + <div class="avatar tr thead"> + <div class="td-idx">#</div> + <div class="td-name">角色</div> + <div class="td-lv">Lv</div> + <div class="td-cons">命座</div> + <div class="td-fetter">好感</div> + <div class="td-talent">A</div> + <div class="td-talent">E</div> + <div class="td-talent">Q</div> + <div class="td-weapon">武器</div> + <div class="td-artis">圣遗物</div> + </div> + {{each avatars avatar idx}} + {{set talent = avatar.talent}} + {{set weapon = avatar.weapon}} + {{set tk = ['a','e','q'] }} + <div class="avatar tr"> + <div class="td td-idx star{{avatar.star}}">{{idx+1}}</div> + <div class="td td-name star{{avatar.star}}"> + <div class="item-banner"> + <div class="item-icon char-icon star{{avatar.star}}"> + <span class="img" + style="background-image:url({{_res_path}}{{avatar.face}})"></span> + </div> + + <span class="item-name">{{avatar.abbr||avatar.name}}</span> + </div> + </div> + <div class="td td-lv">{{avatar.level}}</div> + <div class="td td-cons"> + <span class="cons avatar cons-{{avatar.cons}}">{{avatar.cons}}</span> + </div> + <div class="td td-fetter"> + <span class="fetter fetter{{['空','荧','旅行者'].includes(avatar.name)?10:avatar.fetter}}"></span> + </div> + + {{set talentLvMap = [0,1,1,1,2,2,3,3,3,4,5] }} + {{each tk talentKey}} + {{set curr = (avatar.talent||{})[talentKey] || {original:1,level:'-'} }} + <div class="td-talent lv{{talentLvMap[curr.original]}} {{curr.level>curr.original?'talent-plus':''}}"> + {{curr.level}} + </div> + {{/each}} + + <div class="td td-weapon star{{weapon.star}}"> + {{if weapon?.name}} + <div class="item-banner star{{weapon.star}}"> + <span class="level">{{weapon.level}}</span> + + <div class="item-icon weapon-icon"> + <span class="img" + style="background-image:url({{_res_path}}{{weapon.img}})"></span> + </div> + <span class="cons weapon cons-{{weapon.affix+1}} star{{weapon.star}}">{{weapon.affix}}</span> + <span class="item-name">{{weapon.abbr}}</span> + </div> + {{/if}} + </div> + {{set mark = avatar.artisMark || false }} + {{set imgs = avatar?.artisMark?.imgs || avatar?.artisSet?.imgs || []}} + <div class="td td-artis class-{{mark?.markClass||'D'}}"> + <div class="item item-banner avatar-artis artis{{imgs.length}}"> + <div class="artis item-icon {{imgs.length>0?'star5':'no-artis'}}"> + {{each imgs img}} + <div class="img" style="background-image:url({{_res_path}}{{img}})"></div> + {{/each}} + {{if imgs.length === 0}} + <span class="img no-artis"></span> + {{/if}} + </div> + {{if mark}} + <span class="artis-mark-class class-{{mark?.markClass||'D'}}">{{mark.markClass}}</span> + {{mark.mark}} + {{else}} + <span class="artis-na">暂无面板数据</span> + {{/if}} + </div> + + </div> + </div> + {{/each}} + </div> + + <div class="cont-notice"> + {{set ut = updateTime }} + {{if ut.profile || ut.mys}} + <strong>数据更新时间</strong> + {{if ut.profile}} + <span>#更新面板: {{ut.profile}}</span> + {{/if}} + {{if ut.mys}} + <span>米游社: {{ut.mys}}</span> + {{/if}} + {{else}} + 未绑定CK或CK失效,信息可能不完全。发送<strong>#体力帮助</strong>查看CK绑定方法,发送<strong>#更新面板</strong>更新游戏内角色展柜信息 + {{/if}} + </div> + + </div> +</div> + + +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/profile-stat.less b/Yunzai/plugins/miao-plugin/resources/character/profile-stat.less new file mode 100644 index 0000000000000000000000000000000000000000..5e93d7509796d37ee1fe8615b9b513426bd6ebf8 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/profile-stat.less @@ -0,0 +1,418 @@ +body { + background: url('./imgs/bg-01.jpg') left center; + background-size: 100% auto; +} + +.container { + background: url('./imgs/main-01.png') center -25px no-repeat; + background-size: 100% auto; +} + +.head-box { + margin-top: 0; +} + +#profile-stat { + display: table; + border-collapse: collapse; + width: calc(100% + 30px); + margin: 0 -15px -5px; + overflow: hidden; + + .item-banner { + display: flex; + flex-direction: row; + align-items: center; + height: 36px; + + .item-icon { + z-index: 10; + } + } + + .level { + border-radius: 3px 0 0 3px; + width: 25px; + white-space: nowrap; + display: inline-block; + + &:before { + content: "Lv"; + display: inline-block; + font-size: 12px; + transform: scale(.7); + transform-origin: right 55%; + margin-left: -3px; + } + } +} + +.cont { + font-size: 14px; + background: none; + + .cons, .level { + height: 22px; + line-height: 22px; + display: inline-block; + width: 19px; + padding: 0; + text-align: center; + vertical-align: middle; + font-size: 13px; + position: relative; + } + + .cons { + width: 16px; + text-shadow: 0 0 2px rgba(0, 0, 0, .5); + } + + .fetter { + width: 32px; + height: 32px; + } + + .item-name { + padding-left: 5px; + text-align: left; + text-shadow: 0 0 1px rgba(255, 255, 255, .8); + } + + .tr.thead { + background: rgba(0, 0, 0, .4); + font-weight: bold; + + & > div { + box-shadow: 0 0 1px 0 rgba(255, 255, 255, .7); + text-align: center; + } + + .td-talent { + + color: #d3bc8e; + } + } + + .tr { + color: #333; + white-space: nowrap; + + .td { + box-shadow: 0 0 1px 0 rgba(100, 100, 100, .3) inset; + } + + .star(@s, @color, @color2:#333) { + .td.star@{s} { + background: @color; + + .item-name { + color: @color2; + } + } + } + .star(1, rgba(200, 200, 200, 0.35)); + .star(2, rgba(168, 255, 133, 0.35)); + .star(3, rgba(137, 168, 255, 0.35)); + .star(4, rgba(195, 134, 255, 0.35), #720465); + .star(5, rgba(255, 212, 132, 0.35), #6f4b00); + + &.thead { + background: rgba(0, 0, 0, 0.5) !important; + + & > div { + color: #d3bc8e !important; + } + } + + &:nth-child(odd) { + background: rgba(255, 255, 255, 1); + } + + &:nth-child(even) { + background: rgba(240, 240, 240, 1); + } + + & > div { + text-align: center; + height: 36px; + vertical-align: middle; + line-height: 36px; + box-shadow: 0 0 1px 0 rgba(255, 255, 255, .7); + + * { + vertical-align: middle; + } + } + + .td-idx { + width: 30px; + } + + .td-name { + text-align: left; + width: 100px; + padding-left: 3px; + + .item-name { + width: 50px; + } + + .char-icon { + width: 30px; + height: 30px; + border-radius: 5px; + display: inline-block; + overflow: visible; + background: none; + + + .img { + width: 30px; + height: 30px; + position: relative; + top: 0; + left: 0; + border-radius: 0 0 6px 6px; + } + } + } + + .td-lv { + width: 35px; + } + + .td-fetter { + width: 40px; + text-align: center; + + + } + + .td-cons { + width: 40px; + text-align: center; + } + + .td-talent { + width: 35px; + box-shadow: 0 0 1px 0 rgba(150, 150, 150, .5); + } + + .td-weapon { + text-align: left; + padding-left: 3px; + + .level { + font-size: 12px; + transform: scale(.9); + text-align: left; + } + + .cons { + transform: scale(.8); + margin-right: -2px; + font-size: 12px; + padding: 0; + height: 16px; + line-height: 16px; + width: 14px; + } + + .weapon-icon { + border-radius: 0; + background: none; + } + + .item-name { + padding-left: 2px; + padding-right: 10px; + font-size: 12px; + } + } + + .weapon-icon { + width: 28px; + display: inline-block; + overflow: visible; + + .img { + width: 28px; + height: 36px; + margin: 0; + } + } + + .td-talent { + + } + + .talent-plus { + font-weight: bold; + color: #006cc7; + font-size: 15px; + text-shadow: 0px 0px 1px #fff; + } + + .lv(@lv, @c1, @c2:#333) { + .lv@{lv} { + background: @c1; + + &.talent-plus { + color: @c2; + } + } + } + .lv(1, rgba(60, 63, 65, .3)); + .lv(2, rgba(23, 184, 58, .5), #005800); + .lv(3, rgba(27, 128, 212, .5)); + .lv(4, rgba(146, 90, 255, .55), #720465); + + .lv5 { + background: url("../common/item/crown-o.png") center center no-repeat rgba(255, 36, 26, .55); + background-size: contain; + + &.talent-plus { + color: #b70000; + } + } + + + } + + /* + .star(1, rgba(171, 171, 171, .5)); + .star(2, rgba(208, 255, 190, .5)); + .star(3, rgba(190, 208, 255, .5)); + .star(4, rgba(223, 190, 255, .5)); + .star(5, rgba(255, 228, 180, .5)); + */ + + .td-artis { + width: 115px; + text-align: left; + + &.class- { + &ACE, &ACE² { + background: rgba(255, 228, 180, .5); + + .artis-mark-class { + background: #ff5722; + } + } + + &SSS, &SS { + background: rgba(223, 190, 255, .5); + + .artis-mark-class { + background: #531ba9cf; + } + } + + &S, &A { + background: rgba(190, 208, 255, .5); + + .artis-mark-class { + background: #3955b7; + } + } + + &B, &C, &D { + background: rgba(171, 171, 171, .5); + + .artis-mark-class { + background: #aaa; + } + } + } + } + + .avatar-artis { + margin-left: 5px; + text-align: left; + position: relative; + z-index: 10; + + .artis { + position: relative; + width: 30px; + height: 30px; + box-shadow: 0 0 1px 0 #ffe4b4; + display: inline-block; + + &.no-artis { + background: #bbb; + } + } + + .no-artis { + background: url(../common/item/artifact-icon.webp) center no-repeat; + background-size: auto 80%; + } + + &.artis2 { + .img { + position: absolute; + transform: scale(.7); + width: 92%; + height: 92%; + margin: 4%; + + &:first-child { + transform-origin: left top; + } + + &:last-child { + transform-origin: right bottom; + } + } + } + + + } + + .artis-mark-class { + width: 28px; + font-size: 12px; + border-radius: 5px; + display: inline-block; + text-align: center; + background: rgba(51, 51, 51, 0.68); + height: 20px; + line-height: 20px; + box-shadow: 0 0 1px 0 #ffe4b4; + position: relative; + z-index: 9; + margin: 0 -2px; + transform: scale(.7); + color: #fff; + + + } + + .artis-na { + padding-left: 12px; + white-space: nowrap; + transform: scale(.8); + transform-origin: left center; + color: #888; + font-size: 12px; + margin-right: -60px; + } +} + +.cont-notice { + background: rgba(0, 0, 0, .7); + font-size: 13px; + text-align: right; + padding: 8px 12px 8px 8px; + + strong { + color: #d3bc8e; + font-weight: normal; + } + + span { + margin-left: 5px; + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/character/rank-profile-list.css b/Yunzai/plugins/miao-plugin/resources/character/rank-profile-list.css new file mode 100644 index 0000000000000000000000000000000000000000..6a2a6a2920438f89d03ad622f38a61e52cd5b887 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/rank-profile-list.css @@ -0,0 +1,344 @@ +.font-YS { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.font-NZBZ { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +body { + width: 820px; +} +.container { + width: 820px; + padding: 0; + background-size: cover; + overflow: hidden; +} +.group-rank-icon { + width: 16px; + height: 16px; + background: url("imgs/mark-icon.png"); + background-size: auto 100%; + display: inline-block; + vertical-align: bottom; + margin: -1px 3px -1px 0; +} +.group-rank-icon.mark-icon { + background-position: 100% 0; +} +.char-list-item { + height: 60px; + background-size: auto 150%; + display: flex; + padding: 5px; + overflow: visible; +} +.char-list-item .line { + margin-left: 15px; + position: relative; +} +.char-list-item .line:before { + content: ""; + display: block; + width: 1px; + height: 40px; + background: rgba(255, 255, 255, 0.8); + background: linear-gradient(rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.1)); + position: absolute; + left: -15px; + top: 5px; +} +.char-idx { + width: 48px; +} +.char-idx .idx-icon { + display: inline-block; + width: 24px; + height: 24px; + margin: 13px 12px; + background: url('imgs/mark-icon.png'); + background-size: auto 100%; + text-align: center; + font-size: 12px; + line-height: 24px; + text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8); +} +.char-idx .idx-icon.mode-mark.idx-1, +.char-idx .idx-icon.mode-dmg.idx-1 { + width: 48px; + margin: 13px 0; + background-image: url('imgs/mark-icon2.png'); + color: rgba(0, 0, 0, 0); + text-shadow: none; +} +.char-idx .idx-icon.mode-mark, +.char-idx .idx-icon.mode-crit, +.char-idx .idx-icon.mode-valid { + background-position: 100% 0; +} +.char-idx .char-icon { + width: 36px; + height: 36px; + margin-top: 8px; + border-radius: 10px; + overflow: hidden; +} +.char-idx .char-icon .img { + border-radius: 0; +} +.char-icon { + width: 50px; + height: 50px; + border-radius: 50%; + border: 1px solid #fff; + box-shadow: 1px 1px 3px 0 #000; + overflow: visible; + margin: 0 5px 0 6px; +} +.char-icon .img { + background-size: auto 100%; + background-position: top center; + overflow: hidden; + border-radius: 50%; +} +.char-info .name { + margin-top: 4px; + height: 24px; + line-height: 24px; + font-size: 18px; + color: #d3bc8e; + font-weight: normal; + text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8); +} +.char-info .cons { + height: 16px; + line-height: 16px; + font-size: 12px; + width: 16px; + text-align: center; + padding: 0; + margin-right: -2px; + text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8); +} +.char-info .info { + height: 20px; + font-size: 12px; + line-height: 20px; +} +.char-name { + width: 100px; +} +.char-talent { + display: flex; + padding: 0 5px; + margin: -5px 0; +} +.char-talent .talent-item, +.char-talent .talent-icon { + width: 56px; + height: 56px; + margin: 0 -3px; +} +.char-talent .talent-item { + position: relative; +} +.char-talent .talent-icon { + width: 56px; + height: 56px; + position: relative; + margin: 7px -5px 13x; + border-radius: 50%; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; + z-index: 90; +} +.char-talent .talent-icon img, +.char-talent .talent-icon .talent-icon-img { + width: 46%; + height: 46%; + position: absolute; + top: 50%; + left: 50%; + margin: -22% 0 0 -23%; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} +.char-talent .talent-icon span { + background: #fff; + width: 22px; + height: 18px; + line-height: 18px; + font-size: 12px; + text-align: center; + border-radius: 5px; + position: absolute; + bottom: -2px; + left: 50%; + margin-left: -11px; + color: #000; + box-shadow: 0 0 5px 0 #000; +} +.char-talent .talent-icon.talent-plus span { + background: #2e353e; + color: #ffdfa0; + font-weight: bold; + box-shadow: 0 0 1px 0 #d3bc8e, 1px 1px 2px 0 rgba(0, 0, 0, 0.5); +} +.char-talent .talent-icon.talent-crown:after { + content: ""; + display: block; + width: 18px; + height: 18px; + background: url("../character/imgs/crown.png") no-repeat; + background-size: contain; + position: absolute; + left: 50%; + top: -2px; + margin-left: -9px; +} +.char-talent .talent-icon.talent-crown-sr:after { + content: ""; + display: block; + width: 22px; + height: 22px; + background: url("../character/imgs/crown-sr.webp") no-repeat; + background-size: contain; + position: absolute; + left: 50%; + top: -2px; + margin-left: -9px; +} +.char-item { + vertical-align: middle; + height: 50px; +} +.char-item .item { + position: relative; + width: 36px; + height: 36px; + margin: 7px 5px 7px 0; + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.7); + display: inline-block; + overflow: visible; + vertical-align: middle; +} +.char-weapon { + width: 125px; + display: flex; +} +.char-weapon .img { + margin: -10px -5px; + width: 46px; + height: 56px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; +} +.char-weapon .weapon-info { + padding-left: 5px; +} +.char-weapon .cons { + width: 28px; + font-size: 12px; + transform: scale(0.9); + transform-origin: 0 50%; +} +.char-weapon .name { + height: 20px; + line-height: 20px; +} +.char-weapon .name strong { + font-size: 13px; + font-weight: normal; +} +.char-artis { + display: flex; + width: 130px; +} +.char-artis { + margin-left: 5px; + text-align: left; + position: relative; + z-index: 10; +} +.char-artis.class-ACE .artis-mark-class, +.char-artis.class-ACE² .artis-mark-class { + background: #ff5722; +} +.char-artis.class-SSS .artis-mark-class, +.char-artis.class-SS .artis-mark-class { + background: #531ba9cf; +} +.char-artis.class-S .artis-mark-class, +.char-artis.class-A .artis-mark-class { + background: #3955b7; +} +.char-artis.class-B .artis-mark-class, +.char-artis.class-C .artis-mark-class, +.char-artis.class-D .artis-mark-class { + background: #aaa; +} +.char-artis .artis-mark-class { + width: 28px; + margin-right: -2px; + transform: scale(0.9); + transform-origin: 0 50%; +} +.char-artis .artis { + position: relative; + width: 36px; + height: 36px; + margin: 7px 5px 7px 0; + display: inline-block; +} +.char-artis .artis.no-artis { + background: #bbb; +} +.char-artis .no-artis { + background: url(../common/item/artifact-icon.webp) center no-repeat; + background-size: auto 88%; +} +.char-artis .char-info .name { + height: 20px; + line-height: 20px; +} +.char-artis .artis2 { + position: relative; +} +.char-artis .artis2 .img { + position: absolute; + transform: scale(0.7); + width: 100%; + height: 100%; + margin: 0; +} +.char-artis .artis2 .img:first-child { + transform-origin: left top; +} +.char-artis .artis2 .img:last-child { + transform-origin: right bottom; +} +.char-artis .artis-title { + font-size: 12px; + white-space: nowrap; +} +.char-artis .artis-mark { + height: 23px; +} +.char-dmg { + width: 120px; +} +.char-dmg .dmg-value { + height: 28px; + line-height: 28px; + font-size: 18px; + text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8); +} +.char-dmg .dmg-title { + height: 16px; + line-height: 16px; + margin-top: 6px; + font-size: 12px; + color: #aaa; +} diff --git a/Yunzai/plugins/miao-plugin/resources/character/rank-profile-list.html b/Yunzai/plugins/miao-plugin/resources/character/rank-profile-list.html new file mode 100644 index 0000000000000000000000000000000000000000..664e1b653fc511badba9840878afb7d1773a7e18 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/rank-profile-list.html @@ -0,0 +1,155 @@ +{{extend elemLayout}} + +{{block 'css'}} +<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/rank-profile-list.css"/> +{{/block}} + +{{set talentMap = game === 'sr' ? {a: '普攻', e: '战技', t:'天赋', q: '爆发'} : {a: '普攻', e: '战技', q: '爆发'} }} +{{set gameHash = game === 'gs' ? '#':'*' }} + +{{block 'main'}} +<div class="head-box"> + <div class="title">{{title}}</div> +</div> +<div id="profile-stat"> + + <div class="cont group-rank-tip {{groupRank?'has-rank':'no-rank'}}"> + <div class="cont-title"> + 群排名说明 + </div> + <div class="cont-body"> + <ul class="cont-msg"> + <li> + <i class="group-rank-icon dmg-icon"></i><strong>综合练度排名:</strong> + 以期望伤害(计算暴击率的平均伤害,不代表实际伤害值)为排序的群内排名 + </li> + <li> + <i class="group-rank-icon mark-icon"></i><strong>圣遗物评分排名:</strong> + 基于角色评分规则进行圣遗物评分。评分规则为线性规则,无法体现词条平衡等实际因素,评分仅供娱乐 + </li> + <li> + <i class="group-rank-icon mark-icon"></i><strong>双爆排名:</strong> + 以圣遗物的双爆(包括头)为排序的群内排名 + </li> + <li> + <i class="group-rank-icon mark-icon"></i><strong>加权有效词条排名:</strong> + 以圣遗物的加权有效词条(按照喵喵权重加权)为排序的群内排名 + </li> + <li> + <strong>排名范围:</strong> + 本群内 / 时间点:{{rankCfg.time}} 后 / 在群内主动通过 {{gameHash}}面板 命令查看过的面板数据 + </li> + {{if rankCfg?.limitTxt !== '无限制'}} + <li> + <strong>排名参与条件:</strong> {{rankCfg.limitTxt}} + </li> + <li> + <strong>排名人数:</strong> {{rankCfg.number}} (可由管理员在#喵喵设置 内设置,范围5~30) + </li> + {{/if}} + </ul> + </div> + </div> + + {{each list ds idx}} + <div class="cont char-list-item"> + {{if !ds.isMax}} + <div class="char-idx"> + <span class="idx-icon idx-{{idx+1}} mode-{{mode}}">{{idx+1}}</span> + </div> + {{/if}} + <div class="item-icon char-icon star{{ds.star}}"> + {{if ds.qqFace}} + <span class="img" style="background-image:url({{ds.qqFace}})"></span> + {{else}} + <span class="img" style="background-image:url({{_res_path}}{{ds.imgs?.face}})"></span> + {{/if}} + </div> + {{if ds.isMax}} + <div class="char-idx"> + <div class="item-icon char-icon star{{ds.star}}"> + <span class="img" style="background-image:url({{_res_path}}{{ds.imgs?.face}})"></span> + </div> + </div> + {{/if}} + <div class="char-info char-name"> + <div class="name"> + <span class="cons cons-{{ds.cons}}">{{ds.cons}}</span> + <strong>{{ds.sName}}</strong> + </div> + <div class="info"> {{ds.uid}}</div> + </div> + + <div class="char-talent elem-{{ds.elem}}"> + {{each talentMap tName key}} + {{set talent = ds.talent[key] || {} }} + <div class="talent-item"> + <div class="talent-icon + {{talent.level > talent.original ? `talent-plus`:``}} + {{talent.original >= 10 && game === 'gs' ? `talent-crown`:``}} + {{talent.original >= 10 && game === 'sr' ? `talent-crown-sr`:``}}"> + <div class="talent-icon-img" + style="background-image:url({{_res_path}}{{ds.imgs[key]}})"></div> + <span>{{talent.level}}</span> + </div> + </div> + {{/each}} + </div> + + <div class="char-item char-weapon line"> + {{set w = ds.weapon }} + <div class="item item-icon star{{w?.star}}"> + <div class="img" style="background-image:url({{_res_path}}{{w?.img}})"></div> + </div> + <div class="char-info weapon-info"> + <div class="name"> + <strong> {{w?.name?.length > 4 ? (w?.abbr||w?.name) : w?.name}}</strong> + </div> + <div class="info"> + {{if w}} + <span class="cons cons-{{w.affix+1}}">精{{w.affix}}</span> Lv.{{w.leve || w.level}} + {{/if}} + </div> + </div> + </div> + + + {{set mark = ds.artisMark || false }} + {{set marks = ds._formatmark || false }} + {{set aImgs = ds?.artisSet?.imgs || []}} + <div class="char-item char-artis class-{{mark?.markClass||'D'}}"> + <div + class="item artis item-icon avatar-artis {{aImgs.length>0?'star5':'no-artis'}} artis{{aImgs.length>2 ? 2 : aImgs.length}}"> + {{each aImgs img idx}} + {{if idx < 2}} + <div class="img" style="background-image:url({{_res_path}}{{img}})"></div> + {{/if}} + {{/each}} + {{if aImgs.length === 0}} + <span class="img no-artis"></span> + {{/if}} + + </div> + <div class="char-info artis-info"> + <div class="name artis-title"> + {{ds?.artisSet?.name}} + </div> + <div class="artis-mark"> + <span class="cons artis-mark-class class-{{mark?.markClass||'D'}}">{{mark.markClass}}</span> + {{marks}} + </div> + </div> + </div> + + <div class="char-dmg line"> + {{if ds.dmg}} + <div class="dmg-title">{{ds.dmg?.title}}</div> + <div class="dmg-value">{{ds.dmg?.avg}}</div> + {{else}} + {{/if}} + </div> + </div> + {{/each}} +</div> + +{{/block}} diff --git a/Yunzai/plugins/miao-plugin/resources/character/rank-profile-list.less b/Yunzai/plugins/miao-plugin/resources/character/rank-profile-list.less new file mode 100644 index 0000000000000000000000000000000000000000..86329ee3819caf7c35fa029eb38fd76ed4fad309 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/character/rank-profile-list.less @@ -0,0 +1,411 @@ +@import "../common/base.less"; + +body { + width: 820px; +} + +.container { + width: 820px; + padding: 0; + background-size: cover; + overflow: hidden; +} + +.group-rank-icon { + width: 16px; + height: 16px; + background: url("./imgs/mark-icon.png"); + background-size: auto 100%; + display: inline-block; + vertical-align: bottom; + margin: -1px 3px -1px 0; + + &.mark-icon { + background-position: 100% 0; + } +} + +.char-list-item { + height: 60px; + background-size: auto 150%; + display: flex; + padding: 5px; + overflow: visible; + + .line { + margin-left: 15px; + position: relative; + + &:before { + content: ""; + display: block; + width: 1px; + height: 40px; + background: rgba(255, 255, 255, .8); + background: linear-gradient(rgba(255, 255, 255, .1), rgba(255, 255, 255, .8), rgba(255, 255, 255, .8), rgba(255, 255, 255, .8), rgba(255, 255, 255, .1)); + position: absolute; + left: -15px; + top: 5px; + } + } +} + +.char-idx { + width: 48px; + + .idx-icon { + display: inline-block; + width: 24px; + height: 24px; + margin: 13px 12px; + background: url('./imgs/mark-icon.png'); + background-size: auto 100%; + text-align: center; + font-size: 12px; + line-height: 24px; + text-shadow: 1px 1px 1px rgba(0, 0, 0, .8); + + + &.mode-mark, &.mode-dmg { + &.idx-1 { + width: 48px; + margin: 13px 0; + background-image: url('./imgs/mark-icon2.png'); + color: rgba(0, 0, 0, 0); + text-shadow: none; + } + } + + &.mode-mark, &.mode-crit, &.mode-valid { + background-position: 100% 0; + } + } + + .char-icon { + width: 36px; + height: 36px; + margin-top: 8px; + border-radius: 10px; + overflow: hidden; + + .img { + border-radius: 0; + } + } + + +} + +.char-icon { + width: 50px; + height: 50px; + border-radius: 50%; + border: 1px solid #fff; + box-shadow: 1px 1px 3px 0 #000; + overflow: visible; + margin: 0 5px 0 6px; + + .img { + background-size: auto 100%; + background-position: top center; + overflow: hidden; + border-radius: 50%; + } +} + + +.char-info { + .name { + margin-top: 4px; + height: 24px; + line-height: 24px; + font-size: 18px; + color: #d3bc8e; + font-weight: normal; + text-shadow: 1px 1px 1px rgba(0, 0, 0, .8); + } + + .cons { + height: 16px; + line-height: 16px; + font-size: 12px; + width: 16px; + text-align: center; + padding: 0; + margin-right: -2px; + text-shadow: 1px 1px 1px rgba(0, 0, 0, .8); + } + + .info { + height: 20px; + font-size: 12px; + line-height: 20px; + } +} + +.char-name { + width: 100px; +} + +.char-talent { + display: flex; + padding: 0 5px; + margin: -5px 0; + + + .talent-item, .talent-icon { + width: 56px; + height: 56px; + margin: 0 -3px; + } + + .talent-item { + position: relative; + } + + .talent-icon { + width: 56px; + height: 56px; + position: relative; + margin: 7px -5px 13x; + border-radius: 50%; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; + z-index: 90; + + img, + .talent-icon-img { + width: 46%; + height: 46%; + position: absolute; + top: 50%; + left: 50%; + margin: -22% 0 0 -23%; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + } + + span { + background: #fff; + width: 22px; + height: 18px; + line-height: 18px; + font-size: 12px; + text-align: center; + border-radius: 5px; + position: absolute; + bottom: -2px; + left: 50%; + margin-left: -11px; + color: #000; + box-shadow: 0 0 5px 0 #000; + } + + &.talent-plus span { + background: #2e353e; + color: #ffdfa0; + font-weight: bold; + box-shadow: 0 0 1px 0 #d3bc8e, 1px 1px 2px 0 rgba(0, 0, 0, 0.5); + } + + &.talent-crown:after { + content: ""; + display: block; + width: 18px; + height: 18px; + background: url("../character/imgs/crown.png") no-repeat; + background-size: contain; + position: absolute; + left: 50%; + top: -2px; + margin-left: -9px; + } + + &.talent-crown-sr:after { + content: ""; + display: block; + width: 22px; + height: 22px; + background: url("../character/imgs/crown-sr.webp") no-repeat; + background-size: contain; + position: absolute; + left: 50%; + top: -2px; + margin-left: -9px; + } + } +} + +.char-item { + vertical-align: middle; + height: 50px; + + .item { + position: relative; + width: 36px; + height: 36px; + margin: 7px 5px 7px 0; + box-shadow: 0 0 0 1px rgba(255, 255, 255, .7); + display: inline-block; + overflow: visible; + vertical-align: middle; + } +} + +.char-weapon { + width: 125px; + display: flex; + + .img { + margin: -10px -5px; + width: 46px; + height: 56px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + } + + .weapon-info { + padding-left: 5px; + } + + .cons { + width: 28px; + font-size: 12px; + transform: scale(.9); + transform-origin: 0 50%; + } + + .name { + height: 20px; + line-height: 20px; + + strong { + font-size: 13px; + font-weight: normal; + } + } +} + + +.char-artis { + display: flex; + width: 130px; +} + +.char-artis { + margin-left: 5px; + text-align: left; + position: relative; + z-index: 10; + + &.class- { + &ACE, &ACE² { + .artis-mark-class { + background: #ff5722; + } + } + + &SSS, &SS { + .artis-mark-class { + background: #531ba9cf; + } + } + + &S, &A { + .artis-mark-class { + background: #3955b7; + } + } + + &B, &C, &D { + .artis-mark-class { + background: #aaa; + } + } + } + + .artis-mark-class { + width: 28px; + margin-right: -2px; + transform: scale(.9); + transform-origin: 0 50%; + + } + + .artis { + position: relative; + width: 36px; + height: 36px; + margin: 7px 5px 7px 0; + display: inline-block; + + &.no-artis { + background: #bbb; + } + } + + .no-artis { + background: url(../common/item/artifact-icon.webp) center no-repeat; + background-size: auto 88%; + } + + .char-info { + .name { + height: 20px; + line-height: 20px; + } + } + + + .artis2 { + position: relative; + + .img { + position: absolute; + transform: scale(.7); + width: 100%; + height: 100%; + margin: 0; + + &:first-child { + transform-origin: left top; + } + + &:last-child { + transform-origin: right bottom; + } + } + } + + .artis-title { + font-size: 12px; + white-space: nowrap; + } + + .artis-mark { + height: 23px; + } + +} + +.char-dmg { + width: 120px; + + .dmg-value { + height: 28px; + line-height: 28px; + font-size: 18px; + text-shadow: 1px 1px 1px rgba(0, 0, 0, .8); + } + + .dmg-title { + height: 16px; + line-height: 16px; + margin-top: 6px; + font-size: 12px; + color: #aaa + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/base.css b/Yunzai/plugins/miao-plugin/resources/common/base.css new file mode 100644 index 0000000000000000000000000000000000000000..991618559bde504c24bcc0ebf5ae43d4b6f69dfc --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/base.css @@ -0,0 +1,7 @@ +.font-ys { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.font-nzbz { + font-family: Number, "印品南征北战NZBZ体", NZBZ, PingFangSC-Medium, "PingFang SC", sans-serif; +} +/*# sourceMappingURL=base.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/base.less b/Yunzai/plugins/miao-plugin/resources/common/base.less new file mode 100644 index 0000000000000000000000000000000000000000..e065b8b7a8789fee992f2ad3c68ddfce4016d96b --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/base.less @@ -0,0 +1,7 @@ +.font-YS { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} + +.font-NZBZ { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/bg-anemo.jpg b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-anemo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..985a7d4702b0a06990b94ac2fd639cc2bde30dec Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-anemo.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/bg-cryo.jpg b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-cryo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cf4bd1d1b1dfe3e179e83ee68876211a53858bc8 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-cryo.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/bg-dendro.jpg b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-dendro.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b900d286b75c2ab95733a60d61df6445f3a78087 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-dendro.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/bg-electro.jpg b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-electro.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5dec7463c406d7576048439657ece9b396c2dd17 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-electro.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/bg-geo.jpg b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-geo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d68405f84992798104bfe6a062ba3b37df4972a7 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-geo.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/bg-hydro.jpg b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-hydro.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cc262f74817355764243109dc3b33af28539fdd0 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-hydro.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/bg-pyro.jpg b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-pyro.jpg new file mode 100644 index 0000000000000000000000000000000000000000..302d61293eacc3fdef8647baa5441d3decaaf594 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-pyro.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/bg-sr.jpg b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-sr.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ab7a1b427e4769f265231b5f45eae81ea1301228 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/bg-sr.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/talent-anemo.png b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-anemo.png new file mode 100644 index 0000000000000000000000000000000000000000..e9926f28d114c998523a6b5debc0ef5d3b9f4472 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-anemo.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/talent-cryo.png b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-cryo.png new file mode 100644 index 0000000000000000000000000000000000000000..2defb365bd4acbc581274f4266e15b09e91afa36 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-cryo.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/talent-dendro.png b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-dendro.png new file mode 100644 index 0000000000000000000000000000000000000000..2359d71a1ee3737805ddaa582ade9d1956b2e851 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-dendro.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/talent-electro.png b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-electro.png new file mode 100644 index 0000000000000000000000000000000000000000..8e3c59da8b54b8dcb103150b9cfc1ba1ce4c7ddf Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-electro.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/talent-geo.png b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-geo.png new file mode 100644 index 0000000000000000000000000000000000000000..87d7d0d307a8b98ebfe56d1329fce3ad1c96d1b6 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-geo.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/talent-hydro.png b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-hydro.png new file mode 100644 index 0000000000000000000000000000000000000000..94081178dadbc2ee3889a3b130166920a3af54e2 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-hydro.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/bg/talent-pyro.png b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-pyro.png new file mode 100644 index 0000000000000000000000000000000000000000..3349fde93f1ef8b9fc9cf22a1cbdadb11f1b3d49 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/bg/talent-pyro.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/common.css b/Yunzai/plugins/miao-plugin/resources/common/common.css new file mode 100644 index 0000000000000000000000000000000000000000..f21e5890be2b6622b9db263487f43ad3cd3f3279 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/common.css @@ -0,0 +1,458 @@ +@font-face { + font-family: 'Number'; + src: url("./font/tttgbnumber.woff") format('woff'), url("./font/tttgbnumber.ttf") format('truetype'); +} +@font-face { + font-family: 'NZBZ'; + src: url("./font/NZBZ.woff") format('woff'), url("./font/NZBZ.ttf") format('truetype'); +} +@font-face { + font-family: 'YS'; + src: url("./font/HYWH-65W.woff") format('woff'), url("./font/HYWH-65W.ttf") format('truetype'); +} +.font-YS { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.font-NZBZ { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +* { + margin: 0; + padding: 0; + box-sizing: border-box; + -webkit-user-select: none; + user-select: none; +} +body { + font-size: 18px; + color: #1e1f20; + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; + transform: scale(1.4); + transform-origin: 0 0; + width: 600px; +} +.container { + width: 600px; + padding: 20px 15px 10px 15px; + background-size: contain; +} +.head-box { + border-radius: 15px; + padding: 10px 20px; + position: relative; + color: #fff; + margin-top: 30px; +} +.head-box .title { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; + font-size: 36px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, 0.9); +} +.head-box .title .label { + display: inline-block; + margin-left: 10px; +} +.head-box .genshin_logo { + position: absolute; + top: 1px; + right: 15px; + width: 97px; +} +.head-box .label { + font-size: 16px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, 0.9); +} +.head-box .label span { + color: #d3bc8e; + padding: 0 2px; +} +.notice { + color: #888; + font-size: 12px; + text-align: right; + padding: 12px 5px 5px; +} +.notice-center { + color: #fff; + text-align: center; + margin-bottom: 10px; + text-shadow: 1px 1px 1px #333; +} +.copyright { + font-size: 14px; + text-align: center; + color: #fff; + position: relative; + padding-left: 10px; + text-shadow: 1px 1px 1px #000; + margin: 10px 0; +} +.copyright .version { + color: #d3bc8e; + display: inline-block; + padding: 0 3px; +} +/* */ +.cons { + display: inline-block; + vertical-align: middle; + padding: 0 5px; + border-radius: 4px; +} +.cons-0 { + background: #666; + color: #fff; +} +.cons-n0 { + background: #404949; + color: #fff; +} +.cons-1 { + background: #5cbac2; + color: #fff; +} +.cons-2 { + background: #339d61; + color: #fff; +} +.cons-3 { + background: #3e95b9; + color: #fff; +} +.cons-4 { + background: #3955b7; + color: #fff; +} +.cons-5 { + background: #531ba9cf; + color: #fff; +} +.cons-6 { + background: #ff5722; + color: #fff; +} +.cons2-0 { + border-radius: 4px; + background: #666; + color: #fff; +} +.cons2-1 { + border-radius: 4px; + background: #71b1b7; + color: #fff; +} +.cons2-2 { + border-radius: 4px; + background: #369961; + color: #fff; +} +.cons2-3 { + border-radius: 4px; + background: #4596b9; + color: #fff; +} +.cons2-4 { + border-radius: 4px; + background: #4560b9; + color: #fff; +} +.cons2-5 { + border-radius: 4px; + background: #531ba9cf; + color: #fff; +} +.cons2-6 { + border-radius: 4px; + background: #ff5722; + color: #fff; +} +/******** Fetter ********/ +.fetter { + width: 50px; + height: 50px; + display: inline-block; + background: url('./item/fetter.png'); + background-size: auto 100%; +} +.fetter.fetter1 { + background-position: 0% 0; +} +.fetter.fetter2 { + background-position: 11.11111111% 0; +} +.fetter.fetter3 { + background-position: 22.22222222% 0; +} +.fetter.fetter4 { + background-position: 33.33333333% 0; +} +.fetter.fetter5 { + background-position: 44.44444444% 0; +} +.fetter.fetter6 { + background-position: 55.55555556% 0; +} +.fetter.fetter7 { + background-position: 66.66666667% 0; +} +.fetter.fetter8 { + background-position: 77.77777778% 0; +} +.fetter.fetter9 { + background-position: 88.88888889% 0; +} +.fetter.fetter10 { + background-position: 100% 0; +} +/******** ELEM ********/ +.elem-hydro .talent-icon { + background-image: url("./bg/talent-hydro.png"); +} +.elem-hydro .elem-bg, +.hydro-bg { + background-image: url("./bg/bg-hydro.jpg"); +} +.elem-anemo .talent-icon { + background-image: url("./bg/talent-anemo.png"); +} +.elem-anemo .elem-bg, +.anemo-bg { + background-image: url("./bg/bg-anemo.jpg"); +} +.elem-cryo .talent-icon { + background-image: url("./bg/talent-cryo.png"); +} +.elem-cryo .elem-bg, +.cryo-bg { + background-image: url("./bg/bg-cryo.jpg"); +} +.elem-electro .talent-icon { + background-image: url("./bg/talent-electro.png"); +} +.elem-electro .elem-bg, +.electro-bg { + background-image: url("./bg/bg-electro.jpg"); +} +.elem-geo .talent-icon { + background-image: url("./bg/talent-geo.png"); +} +.elem-geo .elem-bg, +.geo-bg { + background-image: url("./bg/bg-geo.jpg"); +} +.elem-pyro .talent-icon { + background-image: url("./bg/talent-pyro.png"); +} +.elem-pyro .elem-bg, +.pyro-bg { + background-image: url("./bg/bg-pyro.jpg"); +} +.elem-dendro .talent-icon { + background-image: url("./bg/talent-dendro.png"); +} +.elem-dendro .elem-bg, +.dendro-bg { + background-image: url("./bg/bg-dendro.jpg"); +} +/* cont */ +.cont { + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 100%; + margin: 5px 15px 5px 10px; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8); + overflow: hidden; + color: #fff; + font-size: 16px; +} +.cont-title { + background: rgba(0, 0, 0, 0.4); + box-shadow: 0 0 1px 0 #fff; + color: #d3bc8e; + padding: 10px 20px; + text-align: left; + border-radius: 10px 10px 0 0; +} +.cont-title span { + font-size: 12px; + color: #aaa; + margin-left: 10px; + font-weight: normal; +} +.cont-title.border-less { + background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)); + box-shadow: none; + padding-bottom: 5px; +} +.cont-body { + padding: 10px 15px; + font-size: 12px; + background: rgba(0, 0, 0, 0.5); + box-shadow: 0 0 1px 0 #fff; + font-weight: normal; +} +.cont-footer { + padding: 10px 15px; + font-size: 12px; + background: rgba(0, 0, 0, 0.5); + font-weight: normal; +} +.cont > ul.cont-msg { + display: block; + padding: 5px 10px; + background: rgba(0, 0, 0, 0.5); +} +ul.cont-msg, +.cont-footer ul { + padding-left: 15px; +} +ul.cont-msg li, +.cont-footer ul li { + margin: 5px 0; + margin-left: 15px; +} +ul.cont-msg li strong, +.cont-footer ul li strong { + font-weight: normal; + margin: 0 2px; + color: #d3bc8e; +} +.cont-table { + display: table; + width: 100%; +} +.cont-table .tr { + display: table-row; +} +.cont-table .tr:nth-child(even) { + background: rgba(0, 0, 0, 0.4); +} +.cont-table .tr:nth-child(odd) { + background: rgba(50, 50, 50, 0.4); +} +.cont-table .tr > div, +.cont-table .tr > td { + display: table-cell; + box-shadow: 0 0 1px 0 #fff; +} +.cont-table .tr > div.value-full { + display: table; + width: 200%; +} +.cont-table .tr > div.value-none { + box-shadow: none; +} +.cont-table .thead { + text-align: center; +} +.cont-table .thead > div, +.cont-table .thead > td { + color: #d3bc8e; + background: rgba(0, 0, 0, 0.4); + line-height: 40px; + height: 40px; +} +.cont-table .title, +.cont-table .th { + color: #d3bc8e; + padding-right: 15px; + text-align: right; + background: rgba(0, 0, 0, 0.4); + min-width: 100px; + vertical-align: middle; +} +.logo { + font-size: 18px; + text-align: center; + color: #fff; + margin: 20px 0 10px 0; +} +/* item-icon */ +.item-icon { + width: 100%; + height: 100%; + border-radius: 4px; + position: relative; + overflow: hidden; +} +.item-icon .img { + width: 100%; + height: 100%; + display: block; + background-size: contain; + background-position: center; + background-repeat: no-repeat; +} +.item-icon.artis .img { + width: 84%; + height: 84%; + margin: 8%; +} +.item-icon.star1 { + background-image: url("../common/item/bg1.png"); +} +.item-icon.opacity-bg.star1 { + background-image: url("../common/item/bg1-o.png"); +} +.item-icon.star2 { + background-image: url("../common/item/bg2.png"); +} +.item-icon.opacity-bg.star2 { + background-image: url("../common/item/bg2-o.png"); +} +.item-icon.star3 { + background-image: url("../common/item/bg3.png"); +} +.item-icon.opacity-bg.star3 { + background-image: url("../common/item/bg3-o.png"); +} +.item-icon.star4 { + background-image: url("../common/item/bg4.png"); +} +.item-icon.opacity-bg.star4 { + background-image: url("../common/item/bg4-o.png"); +} +.item-icon.star5 { + background-image: url("../common/item/bg5.png"); +} +.item-icon.opacity-bg.star5 { + background-image: url("../common/item/bg5-o.png"); +} +.item-icon.star-w { + background: #fff; +} +.item-list { + display: flex; +} +.item-list .item-card { + width: 70px; + background: #e7e5d9; +} +.item-list .item-icon { + border-bottom-left-radius: 0; + border-bottom-right-radius: 12px; +} +.item-list .item-title { + color: #222; + font-size: 13px; + text-align: center; + padding: 2px; + white-space: nowrap; + overflow: hidden; +} +.item-list .item-icon { + height: initial; +} +.item-list .item-badge { + position: absolute; + display: block; + left: 0; + top: 0; + background: rgba(0, 0, 0, 0.6); + font-size: 12px; + color: #fff; + padding: 4px 5px 3px; + border-radius: 0 0 6px 0; +} +/*# sourceMappingURL=common.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/common.less b/Yunzai/plugins/miao-plugin/resources/common/common.less new file mode 100644 index 0000000000000000000000000000000000000000..84fca6b82febbac6516a40b22fb5e0ad9ba73434 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/common.less @@ -0,0 +1,394 @@ +.font(@name, @file) { + @font-face { + font-family: @name; + src: url("./font/@{file}.woff") format('woff'), url("./font/@{file}.ttf") format('truetype'); + } +} + +.font('Number', 'tttgbnumber'); +.font('NZBZ', 'NZBZ'); +.font('YS', 'HYWH-65W'); + +@import "base.less"; + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + -webkit-user-select: none; + user-select: none; +} + +body { + font-size: 18px; + color: #1e1f20; + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; + transform: scale(1.4); + transform-origin: 0 0; + width: 600px; +} + +.container { + width: 600px; + padding: 20px 15px 10px 15px; + background-size: contain; +} + + +.head-box { + border-radius: 15px; + padding: 10px 20px; + position: relative; + color: #fff; + margin-top: 30px; + + .title { + .font-NZBZ; + font-size: 36px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, .9); + + .label { + display: inline-block; + margin-left: 10px; + } + } + + .genshin_logo { + position: absolute; + top: 1px; + right: 15px; + width: 97px; + } + + .label { + font-size: 16px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, .9); + + span { + color: #d3bc8e; + padding: 0 2px; + } + } +} + + +.notice { + color: #888; + font-size: 12px; + text-align: right; + padding: 12px 5px 5px; +} + +.notice-center { + color: #fff; + text-align: center; + margin-bottom: 10px; + text-shadow: 1px 1px 1px #333; +} + +.copyright { + font-size: 14px; + text-align: center; + color: #fff; + position: relative; + padding-left: 10px; + text-shadow: 1px 1px 1px #000; + margin: 10px 0; + + .version { + color: #d3bc8e; + display: inline-block; + padding: 0 3px; + } +} + + +/* */ + +.cons { + display: inline-block; + vertical-align: middle; + padding: 0 5px; + border-radius: 4px; +} + + +.cons(@idx, @bg, @color:#fff) { + .cons-@{idx} { + background: @bg; + color: @color; + } +} + +.cons(0, #666); +.cons(n0, #404949); +.cons(1, #5cbac2); +.cons(2, #339d61); +.cons(3, #3e95b9); +.cons(4, #3955b7); +.cons(5, #531ba9cf); +.cons(6, #ff5722); + +.cons2(@idx, @bg, @color:#fff) { + .cons2-@{idx} { + border-radius: 4px; + background: @bg; + color: @color; + } +} + +.cons2(0, #666); +.cons2(1, #71b1b7); +.cons2(2, #369961); +.cons2(3, #4596b9); +.cons2(4, #4560b9); +.cons2(5, #531ba9cf); +.cons2(6, #ff5722); + +/******** Fetter ********/ + +.fetter { + width: 50px; + height: 50px; + display: inline-block; + background: url('./item/fetter.png'); + background-size: auto 100%; + @fetters: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; + each(@fetters, { + &.fetter@{value} { + background-position: (-100%/9)+(100%/9)*@value 0; + } + }) +} + +/******** ELEM ********/ + +@elems: hydro, anemo, cryo, electro, geo, pyro, dendro; + +each(@elems, { + .elem-@{value} .talent-icon { + background-image: url("./bg/talent-@{value}.png"); + } + + .elem-@{value} .elem-bg, + .@{value}-bg { + background-image: url("./bg/bg-@{value}.jpg"); + } +}) + + +/* cont */ + +.cont { + border-radius: 10px; + background: url("../common/cont/card-bg.png") top left repeat-x; + background-size: auto 100%; + // backdrop-filter: blur(3px); + margin: 5px 15px 5px 10px; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, .8); + overflow: hidden; + color: #fff; + font-size: 16px; +} + + +.cont-title { + background: rgba(0, 0, 0, .4); + box-shadow: 0 0 1px 0 #fff; + color: #d3bc8e; + padding: 10px 20px; + text-align: left; + border-radius: 10px 10px 0 0; + + span { + font-size: 12px; + color: #aaa; + margin-left: 10px; + font-weight: normal; + } + + &.border-less { + background: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); + box-shadow: none; + padding-bottom: 5px; + } +} + +.cont-body { + padding: 10px 15px; + font-size: 12px; + background: rgba(0, 0, 0, 0.5); + box-shadow: 0 0 1px 0 #fff; + font-weight: normal; +} + + +.cont-footer { + padding: 10px 15px; + font-size: 12px; + background: rgba(0, 0, 0, 0.5); + font-weight: normal; +} + +.cont > ul.cont-msg { + display: block; + padding: 5px 10px; + background: rgba(0, 0, 0, 0.5); +} + +ul.cont-msg, .cont-footer ul { + padding-left: 15px; + + li { + margin: 5px 0; + margin-left: 15px; + + strong { + font-weight: normal; + margin: 0 2px; + color: #d3bc8e; + } + } +} + +.cont-table { + display: table; + width: 100%; +} + +.cont-table .tr { + display: table-row; +} + +.cont-table .tr:nth-child(even) { + background: rgba(0, 0, 0, .4); +} + +.cont-table .tr:nth-child(odd) { + background: rgba(50, 50, 50, .4); +} + +.cont-table .tr > div, +.cont-table .tr > td { + display: table-cell; + box-shadow: 0 0 1px 0 #fff; +} + +.cont-table .tr > div.value-full { + display: table; + width: 200%; +} + +.cont-table .tr > div.value-none { + box-shadow: none; +} + +.cont-table .thead { + text-align: center; +} + +.cont-table .thead > div, +.cont-table .thead > td { + color: #d3bc8e; + background: rgba(0, 0, 0, .4); + line-height: 40px; + height: 40px; +} + + +.cont-table .title, +.cont-table .th { + color: #d3bc8e; + padding-right: 15px; + text-align: right; + background: rgba(0, 0, 0, .4); + min-width: 100px; + vertical-align: middle; +} + +.logo { + font-size: 18px; + text-align: center; + color: #fff; + margin: 20px 0 10px 0; +} + +/* item-icon */ +.item-icon { + width: 100%; + height: 100%; + border-radius: 4px; + position: relative; + overflow: hidden; + + .img { + width: 100%; + height: 100%; + display: block; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + } + + &.artis { + .img { + width: 84%; + height: 84%; + margin: 8%; + } + } + + @stars: 1, 2, 3, 4, 5; + each(@stars, { + &.star@{value} { + background-image: url("../common/item/bg@{value}.png"); + } + &.opacity-bg.star@{value} { + background-image: url("../common/item/bg@{value}-o.png"); + } + }) + + &.star-w { + background: #fff; + } +} + +.item-list { + display: flex; + + .item-card { + width: 70px; + background: #e7e5d9; + } + + .item-icon { + border-bottom-left-radius: 0; + border-bottom-right-radius: 12px; + } + + .item-title { + color: #222; + font-size: 13px; + text-align: center; + padding: 2px; + white-space: nowrap; + overflow: hidden; + } + + .item-icon { + height: initial; + } + + .item-badge { + position: absolute; + display: block; + left: 0; + top: 0; + background: rgba(0, 0, 0, 0.6); + font-size: 12px; + color: #fff; + padding: 4px 5px 3px; + border-radius: 0 0 6px 0; + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/cont/card-bg.png b/Yunzai/plugins/miao-plugin/resources/common/cont/card-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..036d416e692030f7c0a8b07d30c5da5c4598dece Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/cont/card-bg.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/cont/logo.png b/Yunzai/plugins/miao-plugin/resources/common/cont/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a8cb922f6a995d0c9bff6229bae057ffcf6b7168 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/cont/logo.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/face/what.jpg b/Yunzai/plugins/miao-plugin/resources/common/face/what.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e9a57f3c0aa36bf2fde1903eb92f40eb1b5c294b Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/face/what.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/font/HYWH-65W.ttf b/Yunzai/plugins/miao-plugin/resources/common/font/HYWH-65W.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b74b5b2421d39d1f1d68f3f54784946cddcd7681 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/font/HYWH-65W.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a93c5d18d5feb4c8f9c2c6697742c1c54b41a2c73554f7b668c52c6e788c34d0 +size 3293520 diff --git a/Yunzai/plugins/miao-plugin/resources/common/font/HYWH-65W.woff b/Yunzai/plugins/miao-plugin/resources/common/font/HYWH-65W.woff new file mode 100644 index 0000000000000000000000000000000000000000..4183b592b014c6f5e72d40a0310302fed81b671d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/font/HYWH-65W.woff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b7147f05859d906bd787cf809d9796621d81294401f5efd3199e043a410f5fd +size 2111996 diff --git a/Yunzai/plugins/miao-plugin/resources/common/font/NZBZ.ttf b/Yunzai/plugins/miao-plugin/resources/common/font/NZBZ.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bb9177e084615ff0da0eecc50b3ea6d17bc0e5ae --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/font/NZBZ.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26e130f37e0f59f8d0eaa7c96662de0545595bf04675c01e037e49de84de6bc3 +size 1502040 diff --git a/Yunzai/plugins/miao-plugin/resources/common/font/NZBZ.woff b/Yunzai/plugins/miao-plugin/resources/common/font/NZBZ.woff new file mode 100644 index 0000000000000000000000000000000000000000..edf38df55bf3bf57107e037b7360ed2a4afb5c97 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/font/NZBZ.woff differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/font/tttgbnumber.ttf b/Yunzai/plugins/miao-plugin/resources/common/font/tttgbnumber.ttf new file mode 100644 index 0000000000000000000000000000000000000000..89a392f7d123ec88caebb16e95ce0f35cfdf83bc Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/font/tttgbnumber.ttf differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/font/tttgbnumber.woff b/Yunzai/plugins/miao-plugin/resources/common/font/tttgbnumber.woff new file mode 100644 index 0000000000000000000000000000000000000000..b35ab09736cbdcc3f06848bab80b3c210fc56a57 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/font/tttgbnumber.woff differ diff --git "a/Yunzai/plugins/miao-plugin/resources/common/font/\345\215\216\346\226\207\344\270\255\345\256\213.TTF" "b/Yunzai/plugins/miao-plugin/resources/common/font/\345\215\216\346\226\207\344\270\255\345\256\213.TTF" new file mode 100644 index 0000000000000000000000000000000000000000..2ddb8b239f192cc4fe99fd3047f7423989d64f56 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/common/font/\345\215\216\346\226\207\344\270\255\345\256\213.TTF" differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/artifact-icon.webp b/Yunzai/plugins/miao-plugin/resources/common/item/artifact-icon.webp new file mode 100644 index 0000000000000000000000000000000000000000..4fb39d96ebbe33ae89bf5afe1f60525d8589b19e Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/artifact-icon.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/atk-bow.webp b/Yunzai/plugins/miao-plugin/resources/common/item/atk-bow.webp new file mode 100644 index 0000000000000000000000000000000000000000..551e4ae60807d384c17898378d025172d2879f9b Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/atk-bow.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/atk-catalyst.webp b/Yunzai/plugins/miao-plugin/resources/common/item/atk-catalyst.webp new file mode 100644 index 0000000000000000000000000000000000000000..493510c1b2b4c59fe88e65d8fac2dafef3b33c9d Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/atk-catalyst.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/atk-claymore.webp b/Yunzai/plugins/miao-plugin/resources/common/item/atk-claymore.webp new file mode 100644 index 0000000000000000000000000000000000000000..96b89f618edf435e467acbd618350a38ab5fcebc Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/atk-claymore.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/atk-polearm.webp b/Yunzai/plugins/miao-plugin/resources/common/item/atk-polearm.webp new file mode 100644 index 0000000000000000000000000000000000000000..b8c3c3b2023b7e4e126609f6a2d238dfc3c89f1d Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/atk-polearm.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/atk-sword.webp b/Yunzai/plugins/miao-plugin/resources/common/item/atk-sword.webp new file mode 100644 index 0000000000000000000000000000000000000000..f92293827fdfdc9845c98445e49d65f64ce3c8f1 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/atk-sword.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg1-o.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg1-o.png new file mode 100644 index 0000000000000000000000000000000000000000..937aca464560e7db718b46e2712615b151838a4f Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg1-o.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg1.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg1.png new file mode 100644 index 0000000000000000000000000000000000000000..5811598929e7719a2e3f1b67f2c70e2a81eed0e0 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg1.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg2-o.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg2-o.png new file mode 100644 index 0000000000000000000000000000000000000000..84b9d88c2868ac0d8096ddf832af7b5d74f24f36 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg2-o.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg2.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg2.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8e63c24d822441ccbfcd7729f9ba6dccc1c022 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg2.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg3-o.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg3-o.png new file mode 100644 index 0000000000000000000000000000000000000000..cd2191fbc62f6e1856c70c0b261421f2f9b55384 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg3-o.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg3.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg3.png new file mode 100644 index 0000000000000000000000000000000000000000..c7d45782119857e12d98dde3530a502949e1a9c6 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg3.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg4-o.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg4-o.png new file mode 100644 index 0000000000000000000000000000000000000000..eddbe8a35147f7461a56812d33d57f0ebb53c6d0 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg4-o.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg4.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg4.png new file mode 100644 index 0000000000000000000000000000000000000000..807954714cb3069fa7e5cee0c285baaed187fcac Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg4.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg5-o.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg5-o.png new file mode 100644 index 0000000000000000000000000000000000000000..23bf9fefd18abfc733fa75588b11f1142347e972 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg5-o.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg5.png b/Yunzai/plugins/miao-plugin/resources/common/item/bg5.png new file mode 100644 index 0000000000000000000000000000000000000000..2630db5bc3f80f014aef47a3299d65395220444c Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg5.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/bg5.psd b/Yunzai/plugins/miao-plugin/resources/common/item/bg5.psd new file mode 100644 index 0000000000000000000000000000000000000000..588f141d2c3ce397ceff85d3e8bcf92b7c13a073 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/bg5.psd differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/cons0.webp b/Yunzai/plugins/miao-plugin/resources/common/item/cons0.webp new file mode 100644 index 0000000000000000000000000000000000000000..31c2102f4816ef4f303701eb7d3726e84ec1970b Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/cons0.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/crown-o.png b/Yunzai/plugins/miao-plugin/resources/common/item/crown-o.png new file mode 100644 index 0000000000000000000000000000000000000000..177c58e440b67498235bfdbcfa402c68e8937293 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/crown-o.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/face.webp b/Yunzai/plugins/miao-plugin/resources/common/item/face.webp new file mode 100644 index 0000000000000000000000000000000000000000..32c532a6b493f5e7f8f567aad1c98c6ba25f128a Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/face.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/fetter.png b/Yunzai/plugins/miao-plugin/resources/common/item/fetter.png new file mode 100644 index 0000000000000000000000000000000000000000..1ccdcf0b53b8bbcdb099ac3c898f209a62004ca0 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/fetter.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/star-ltr.png b/Yunzai/plugins/miao-plugin/resources/common/item/star-ltr.png new file mode 100644 index 0000000000000000000000000000000000000000..f0895d62bb23debb44db64f5a4c8ea2cd6cf4c5c Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/star-ltr.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/item/star.png b/Yunzai/plugins/miao-plugin/resources/common/item/star.png new file mode 100644 index 0000000000000000000000000000000000000000..80d18882572a75775ddc4288d8d8c250ca66a851 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/item/star.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/layout/default.html b/Yunzai/plugins/miao-plugin/resources/common/layout/default.html new file mode 100644 index 0000000000000000000000000000000000000000..e25454ebd8793d6525a869bde2ae93e703778911 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/layout/default.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html lang="zh-cn"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width"> + <link rel="shortcut icon" href="#"/> + <link rel="preload" href="{{_miao_path}}common/font/HYWH-65W.woff" as="font" type="font/woff"> + <link rel="preload" href="{{_miao_path}}common/font/NZBZ.woff" as="font" type="font/woff"> + <link rel="preload" href="{{_miao_path}}common/font/tttgbnumber.woff" as="font" type="font/woff"> + <link rel="stylesheet" type="text/css" href="{{_miao_path}}common/common.css"/> + <title>miao-plugin + {{block 'css'}} + {{/block}} + + +
+ {{block 'main'}}{{/block}} + +
+ + \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/layout/elem.html b/Yunzai/plugins/miao-plugin/resources/common/layout/elem.html new file mode 100644 index 0000000000000000000000000000000000000000..7ad2f5dad8c9f088d8b97c722dcc35f99cdb2e88 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/layout/elem.html @@ -0,0 +1,22 @@ + + + + + + + + + + + miao-plugin + {{block 'css'}} + {{/block}} + +{{set elemCls = {火:'pyro',冰:'cryo',风:'anemo',雷:'electro',量子:'electro',虚数:'geo',物理:'hydro', }[element||elem] || element || elem || 'hydro' }} + +
+ {{block 'main'}}{{/block}} + +
+ + \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/theme/bg-01.jpg b/Yunzai/plugins/miao-plugin/resources/common/theme/bg-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6726b9ac303f94c8615e87a5f602e4c80a08a23e Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/theme/bg-01.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/theme/main-01.png b/Yunzai/plugins/miao-plugin/resources/common/theme/main-01.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e891885151ae9166125ac2a9a3a6e4846bf9a1 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/common/theme/main-01.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl.css b/Yunzai/plugins/miao-plugin/resources/common/tpl.css new file mode 100644 index 0000000000000000000000000000000000000000..045df5896464e477be41c1b388dd7ffb3dbe6604 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl.css @@ -0,0 +1,356 @@ +.item-card { + width: 66px; + margin: 4px; + position: relative; + border-radius: 5px; +} +.item-card .badge { + overflow: hidden; + border-radius: 50%; + display: block; + width: 26px; + height: 26px; + position: absolute; + right: -4px; + top: -4px; + background: #e9e5dc; + box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.8), 2px 2px 2px rgba(50, 50, 50, 0.5); + z-index: 10; +} +.item-card .badge img { + width: 140%; + left: -27%; + top: -45%; + overflow: hidden; + background-size: 100%; + background-repeat: no-repeat; + position: absolute; +} +.item-card .item-bg { + width: 100%; + padding: 100% 0 0; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + margin: 0; +} +.item-card .bg1 { + background-image: url("./item/bg1.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .bg-1 { + background-image: url("./item/bg1.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .bg2 { + background-image: url("./item/bg2.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .bg-2 { + background-image: url("./item/bg2.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .bg3 { + background-image: url("./item/bg3.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .bg-3 { + background-image: url("./item/bg3.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .bg4 { + background-image: url("./item/bg4.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .bg-4 { + background-image: url("./item/bg4.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .bg5 { + background-image: url("./item/bg5.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .bg-5 { + background-image: url("./item/bg5.png"); + border-radius: 5px 5px 15px 0; +} +.item-card .box { + border-radius: 5px; + overflow: hidden; + background: #e9e5dc; +} +.item-card .box .item-desc { + display: block; + font-weight: 500; + text-align: center; + bottom: 0; + background: #e9e5dc; + width: 100%; + font-size: 12px; + line-height: 16px; + white-space: nowrap; + overflow: hidden; + padding: 0 3px; +} +.item-card .box .item-desc:last-child { + padding-bottom: 2px; +} +.item-card .box .name { + overflow: hidden; + white-space: nowrap; + margin-top: 5px; + font-weight: 500; + text-align: center; + font-size: 14px; +} +.item-card .box .item-img { + width: 100%; + overflow: hidden; + background-size: 100%; + background-repeat: no-repeat; + position: absolute; + top: 0; +} +.item-card .item-life { + position: absolute; + top: 0; + left: 0; + z-index: 9; + font-size: 13px; + text-align: center; + color: #fff; + padding: 1px 4px; + border-radius: 3px; +} +.item-card .life1 { + background-color: #62a8ea; +} +.item-card .life2 { + background-color: #62a8ea; +} +.item-card .life3 { + background-color: #62a8ea; +} +.item-card .life4 { + background-color: #ff5722; +} +.item-card .life5 { + background-color: #ff5722; +} +.avatar-card { + margin: 4.5px; + box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.8); + font-size: 19.5px; + border-radius: 10.5px; +} +.avatar-card .card { + border-radius: 10.5px; + box-shadow: 0 2px 9px 0 rgba(132, 93, 90, 0.3); + position: relative; + overflow: hidden; + background: #e7e5d9; + width: 105px; +} +.avatar-card .avatar-face { + width: 105px; + height: 105px; + border-radius: 10.5px 10.5px 22.5px 0; + background-size: 100% 100%; + background-repeat: no-repeat; + position: relative; + box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.5); +} +.avatar-card .avatar-face .img { + background-position: center bottom; +} +.avatar-card .avatar-face .avatar-level { + position: absolute; + bottom: 0; + background: rgba(0, 0, 0, 0.6); + left: 0; + padding: 3px 7.5px 3px 4.5px; + border-radius: 0 6px 0 0; + color: #fff; + font-size: 16px; + text-shadow: 0 0 1px #000; +} +.avatar-card .avatar-face .avatar-level span { + font-size: 12px; +} +.avatar-card .cons { + border-radius: 0 0 0 7.5px; + padding: 3px 7.5px; + position: absolute; + right: 0; + top: 0; + font-size: 16px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, 0.8); +} +.avatar-card .cons.cons-0 { + display: none; +} +.avatar-card .avatar-talent { + height: 30px; + padding: 4.5px 7.5px 3px; + font-size: 18px; + width: 100%; + color: #222; + text-align: center; + display: flex; +} +.avatar-card .avatar-talent .talent-item { + width: 30px; + height: 24px; + line-height: 25.5px; + margin: 0 3px; + text-align: center; + display: block; + background-size: contain; + opacity: 0.8; + position: relative; + border-radius: 4.5px; + box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.5); +} +.avatar-card .avatar-talent .talent-item.talent-plus { + font-weight: bold; + color: #0284b9; +} +.avatar-card .avatar-talent .talent-item.talent-crown { + background: #d3bc8e; + color: #3a2702; + box-shadow: 0 0 3px 0 #000; +} +.avatar-card .avatar-talent.no-talent { + font-size: 18px; + color: rgba(100, 100, 100, 0.5); + text-align: center; + padding: 4.5px 0 3px; +} +.avatar-card .avatar-talent.no-talent span { + transform: scale(0.75); + white-space: nowrap; + margin-left: -1px; +} +.avatar-card.card-mini .wide, +.avatar-card.card-mini .line { + display: none; +} +.avatar-card .avatar-name { + padding: 12px 0 0 7.5px; + color: #333; +} +.avatar-card .avatar-name strong { + font-size: 30px; + display: block; + height: 34.5px; + line-height: 30px; +} +.avatar-card .avatar-name .cons { + position: initial; + border-radius: 4px; + padding: 1.5px 4.5px; + vertical-align: baseline; +} +.avatar-card.card-wide .mini { + display: none; +} +.avatar-card.card-wide .card { + width: 219px; + display: flex; +} +.avatar-card.card-wide .avatar-face { + height: 189px; + width: 114px; + border-radius: 10.5px 0 0 10.5px; +} +.avatar-card.card-wide .avatar-face .img { + background-size: 100% auto; + background-position: 0 10%; + height: 202.5px; + margin-top: -13.5px; +} +.avatar-card.card-wide .avatar-info { + width: 105px; +} +.avatar-card.card-wide .avatar-info strong { + display: block; + height: 45px; + line-height: 45px; +} +.avatar-card.card-wide .avatar-info .lv-info { + height: 30px; +} +.avatar-card.card-wide .line { + display: block; + height: 1px; + width: 100%; + margin: 5px 0; + background: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(100, 100, 100, 0.5) 20%, rgba(100, 100, 100, 0.5) 80%, rgba(0, 0, 0, 0)); + transform: scale(0.8); +} +.avatar-card.wide2 .card { + width: 447px; +} +.avatar-card.wide2 .avatar-face { + width: 219px; +} +.avatar-card.wide2 .avatar-face .img { + margin-top: -75px; + height: 264px; +} +.avatar-card.wide2 .avatar-info { + width: 219px; + padding-left: 7.5px; +} +.avatar-card .avatar-detail { + display: flex; + padding: 0 1.5px 3px 3px; +} +.avatar-card .avatar-detail .item { + width: 46.5px; + height: 46.5px; + border-radius: 4.5px; + margin: 1.5px; + overflow: hidden; +} +.avatar-card .avatar-weapon .icon { + border-radius: 4px; +} +.avatar-card .avatar-weapon .cons { + top: initial; + bottom: 0; + padding: 1.5px 4.5px; + border-radius: 4.5px 0 0 0; +} +.avatar-card .avatar-artis { + position: relative; +} +.avatar-card .avatar-artis.artis0 .item-icon { + background: url('./item/artifact-icon.webp') rgba(0, 0, 0, 0.3) center no-repeat; + background-size: auto 80%; +} +.avatar-card .avatar-artis .artis { + background: rgba(0, 0, 0, 0.4); +} +.avatar-card .avatar-artis.artis2 .img { + position: absolute; + transform: scale(0.7); + width: 92%; + height: 92%; + margin: 4%; +} +.avatar-card .avatar-artis.artis2 .img:first-child { + transform-origin: left top; +} +.avatar-card .avatar-artis.artis2 .img:last-child { + transform-origin: right bottom; +} +.item-list { + display: flex; + flex-wrap: wrap; + transform-origin: 0 0; +} +.item-list .item { + width: 65px; +} +/*# sourceMappingURL=tpl.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl.less b/Yunzai/plugins/miao-plugin/resources/common/tpl.less new file mode 100644 index 0000000000000000000000000000000000000000..ac47da837a21b6bd611e5f9a63125e6584b663b8 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl.less @@ -0,0 +1,12 @@ +@import url('tpl/item-card'); +@import url('tpl/avatar-card'); + +.item-list { + display: flex; + flex-wrap: wrap; + transform-origin: 0 0; +} + +.item-list .item { + width: 65px; +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl/artis-detail.css b/Yunzai/plugins/miao-plugin/resources/common/tpl/artis-detail.css new file mode 100644 index 0000000000000000000000000000000000000000..06ce5f29c6e3abb804211c8ed8d850d2a4137df4 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl/artis-detail.css @@ -0,0 +1,116 @@ +.arti-detail { + width: 185px; + border-radius: 10px; + background: url("../cont/card-bg.png") top left repeat-x; + background-size: auto 100%; + margin: 5px; + position: relative; + box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8); + height: 205px; + overflow: hidden; +} +.arti-detail .arti-icon { + width: 60px; + height: 60px; + position: absolute; + left: 2px; + top: 3px; +} +.arti-detail .arti-icon span { + position: absolute; + right: 2px; + bottom: 0; + margin-left: 5px; + background: rgba(0, 0, 0, 0.5); + border-radius: 5px; + height: 18px; + line-height: 18px; + padding: 0 3px; + color: #fff; + font-size: 12px; + display: block; +} +.arti-detail .arti-icon img { + width: 60px; + height: 60px; +} +.arti-detail .head { + color: #fff; + padding: 12px 0 8px 68px; +} +.arti-detail .head strong { + font-size: 15px; + display: block; + white-space: nowrap; + overflow: hidden; + font-font: YS; +} +.arti-detail .head span { + font-size: 14px; +} +.arti-detail .head .mark { + font-family: Number, YS; +} +.arti-detail ul.detail { + width: 100%; + padding: 0; + position: initial; + font-family: YS; +} +.arti-detail ul.detail li { + padding: 0 3px; + font-size: 14px; + position: initial; + width: 100%; + display: table; + line-height: 26px; + height: 26px; +} +.arti-detail ul.detail li.nouse span { + color: #888; +} +.arti-detail ul.detail li.arti-main { + font-size: 16px; + padding: 3px 3px; + font-weight: bold; +} +.arti-detail ul.detail li span { + position: initial; + display: table-cell; + color: #fff; + font-family: YS; +} +.arti-detail ul.detail li.title { + text-align: left; + padding-left: 10px; +} +.arti-detail ul.detail li.val { + text-align: right; + padding-right: 10px; + font-family: Number; +} +.arti-detail ul.detail:nth-child(even) { + background: rgba(0, 0, 0, 0.4); +} +.arti-detail ul.detail:nth-child(odd) { + background: rgba(50, 50, 50, 0.4); +} +.arti-detail .avatar { + position: absolute; + left: 32px; + top: 26px; + width: 38px; + height: 38px; + border-radius: 50%; + overflow: hidden; + z-index: 3; +} +.arti-detail .avatar img { + max-width: 100%; + max-height: 100%; +} +.arti-detail .arti-icon img { + width: 52px; + height: 52px; +} +/*# sourceMappingURL=artis-detail.less.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-card.css b/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-card.css new file mode 100644 index 0000000000000000000000000000000000000000..379e768e92c654c109305447441caa0b51780754 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-card.css @@ -0,0 +1,57 @@ +.avatar-card { + margin: 0 0 10px 10px; + border-radius: 7px; + box-shadow: 0 2px 6px 0 rgba(132, 93, 90, 0.3); + height: 88px; + position: relative; + overflow: hidden; + background: #e7e5d9; +} +.avatar-card img { + width: 70px; + height: 70px; + border-radius: 7px 7px 20px 0; +} +.avatar-card.star5 img { + background-image: url(../common/item/bg5.png); + width: 100%; + height: 70px; + /*filter: brightness(1.1);*/ + background-size: 100%; + background-repeat: no-repeat; +} +.avatar-card.star4 img { + width: 100%; + height: 70px; + background-image: url(../common/item/bg4.png); + background-size: 100%; + background-repeat: no-repeat; +} +.avatar-card .num { + position: absolute; + top: 0; + right: 0; + z-index: 9; + font-size: 18px; + text-align: center; + color: #fff; + padding: 1px 5px; + border-radius: 4px; + background: rgba(0, 0, 0, 0.5); +} +.avatar-card .name, +.avatar-card .num_name { + position: absolute; + top: 70px; + left: 0; + z-index: 9; + font-size: 12px; + text-align: center; + width: 100%; + height: 16px; + line-height: 18px; +} +.avatar-card .num_name { + font-size: 16px; +} +/*# sourceMappingURL=avatar-card.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-card.html b/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-card.html new file mode 100644 index 0000000000000000000000000000000000000000..a411e965062d8b6103e6c301cca644b0a9454cdd --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-card.html @@ -0,0 +1,56 @@ +{{set avatar = $data[0] || false }} +{{set {_res_path, cardType} = $data[1]}} +{{set weapon = avatar.weapon || {} }} +{{set talentMap = ['a','e','q'] }} + +
+
+ {{if avatar}} +
+
+
+ {{avatar.cons}} +
Lv{{avatar.level}} {{avatar.abbr}}
+
+
+ {{set talent = avatar.talent || {} }} + +
+ {{avatar.abbr}} +
+ {{avatar.cons}} + Lv{{avatar.level}} +
+
+
+ {{if talent.a && talent.a.level }} +
+ {{each talentMap k}} + {{set t = talent[k] || {} }} + {{t.level}} + {{/each}} +
+ {{else}} +
暂无天赋数据
+ {{/if}} +
+
+
+
+ + {{weapon.affix}} +
+
+
+
+ {{each avatar.artisSet?.imgs img}} +
+ {{/each}} +
+
+
+
+ {{/if}} +
+
+
\ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-card.less b/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-card.less new file mode 100644 index 0000000000000000000000000000000000000000..ae5bea3d296fd3469be8082ace6857c0afce0b82 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-card.less @@ -0,0 +1,265 @@ + +.avatar-card { + @px: 1.5px; + margin: @px*3; + box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.8); + font-size: @px*13; + border-radius: @px*7; + + + .card { + border-radius: @px*7; + box-shadow: 0 2px @px*6 0 rgb(132 93 90 / 30%); + position: relative; + overflow: hidden; + background: #e7e5d9; + width: @px*70; + } + + .avatar-face { + width: @px*70; + height: @px*70; + border-radius: @px*7 @px*7 @px*15 0; + background-size: 100% 100%; + background-repeat: no-repeat; + position: relative; + box-shadow: 0 0 2px 0 rgba(0, 0, 0, .5); + + .img { + background-position: center bottom; + } + + .avatar-level { + position: absolute; + bottom: 0; + background: rgba(0, 0, 0, 0.6); + left: 0; + padding: @px*2 @px*5 @px*2 @px*3; + border-radius: 0 @px*4 0 0; + color: #fff; + font-size: 16px; + text-shadow: 0 0 1px #000; + + span { + font-size: 12px; + } + } + + } + + .cons { + border-radius: 0 0 0 @px*5; + padding: @px*2 @px*5; + position: absolute; + right: 0; + top: 0; + font-size: 16px; + text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, .8); + + &.cons-0 { + display: none; + } + } + + .avatar-talent { + height: @px*20; + padding: @px*3 @px*5 @px*2; + font-size: @px*12; + width: 100%; + color: #222; + text-align: center; + display: flex; + + .talent-item { + width: @px*20; + height: @px*16; + line-height: @px*17; + margin: 0 @px*2; + text-align: center; + display: block; + background-size: contain; + opacity: 0.8; + position: relative; + border-radius: @px*3; + box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.5); + + &.talent-plus { + font-weight: bold; + color: #0284b9; + } + + &.talent-crown { + background: #d3bc8e; + color: #3a2702; + box-shadow: 0 0 @px*2 0 #000; + } + } + + &.no-talent { + font-size: @px*12; + color: rgba(100, 100, 100, .5); + text-align: center; + padding: @px*3 0 @px*2; + + span { + transform: scale(.75); + white-space: nowrap; + margin-left: -1px; + } + } + } + + &.card-mini { + .wide, .line { + display: none; + } + } + + .avatar-name { + padding: @px*8 0 0 @px*5; + color: #333; + + strong { + font-size: @px*20px; + display: block; + height: @px*23; + line-height: @px*20; + } + + .cons { + position: initial; + border-radius: 4px; + padding: @px @px*3; + vertical-align: baseline; + } + } + + &.card-wide { + .mini { + display: none; + } + + .card { + width: @px*146; + display: flex; + } + + .avatar-face { + height: @px * 126; + width: @px*76; + border-radius: @px*7 0 0 @px*7; + + .img { + background-size: 100% auto; + background-position: 0 10%; + height: @px*135; + margin-top: @px*-9; + } + } + + .avatar-info { + width: @px*70; + + strong { + display: block; + height: @px * 30; + line-height: @px*30; + } + + .lv-info { + height: @px*20; + } + } + + .line { + display: block; + height: 1px; + width: 100%; + margin: 5px 0; + background: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(100, 100, 100, .5) 20%, rgba(100, 100, 100, .5) 80%, rgba(0, 0, 0, 0)); + transform: scale(.8) + } + } + + &.wide2 { + .card { + width: @px*298; + } + + .avatar-face { + width: @px*146; + + .img { + margin-top: @px*-50; + height: @px*176; + } + } + + .avatar-info { + width: @px*146; + padding-left: @px*5; + } + + + } + + + .avatar-detail { + display: flex; + padding: 0 @px*1 @px*2 @px*2; + + .item { + width: @px*31; + height: @px*31; + border-radius: @px*3; + margin: @px*1; + overflow: hidden; + } + } + + .avatar-weapon { + .icon { + border-radius: 4px; + } + + .cons { + top: initial; + bottom: 0; + padding: @px @px*3; + border-radius: @px*3 0 0 0; + } + } + + .avatar-artis { + position: relative; + + &.artis0 { + .item-icon { + background: url('./item/artifact-icon.webp') rgba(0, 0, 0, .3) center no-repeat; + background-size: auto 80%; + } + } + + .artis { + background: rgba(0, 0, 0, 0.4) + } + + &.artis2 { + .img { + position: absolute; + transform: scale(.7); + width: 92%; + height: 92%; + margin: 4%; + + &:first-child { + transform-origin: left top; + } + + &:last-child { + transform-origin: right bottom; + } + } + } + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-profile.css b/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-profile.css new file mode 100644 index 0000000000000000000000000000000000000000..edf1125f42340539025295550fe4f2e348c2f902 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl/avatar-profile.css @@ -0,0 +1,204 @@ +.profile { + position: relative; + margin-bottom: 10px; +} +.profile:after { + content: ""; + display: block; + position: absolute; + left: 8px; + top: 115px; + bottom: 0; + right: 8px; + box-shadow: 0 0 2px 0 #fff; + border-radius: 5px; + z-index: 1; +} +.profile .main-pic { + width: 800px; + height: 500px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + margin-left: -260px; + position: relative; + z-index: 2; +} +.profile .detail { + position: absolute; + right: 20px; + top: 20px; + color: #fff; + z-index: 3; +} +.profile .char-name { + font-size: 50px; + font-family: NZBZ; + text-shadow: 0 0 3px #000, 2px 2px 4px rgba(0, 0, 0, 0.7); + text-align: right; +} +.profile .char-lv { + font-family: Number; + margin-bottom: 20px; + text-shadow: 0 0 3px #000, 2px 2px 4px rgba(0, 0, 0, 0.7); + text-align: right; +} +.profile .attr { + border-radius: 4px; + overflow: hidden; +} +.profile .detail li { + width: 300px; + font-size: 17px; + list-style: none; + padding: 0 100px 0 35px; + position: relative; + font-family: YS; + height: 32px; + line-height: 32px; + text-shadow: 0 0 1px rgba(0, 0, 0, 0.5); +} +.profile .attr li i { + display: inline-block; + height: 20px; + width: 20px; + background-image: url("../../character/icon.png"); + background-size: auto 20px; + position: absolute; + left: 10px; + top: 8px; + opacity: 0.9; + transform: scale(0.9); +} +.profile .i-hp { + background-position: -20px 0; +} +.profile .i-atk { + background-position: -40px 0; +} +.profile .i-def { + background-position: -60px 0; +} +.profile .i-mastery { + background-position: -80px 0; +} +.profile .i-cr { + background-position: -100px 0; +} +.profile .i-cd { + background-position: -140px 0; +} +.profile .i-re { + background-position: -120px 0; +} +.profile .i-dmg { + background-position: -160px 0; +} +.profile .detail li:nth-child(even) { + background: rgba(0, 0, 0, 0.4); +} +.profile .detail li:nth-child(odd) { + background: rgba(50, 50, 50, 0.4); +} +.profile .detail li strong { + display: inline-block; + position: absolute; + right: 85px; + text-align: right; + font-family: Number, sans-serif; + font-weight: normal; +} +.profile .detail li span { + position: absolute; + right: 0; + text-align: left; + width: 75px; + display: inline-block; + font-family: Number, sans-serif; + color: #90e800; + font-size: 15px; +} +.profile .talent-icon { + width: 100px; + height: 100px; + padding: 5px; + display: table; + border-radius: 50%; + position: relative; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; + z-index: 90; +} +.profile .talent-icon img, +.profile .talent-icon .profile .talent-icon-img { + width: 46%; + height: 46%; + position: absolute; + top: 50%; + left: 50%; + margin: -22% 0 0 -23%; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} +.profile .talent-icon span { + background: #fff; + width: 34px; + height: 26px; + line-height: 26px; + font-size: 17px; + text-align: center; + border-radius: 5px; + position: absolute; + bottom: 2px; + left: 50%; + margin-left: -15px; + color: #000; + box-shadow: 0 0 5px 0 #000; + font-family: Number; +} +.profile .talent-icon.talent-plus span { + background: #2e353e; + color: #ffdfa0; + font-weight: bold; + box-shadow: 0 0 1px 0 #d3bc8e, 1px 1px 2px 0 rgba(0, 0, 0, 0.5); +} +.profile .talent-icon.talent-crown:after { + content: ""; + display: block; + width: 28px; + height: 28px; + background: url("../character/imgs/crown.png") no-repeat; + background-size: contain; + position: absolute; + left: 50%; + top: 0; + margin-left: -14px; +} +.profile .char-talents { + display: flex; + width: 300px; + margin-bottom: 10px; +} +.profile .char-cons .talent-item, +.profile .char-talents .talent-item { + flex: 1; +} +.profile .char-cons { + display: flex; + width: 250px; + position: absolute; + bottom: 5px; + left: 20px; +} +.profile .char-cons .talent-icon { + width: 50px; + height: 50px; + margin: 0 -5px; +} +.profile .char-cons .talent-icon.off { + filter: grayscale(100%); + opacity: 0.4; +} +/*# sourceMappingURL=avatar-profile-source.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl/item-card.css b/Yunzai/plugins/miao-plugin/resources/common/tpl/item-card.css new file mode 100644 index 0000000000000000000000000000000000000000..d5bfc6194cc81c1f58a9e473a2b23c8b2d7e3f34 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl/item-card.css @@ -0,0 +1,113 @@ +.item-card { + width: 52px; + margin: 0px 0 5px 7px; + position: relative; +} +.item-card .badge { + overflow: hidden; + border-radius: 5px; + position: relative; + background: #e9e5dc; + box-shadow: 0 2px 6px 0 rgba(132, 93, 90, 0.3); +} +.item-card .badge img { + width: 100%; + overflow: hidden; + background-size: 100%; + background-repeat: no-repeat; + position: absolute; + top: 0; + /*filter: contrast(95%);*/ +} +.item-card .bg1 { + background-image: url("imgs/bg1.png"); + width: 100%; + height: 70px; + background-size: 100%; + background-repeat: no-repeat; +} +.item-card .bg2 { + background-image: url("imgs/bg2.png"); + width: 100%; + height: 70px; + background-size: 100%; + background-repeat: no-repeat; +} +.item-card .bg3 { + background-image: url("imgs/bg3.png"); + width: 100%; + height: 70px; + background-size: 100%; + background-repeat: no-repeat; +} +.item-card .bg4 { + background-image: url("imgs/bg4.png"); + width: 100%; + height: 70px; + background-size: 100%; + background-repeat: no-repeat; +} +.item-card .bg5 { + background-image: url("imgs/bg5.png"); + width: 100%; + height: 70px; + background-size: 100%; + background-repeat: no-repeat; +} +.item-card .box:after { + content: ""; + display: block; + position: absolute; + width: 15px; + right: 0; + bottom: 15px; +} +.item-card .box .desc { + font-weight: 500; + text-align: center; + position: absolute; + bottom: 0; + background: #e9e5dc; + width: 100%; + height: 16px; + font-size: 12px; + line-height: 16px; + font-family: Number; +} +.item-card .box .name { + overflow: hidden; + white-space: nowrap; + margin-top: 5px; + font-weight: 500; + text-align: center; + font-size: 14px; +} +.item-card .life { + position: absolute; + top: 0px; + left: 0px; + z-index: 9; + font-size: 13px; + text-align: center; + color: #fff; + border-radius: 2px; + padding: 1px 4px; + border-radius: 3px; + font-family: "tttgbnumber"; +} +.item-card .life1 { + background-color: #62a8ea; +} +.item-card .life2 { + background-color: #62a8ea; +} +.item-card .life3 { + background-color: #62a8ea; +} +.item-card .life4 { + background-color: #ff5722; +} +.item-card .life5 { + background-color: #ff5722; +} +/*# sourceMappingURL=item-card.less.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl/item-card.less b/Yunzai/plugins/miao-plugin/resources/common/tpl/item-card.less new file mode 100644 index 0000000000000000000000000000000000000000..74eb0b9a513a9b36157de6638a4c4b37ab36eea9 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl/item-card.less @@ -0,0 +1,120 @@ + +.item-card { + width: 66px; + margin: 4px; + position: relative; + border-radius: 5px; + + + .badge { + overflow: hidden; + border-radius: 50%; + display: block; + width: 26px; + height: 26px; + position: absolute; + right: -4px; + top: -4px; + background: #e9e5dc; + box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.8), 2px 2px 2px rgba(50, 50, 50, .5); + z-index: 10; + + + img { + width: 140%; + left: -27%; + top: -45%; + overflow: hidden; + background-size: 100%; + background-repeat: no-repeat; + position: absolute; + } + } + + .item-bg { + width: 100%; + padding: 100% 0 0; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + margin: 0; + } + + each(range(5), { + .bg@{value} { + background-image: url("./item/bg@{value}.png"); + border-radius: 5px 5px 15px 0; + } + .bg-@{value} { + background-image: url("./item/bg@{value}.png"); + border-radius: 5px 5px 15px 0; + } + }) + + .box { + border-radius: 5px; + overflow: hidden; + background: #e9e5dc; + + .item-desc { + display: block; + font-weight: 500; + text-align: center; + bottom: 0; + background: #e9e5dc; + width: 100%; + font-size: 12px; + line-height: 16px; + white-space: nowrap; + overflow: hidden; + padding: 0 3px; + + &:last-child { + padding-bottom: 2px; + } + } + + .name { + overflow: hidden; + white-space: nowrap; + margin-top: 5px; + font-weight: 500; + text-align: center; + font-size: 14px; + } + + .item-img { + width: 100%; + overflow: hidden; + background-size: 100%; + background-repeat: no-repeat; + position: absolute; + top: 0; + } + } + + .item-life { + position: absolute; + top: 0; + left: 0; + z-index: 9; + font-size: 13px; + text-align: center; + color: #fff; + padding: 1px 4px; + border-radius: 3px; + } + + .life(@idx, @color) { + .life@{idx} { + background-color: @color; + } + } + + .life(1, #62a8ea); + .life(2, #62a8ea); + .life(3, #62a8ea); + .life(4, #ff5722); + .life(5, #ff5722); +} + diff --git a/Yunzai/plugins/miao-plugin/resources/common/tpl/talent-detail.html b/Yunzai/plugins/miao-plugin/resources/common/tpl/talent-detail.html new file mode 100644 index 0000000000000000000000000000000000000000..4bb11bb2dae98209326a8be23ede5b11505e3d1d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/common/tpl/talent-detail.html @@ -0,0 +1,61 @@ +{{set ds = $data[0] || false }} +{{set {_res_path, icon,lvs,type,game,minLv,maxLv} = $data[1]}} + +
+
+ +
+
+
{{ds.name}}
+
+ {{each ds.desc d}} + {{ if d[0] === "<" || game==='sr' }} + {{@d}} + {{else if d!=""}} +

{{d}}

+ {{/if}} + {{/each}} +
+
+ + {{if ds.tables && ds.tables.length > 0}} +
+ {{each ds.tables tr}} + {{if tr.isSame}} +
+ {{tr.name}}{{if tr.unit}}({{tr.unit}}){{/if}} + {{tr.values[0]}} +
+ {{/if}} + {{/each}} +
+ + + + {{each lvs lv idx}} + {{if idx+1 >= minLv && idx+1 <= maxLv }} + + {{/if}} + {{/each}} + + {{each ds.tables tr}} + {{if !tr.isSame}} + + + + {{each tr.values v idx}} + {{if idx+1 >= minLv && idx+1 <= maxLv }} + + {{/if}} + {{/each}} + {{/if}} + + {{/each}} +
{{lv}}
+ {{tr.name}} + {{if tr.unit}} + ({{tr.unit}}) + {{/if}} + {{v}}
+ {{/if}} +
diff --git a/Yunzai/plugins/miao-plugin/resources/gacha/gacha-detail.css b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-detail.css new file mode 100644 index 0000000000000000000000000000000000000000..727449d50cb2e5ee4cac1bfacca2351681b53ab2 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-detail.css @@ -0,0 +1,143 @@ +.avatar-cont { + background: rgba(0, 0, 0, 0.1); +} +.user-banner .stat-li { + width: auto; + min-width: 75px; +} +.gacha-list .gacha-item { + height: 38px; + display: flex; + background: rgba(0, 0, 0, 0.4); +} +.gacha-list .gacha-item .date { + width: 97px; + line-height: 38px; + padding-left: 5px; + background: rgba(0, 0, 0, 0.8); + display: flex; +} +.gacha-list .gacha-item .date .dot { + width: 23.75px; + height: 43px; + background: url('./imgs/date-icon.webp') center -38px; + background-size: 100% auto; +} +.gacha-list .gacha-item .date .dot.first { + background-position: center 0; +} +.gacha-list .gacha-item .date .dot.last { + background-position: center -128px; +} +.gacha-list .gacha-item .date .txt { + text-align: center; +} +.gacha-list .gacha-item.no-date .date .dot { + background-position: center -71.25px; +} +.gacha-list .gacha-item.no-date .date .dot.last { + background-position: center -95px; +} +.gacha-list .gacha-item.no-date .date .txt { + opacity: 0; +} +.gacha-list .gacha-item.has-date { + margin-top: 5px; +} +.gacha-list .gacha-item .name { + width: 90px; + text-align: right; + line-height: 38px; + padding-right: 5px; +} +.gacha-list .gacha-item.wai .name { + color: #aaa; +} +.gacha-list .gacha-item.up .name { + /*background: rgba(0, 0, 0, .5);*/ + color: #ffd484; +} +.gacha-list .gacha-item.up .process, +.gacha-list .gacha-item.up .icon { + /* background-color: rgba(0, 0, 0, .5);*/ +} +.gacha-list .gacha-item.up .bar { + position: relative; +} +.gacha-list .gacha-item.up .bar:after { + display: block; + position: absolute; + right: 5px; + top: 3px; + width: 26px; + border-radius: 15px; + content: "UP"; + text-align: center; + height: 18px; + line-height: 18px; + font-size: 12px; + font-weight: bold; + background: #ffeb73; + color: #6f4b00; + box-shadow: 0 0 3px 0 #6f4b00; +} +.gacha-list .gacha-item.no-avatar .bar:after { + display: none; +} +.gacha-list .icon { + width: 32px; + height: 38px; +} +.gacha-list .icon .icon-bg { + width: 32px; + height: 32px; + margin: 3px 0; + border-radius: 5px; +} +.gacha-list .icon .icon-bg.star5 { + background: url('../common/item/bg5.png') 100% 100% no-repeat; +} +.gacha-list .icon span { + display: block; + width: 32px; + height: 32px; + background-size: auto 100%; + background-position: center; + background-repeat: no-repeat; +} +.gacha-list .process { + width: 490px; + padding-right: 15px; +} +.gacha-list .process .bar { + border-radius: 0 5px 5px 0; + height: 26px; + line-height: 26px; + margin: 6px 0; + padding-left: 5px; +} +.gacha-list .process .bar.gold { + background: #ffeb73; + color: #6f4b00; + min-width: 18px; +} +.gacha-list .process .bar.gold:after { + right: -30px; +} +.gacha-list .process .bar.good { + background: #168b2c; + min-width: 13%; + color: #fff; +} +.gacha-list .process .bar.normal { + background: #6939b7; + color: #fff; +} +.gacha-list .process .bar.bad { + background: #9d3333; + color: #fff; +} +.avatar-card .name { + text-align: center; +} +/*# sourceMappingURL=gacha-detail.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/gacha/gacha-detail.html b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-detail.html new file mode 100644 index 0000000000000000000000000000000000000000..9714d54c40ecd70effff2b516c49a797a0f7ce7c --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-detail.html @@ -0,0 +1,74 @@ +{{extend elemLayout}} + +{{block 'css'}} + + + + +{{/block}} + +{{ set statMap = { allNum:'抽卡总数', fiveNum:'金卡数',wai:'歪 T.T',fourNum:'紫卡数', fiveAvg:'平均出金', upYs:'UP原石' } }} + +{{block 'main'}} +
+
+
+ +
+ + {{if gacha && gacha.stat }} + {{set stat = gacha.stat }} +
+ {{each statMap title key}} + {{if stat[key] }} +
+ {{stat[key]}} + {{title}} +
+ {{/if}} + {{/each}} +
+ {{/if}} +
+ +
#抽卡帮助获取抽卡链接,#更新抽卡记录更新抽卡信息,#抽卡统计#角色统计可查看按卡池分析结果 +
+ +
+
+ {{each gacha.fiveLog ds idx}} + {{set item = gacha.items[ds.id]}} + {{set max = item.type === 'weapon'?80:90}} + {{set hasDate = (idx===0 || idx ===gacha.items.length-1 || (idx>0 && gacha.fiveLog[idx-1].date !== ds.date)) }} +
+
+
+
{{ds.date}}
+
+
{{item.abbr}}
+
+
+ +
+
+
+ {{set count = ds.count}} +
{{count}} +
+
+
+ {{/each}} +
+
+
+{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/gacha/gacha-detail.less b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-detail.less new file mode 100644 index 0000000000000000000000000000000000000000..4fb5e89731b411c034dec911b9b37194004815aa --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-detail.less @@ -0,0 +1,204 @@ +.avatar-cont { + background: rgba(0, 0, 0, .1); +} + +.user-banner { + .stat-li { + width: auto; + min-width: 75px; + } +} + + +.gacha-list { + @size: 32px; + @padding: 3px; + @height: @size + @padding * 2; + + .gacha-item { + height: @height; + display: flex; + background: rgba(0, 0, 0, .4); + + .date { + width: @size + 65px; + line-height: @height; + padding-left: 5px; + background: rgba(0, 0, 0, .8); + display: flex; + + .dot { + width: @height * 0.625; + height: @height + 5px; + background: url('./imgs/date-icon.webp') center -@height; + background-size: 100% auto; + + &.first { + background-position: center 0; + } + + &.last { + background-position: center @size * -4 + } + } + + .txt { + text-align: center; + } + } + + &.no-date { + .date { + .dot { + background-position: center @height * 0.625 * -3; + + &.last { + background-position: center @height * 0.625 * -4 + } + } + + .txt { + opacity: 0; + } + } + } + + &.has-date { + margin-top: 5px; + } + + .name { + width: 90px; + text-align: right; + line-height: @height; + padding-right: 5px; + } + + + &.wai { + .name { + color: #aaa; + } + + .name, .icon, .process { + + } + } + + &.up { + .name { + /*background: rgba(0, 0, 0, .5);*/ + color: rgb(255, 212, 132); + } + + .process, .icon { + /* background-color: rgba(0, 0, 0, .5);*/ + } + + .bar { + position: relative; + + &:after { + display: block; + position: absolute; + right: 5px; + top: 3px; + width: 26px; + border-radius: 15px; + content: "UP"; + text-align: center; + height: 18px; + line-height: 18px; + font-size: 12px; + font-weight: bold; + background: #ffeb73; + color: #6f4b00; + box-shadow: 0 0 3px 0 #6f4b00; + } + } + } + + &.no-avatar { + .bar:after { + display: none; + } + } + } + + + .icon { + width: @size; + height: @height; + + .icon-bg { + width: @size; + height: @size; + margin: @padding 0; + border-radius: 5px; + + &.star5 { + background: url('../common/item/bg5.png') 100% 100% no-repeat; + } + } + + + span { + display: block; + width: @size; + height: @size; + background-size: auto 100%; + background-position: center; + background-repeat: no-repeat; + } + } + + .process { + width: 490px; + padding-right: 15px; + @pd: 3px; + + .bar { + border-radius: 0 5px 5px 0; + height: @size - @pd * 2; + line-height: @size - @pd * 2; + margin: @padding + @pd 0; + padding-left: 5px; + } + + .bar { + &.gold { + background: #ffeb73; + color: #6f4b00; + min-width: 18px; + + &:after { + right: -30px; + } + } + + &.good { + background: #168b2c; + min-width: 13%; + color: #fff; + } + + &.normal { + background: #6939b7; + color: #fff; + } + + &.bad { + background: #9d3333; + color: #fff; + } + } + } + +} + + +.avatar-card { + .name { + text-align: center; + } +} diff --git a/Yunzai/plugins/miao-plugin/resources/gacha/gacha-stat.css b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-stat.css new file mode 100644 index 0000000000000000000000000000000000000000..bd9f207d9a8e87bfa91e05a324aef6a035e249eb --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-stat.css @@ -0,0 +1,139 @@ +.cont-title { + padding: 0; + background: rgba(0, 0, 0, 0.6); +} +.gacha-pool { + display: flex; + text-align: center; +} +.gacha-pool > div { + padding: 10px; + height: 56px; +} +.gacha-pool .line { + padding-right: 15px; + position: relative; +} +.gacha-pool .line:after { + content: ""; + display: block; + width: 1px; + height: 15px; + position: absolute; + top: 12px; + right: 7px; + background: #d3bc8e; +} +.gacha-pool .version { + text-align: center; + background: rgba(0, 0, 0, 0.8); + padding: 10px 0; + display: flex; + border-right: 1px solid rgba(255, 255, 255, 0.3); +} +.gacha-pool .version-name { + width: 105px; + line-height: 36px; + font-size: 20px; + font-weight: bold; + text-align: right; +} +.gacha-pool .version-name.all-version { + width: 130px; + text-align: center; +} +.gacha-pool .pool-name { + width: 125px; + text-align: left; +} +.gacha-pool .pool-name .name { + height: 22px; + line-height: 22px; +} +.gacha-pool .pool-name .time { + font-size: 12px; + line-height: 14px; + height: 14px; + color: #888; +} +.gacha-pool .stat-info { + display: flex; + padding: 10px 20px 0; +} +.gacha-pool .stat-info .info { + min-width: 60px; + padding: 0 20px 0 10px; +} +.gacha-pool .stat-info .info .num { + color: #ffde9d; + height: 25px; + line-height: 25px; + font-size: 22px; + text-shadow: 0 0 2px #000; +} +.gacha-pool .stat-info .info .title { + font-size: 12px; + line-height: 14px; + height: 14px; + color: #888; +} +.gacha-pool .stat-info .info:last-child:after { + display: none; +} +.gacha-stat { + display: flex; + flex-wrap: wrap; + align-items: flex-start; + background: rgba(0, 0, 0, 0.5); + padding: 5px 8px; +} +.gacha-stat .gacha-item { + text-align: center; +} +.gacha-stat .gacha-item .item-card { + width: 69px; + border-radius: 6px; + background: #fff; +} +.gacha-stat .item-icon { + border-radius: 6px 6px 10px 0; + box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.6); +} +.gacha-stat .item-life { + top: initial; + left: initial; + right: 0; + bottom: 0; + border-radius: 10px 0 0 0; + font-size: 16px; + padding: 0 6px; + min-width: 20px; + height: 22px; + line-height: 22px; + text-align: center; +} +.gacha-stat .item-name { + font-size: 14px; + line-height: 24px; + color: #000; +} +.gacha-stat .up-card { + box-shadow: 0 0 8px 0 #ffeb73, 0 0 0 1px #fff100; + background: #fff; +} +.gacha-stat .up-card .item-life { + color: #6f4b00; + background: #ffeb73; + box-shadow: 0 0 3px 0 #6f4b00; +} +.gacha-stat .up-card .item-name { + color: #6f4b00; +} +.gacha-stat .normal-card { + box-shadow: 0 0 0 1px #fff; +} +.gacha-stat .normal-card .item-life { + background: #333; + color: #fff; +} +/*# sourceMappingURL=gacha-stat.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/gacha/gacha-stat.html b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-stat.html new file mode 100644 index 0000000000000000000000000000000000000000..0abf4a51bcd6cd8534fad39e52e3020c3e88a37c --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-stat.html @@ -0,0 +1,99 @@ +{{extend elemLayout}} + +{{block 'css'}} + + + + + +{{/block}} + +{{ set statMap = { totalNum:'抽卡总数', star5Num:'金卡',c5UpNum:'UP角色',w5UpNum:'UP武器', star4Num:'紫卡',avgUpNum:'平均UP抽' } }} + +{{block 'main'}} +
+
+
+ +
+ + {{if gacha && gacha.totalStat }} + {{set stat = gacha.totalStat }} +
+ {{each statMap title key}} + {{if stat[key] }} +
+ {{stat[key]}} + {{title}} +
+ {{/if}} + {{/each}} +
+ {{/if}} +
+ +
+ #角色统计/#武器统计角色/武器池统计, + #常驻统计常驻池统计, + #全部统计全部抽卡统计, + #抽卡帮助 获取帮助 +
+ + {{each gacha.versionData vData}} + {{set stats = vData.stats}} +
+
+
+
+ {{if vData.from}} +
+ {{vData.version}} {{vData.half}} +
+
+
{{vData.name}}
+
{{vData.from}}~{{vData.to}}
+
+ {{else}} +
{{vData.version}}
+ {{/if}} +
+
+ {{set keyMap = {totalNum:'总抽卡',star5Num:'金卡',upNum:'UP金卡', c4Num:'紫角色', w4Num:'紫武器'} }} + {{each keyMap title key}} + {{if stats[key] > 0}} +
+
{{stats[key]}}
+
{{title}}
+
+ {{/if}} + {{/each}} +
+
+
+
+ {{each vData.items ds}} + {{set item = gacha.itemMap[ds.id]}} + {{if item.star === 4 || item.star === 5}} +
+
+
+
+
{{ds.num}}
+
+
{{item.name.length >4 ? item.abbr : item.name}}
+
+
+ {{/if}} + {{/each}} +
+
+ {{/each}} +
+{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/gacha/gacha-stat.less b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-stat.less new file mode 100644 index 0000000000000000000000000000000000000000..8669b3d0755a6123142114dfc772691a5bcd7122 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/gacha/gacha-stat.less @@ -0,0 +1,167 @@ +.cont-title { + padding: 0; + background: rgba(0, 0, 0, .6); +} + +.gacha-pool { + display: flex; + text-align: center; + + & > div { + padding: 10px; + height: 56px; + } + + .line { + padding-right: 15px; + position: relative; + + &:after { + content: ""; + display: block; + width: 1px; + height: 15px; + position: absolute; + top: 12px; + right: 7px; + background: #d3bc8e; + } + } + + .version { + text-align: center; + background: rgba(0, 0, 0, .8); + padding: 10px 0; + display: flex; + border-right: 1px solid rgba(255, 255, 255, .3); + } + + .version-name { + width: 105px; + line-height: 36px; + font-size: 20px; + font-weight: bold; + text-align: right; + + &.all-version { + width: 130px; + text-align: center; + } + } + + .pool-name { + width: 125px; + text-align: left; + + .name { + height: 22px; + line-height: 22px; + } + + .time { + font-size: 12px; + line-height: 14px; + height: 14px; + color: #888; + } + } + + .stat-info { + display: flex; + padding: 10px 20px 0; + + .info { + min-width: 60px; + padding: 0 20px 0 10px; + + .num { + color: #ffde9d; + height: 25px; + line-height: 25px; + font-size: 22px; + text-shadow: 0 0 2px #000; + } + + .title { + font-size: 12px; + line-height: 14px; + height: 14px; + color: #888; + } + + &:last-child:after { + display: none; + } + } + } +} + +.gacha-stat { + display: flex; + flex-wrap: wrap; + align-items: flex-start; + background: rgba(0, 0, 0, .5); + padding: 5px 8px; + + .gacha-item { + text-align: center; + + .item-card { + width: 69px; + border-radius: 6px; + background: #fff; + } + } + + .item-icon { + border-radius: 6px 6px 10px 0; + box-shadow: 0 0 3px 0 rgba(0, 0, 0, .6); + } + + .item-life { + top: initial; + left: initial; + right: 0; + bottom: 0; + border-radius: 10px 0 0 0; + font-size: 16px; + padding: 0 6px; + min-width: 20px; + height: 22px; + line-height: 22px; + text-align: center; + } + + .item-name { + font-size: 14px; + line-height: 24px; + color: #000; + } + + .up-card { + box-shadow: 0 0 8px 0 #ffeb73, 0 0 0 1px #fff100; + background: #fff; + + .item-life { + color: #6f4b00; + background: #ffeb73; + box-shadow: 0 0 3px 0 #6f4b00; + } + + .item-name { + color: #6f4b00; + } + } + + .normal-card { + box-shadow: 0 0 0 1px #fff; + + .item-life { + background: #333; + color: #fff; + } + } + + +} + diff --git a/Yunzai/plugins/miao-plugin/resources/gacha/imgs/date-icon.webp b/Yunzai/plugins/miao-plugin/resources/gacha/imgs/date-icon.webp new file mode 100644 index 0000000000000000000000000000000000000000..fa336ba63bb16fcfcf96418fe79294d68e34de67 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/gacha/imgs/date-icon.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/gacha/imgs/no-avatar.webp b/Yunzai/plugins/miao-plugin/resources/gacha/imgs/no-avatar.webp new file mode 100644 index 0000000000000000000000000000000000000000..61886b5f0de844ba591f644cf66434134b487a15 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/gacha/imgs/no-avatar.webp differ diff --git a/Yunzai/plugins/miao-plugin/resources/help/icon.png b/Yunzai/plugins/miao-plugin/resources/help/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f78cbdbd2f86cfc9a90d387b12138600eeed6fe4 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/help/icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50b1bae661fa7358b0bb3cbdf5086eaf26c02c5f793e86671063efe95a1a9846 +size 1129336 diff --git a/Yunzai/plugins/miao-plugin/resources/help/index.css b/Yunzai/plugins/miao-plugin/resources/help/index.css new file mode 100644 index 0000000000000000000000000000000000000000..b0db1f8f12bd4945a7d48885ca8e5dc00de36c29 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/help/index.css @@ -0,0 +1,83 @@ +body { + transform: scale(1); + width: 830px; + background: url("../common/theme/bg-01.jpg"); +} +.container { + background: url(../common/theme/main-01.png) top left no-repeat; + background-size: 100% auto; + width: 830px; +} +.head-box { + margin: 60px 0 0 0; + padding-bottom: 0; +} +.head-box .title { + font-size: 50px; +} +.cont-box { + border-radius: 15px; + margin-top: 20px; + margin-bottom: 20px; + overflow: hidden; + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.15); + position: relative; +} +.help-group { + font-size: 18px; + font-weight: bold; + padding: 15px 15px 10px 20px; +} +.help-table { + text-align: center; + border-collapse: collapse; + margin: 0; + border-radius: 0 0 10px 10px; + display: table; + overflow: hidden; + width: 100%; + color: #fff; +} +.help-table .tr { + display: table-row; +} +.help-table .td, +.help-table .th { + font-size: 14px; + display: table-cell; + box-shadow: 0 0 1px 0 #888 inset; + padding: 12px 0 12px 50px; + line-height: 24px; + position: relative; + text-align: left; +} +.help-table .tr:last-child .td { + padding-bottom: 12px; +} +.help-table .th { + background: rgba(34, 41, 51, 0.5); +} +.help-icon { + width: 40px; + height: 40px; + display: block; + position: absolute; + background: url("icon.png") 0 0 no-repeat; + background-size: 500px auto; + border-radius: 5px; + left: 6px; + top: 12px; + transform: scale(0.85); +} +.help-title { + display: block; + color: #d3bc8e; + font-size: 16px; + line-height: 24px; +} +.help-desc { + display: block; + font-size: 13px; + line-height: 18px; +} +/*# sourceMappingURL=index.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/help/index.html b/Yunzai/plugins/miao-plugin/resources/help/index.html new file mode 100644 index 0000000000000000000000000000000000000000..cac6d03f219d3ed47e71a9d0e9a5502254ba66a9 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/help/index.html @@ -0,0 +1,44 @@ +{{extend defaultLayout}} + +{{block 'css'}} + +<% style = style.replace(/{{_res_path}}/g, _res_path) %> +{{@style}} +{{/block}} + +{{block 'main'}} + +
+
+
{{helpCfg.title||"使用帮助"}}
+
{{helpCfg.subTitle || "Yunzai-Bot & Miao-Plugin"}}
+
+
+ +{{each helpGroup group}} +{{set len = group?.list?.length || 0 }} +
+
{{group.group}}
+ {{if len > 0}} +
+
+ {{each group.list help idx}} +
+ + {{help.title}} + {{help.desc}} +
+ {{if idx%colCount === colCount-1 && idx>0 && idx< len-1}} +
+
+ {{/if}} + {{/each}} + <% for(let i=(len-1)%colCount; i< colCount-1 ; i++){ %> +
+ <% } %> +
+
+ {{/if}} +
+{{/each}} +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/help/index.less b/Yunzai/plugins/miao-plugin/resources/help/index.less new file mode 100644 index 0000000000000000000000000000000000000000..3ea3dad8a06ee5c94f963bd6c0d441d74ebc5ffc --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/help/index.less @@ -0,0 +1,96 @@ +body { + transform: scale(1); + width: 830px; + background: url("../common/theme/bg-01.jpg"); +} + +.container { + background: url(../common/theme/main-01.png) top left no-repeat; + background-size: 100% auto; + width: 830px; +} + +.head-box { + margin: 60px 0 0 0; + padding-bottom: 0; +} + +.head-box .title { + font-size: 50px; +} + +.cont-box { + border-radius: 15px; + margin-top: 20px; + margin-bottom: 20px; + overflow: hidden; + box-shadow: 0 5px 10px 0 rgb(0 0 0 / 15%); + position: relative; +} + +.help-group { + font-size: 18px; + font-weight: bold; + padding: 15px 15px 10px 20px; +} + +.help-table { + text-align: center; + border-collapse: collapse; + margin: 0; + border-radius: 0 0 10px 10px; + display: table; + overflow: hidden; + width: 100%; + color: #fff; +} + +.help-table .tr { + display: table-row; +} + +.help-table .td, +.help-table .th { + font-size: 14px; + display: table-cell; + box-shadow: 0 0 1px 0 #888 inset; + padding: 12px 0 12px 50px; + line-height: 24px; + position: relative; + text-align: left; +} + +.help-table .tr:last-child .td { + padding-bottom: 12px; +} + +.help-table .th { + background: rgba(34, 41, 51, .5) +} + +.help-icon { + width: 40px; + height: 40px; + display: block; + position: absolute; + background: url("icon.png") 0 0 no-repeat; + background-size: 500px auto; + border-radius: 5px; + left: 6px; + top: 12px; + transform: scale(0.85); +} + +.help-title { + display: block; + color: #d3bc8e; + font-size: 16px; + line-height: 24px; +} + +.help-desc { + display: block; + font-size: 13px; + line-height: 18px; +} + diff --git a/Yunzai/plugins/miao-plugin/resources/help/theme/default/bg.jpg b/Yunzai/plugins/miao-plugin/resources/help/theme/default/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6726b9ac303f94c8615e87a5f602e4c80a08a23e Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/help/theme/default/bg.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/help/theme/default/config.js b/Yunzai/plugins/miao-plugin/resources/help/theme/default/config.js new file mode 100644 index 0000000000000000000000000000000000000000..fe2ba525fcef6fd3f7fdcb03379b8b0a3318b07d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/help/theme/default/config.js @@ -0,0 +1,24 @@ +export const style = { + // 主文字颜色 + fontColor: '#ceb78b', + // 主文字阴影: 横向距离 垂直距离 阴影大小 阴影颜色 + // fontShadow: '0px 0px 1px rgba(6, 21, 31, .9)', + fontShadow: 'none', + // 描述文字颜色 + descColor: '#eee', + + /* 面板整体底色,会叠加在标题栏及帮助行之下,方便整体帮助有一个基础底色 + * 若无需此项可将rgba最后一位置为0即为完全透明 + * 注意若综合透明度较低,或颜色与主文字颜色过近或太透明可能导致阅读困难 */ + contBgColor: 'rgba(6, 21, 31, .5)', + + // 面板底图毛玻璃效果,数字越大越模糊,0-10 ,可为小数 + contBgBlur: 3, + + // 板块标题栏底色 + headerBgColor: 'rgba(6, 21, 31, .4)', + // 帮助奇数行底色 + rowBgColor1: 'rgba(6, 21, 31, .2)', + // 帮助偶数行底色 + rowBgColor2: 'rgba(6, 21, 31, .35)' +} diff --git a/Yunzai/plugins/miao-plugin/resources/help/theme/default/main.png b/Yunzai/plugins/miao-plugin/resources/help/theme/default/main.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e891885151ae9166125ac2a9a3a6e4846bf9a1 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/help/theme/default/main.png differ diff --git "a/Yunzai/plugins/miao-plugin/resources/help/theme/\347\233\256\345\275\225\350\257\264\346\230\216.txt" "b/Yunzai/plugins/miao-plugin/resources/help/theme/\347\233\256\345\275\225\350\257\264\346\230\216.txt" new file mode 100644 index 0000000000000000000000000000000000000000..a65c3df1b2f2eb1dec1a9a04aecd9af5b4156720 --- /dev/null +++ "b/Yunzai/plugins/miao-plugin/resources/help/theme/\347\233\256\345\275\225\350\257\264\346\230\216.txt" @@ -0,0 +1,24 @@ +【default皮肤】 +default为默认皮肤,不建议改动,防止后续更新冲突 +如不想使用default可创建或下载其他皮肤,存在其他皮肤时会默认忽略default皮肤 + +【增加自定义皮肤】 +可创建或下载皮肤包,放置在当前目录(theme)下,皮肤名称为皮肤文件夹名字 + +皮肤包内应包含的文件: +main.png:主图,高度自适应 +bg.jpg:背景图,如果main.png图片不够高或存在透明的话则会使用bg.jpg作为背景进行填充 +config.js:当前皮肤元素的颜色、透明度等配置,可选。如无此文件会使用默认配置,如需自定义,可参考default/config.js + + +【皮肤选择】 +默认为随机皮肤,如需指定固定某个皮肤可到config/help.js中,设置theme的字段选项 + +在有其他皮肤时,会默认忽略自带的default皮肤 +如希望default皮肤也出现在随机中,可修改config/help.js,将themeExclude中配置的default项删掉 +如需临时增加其他皮肤屏蔽,也可以追加至themeExclude中(当然也可以直接删掉对应皮肤) + +新增皮肤或修改配置后无需重启,可直接生效 + + + diff --git a/Yunzai/plugins/miao-plugin/resources/help/version-info.css b/Yunzai/plugins/miao-plugin/resources/help/version-info.css new file mode 100644 index 0000000000000000000000000000000000000000..1ae34aaf5fce596dee49433256e8ce65f0275df5 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/help/version-info.css @@ -0,0 +1,83 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} +body { + font-size: 18px; + color: #1e1f20; + transform: scale(1.3); + transform-origin: 0 0; + width: 600px; +} +.container { + width: 600px; + padding: 10px 0 10px 0; + background-size: 100% 100%; +} +.log-cont { + background-size: cover; + margin: 5px 15px 5px 10px; + border-radius: 10px; +} +.log-cont .cont { + margin: 0; +} +.log-cont .cont-title { + font-size: 16px; + padding: 10px 20px 6px; +} +.log-cont .cont-title.current-version { + font-size: 20px; +} +.log-cont ul { + font-size: 14px; + padding-left: 20px; +} +.log-cont ul li { + margin: 3px 0; +} +.log-cont ul.sub-log-ul li { + margin: 1px 0; +} +.log-cont .cmd { + color: #d3bc8e; + display: inline-block; + border-radius: 3px; + background: rgba(0, 0, 0, 0.5); + padding: 0 3px; + margin: 1px 2px; +} +.log-cont .strong { + color: #24d5cd; +} +.log-cont .new { + display: inline-block; + width: 18px; + margin: 0 -3px 0 1px; +} +.log-cont .new:before { + content: "NEW"; + display: inline-block; + transform: scale(0.6); + transform-origin: 0 0; + color: #d3bc8e; + white-space: nowrap; +} +.dev-cont { + background: none; +} +.dev-cont .cont-title { + background: rgba(0, 0, 0, 0.7); +} +.dev-cont .cont-body { + background: rgba(0, 0, 0, 0.5); +} +.dev-cont .cont-body.dev-info { + background: rgba(0, 0, 0, 0.2); +} +.dev-cont .strong { + font-size: 15px; +} +/*# sourceMappingURL=version-info.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/help/version-info.html b/Yunzai/plugins/miao-plugin/resources/help/version-info.html new file mode 100644 index 0000000000000000000000000000000000000000..0ea7bf419953909a2834c750f816f64f60b76585 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/help/version-info.html @@ -0,0 +1,47 @@ +{{extend elemLayout}} + +{{block 'css'}} + +{{/block}} + +{{block 'main'}} +{{each changelogs ds idx}} +
+ {{set v = ds.version }} + {{set isDev = v[v.length-1] === 'v'}} +
+ {{if idx === 0 }} +
当前版本 {{v}}
+ {{if v[v.length-1] === 'v'}} +
+
【Dev测试分支,开发中】
+
    +
  • 如需体验可切换至{{name||'miao-plugin'}}仓库dev分支
  • +
  • Dev功能可能不稳定,建议具备一定排错能力的勇士体验
  • +
+
+ {{else}} + {{/if}} + {{else}} +
{{name || '喵喵'}}版本 {{v}}
+ {{/if}} +
+
    + {{each ds.logs log}} +
  • +

    {{@log.title}}

    + {{if log.logs.length > 0}} +
      + {{each log.logs ls}} +
    • {{@ls}}
    • + {{/each}} +
    + {{/if}} +
  • + {{/each}} +
+
+
+
+{{/each}} +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/help/version-info.less b/Yunzai/plugins/miao-plugin/resources/help/version-info.less new file mode 100644 index 0000000000000000000000000000000000000000..98483650f553dbee40909febcbe34bd956c0bc03 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/help/version-info.less @@ -0,0 +1,110 @@ +.linear-bg(@color) { + background-image: linear-gradient(to right, @color, @color 80%, fade(@color, 0) 100%); +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} + +body { + font-size: 18px; + color: #1e1f20; + transform: scale(1.3); + transform-origin: 0 0; + width: 600px; +} + +.container { + width: 600px; + padding: 10px 0 10px 0; + background-size: 100% 100%; + +} + +.log-cont { + background-size: cover; + margin: 5px 15px 5px 10px; + border-radius: 10px; + + .cont { + margin: 0; + } + + .cont-title { + font-size: 16px; + padding: 10px 20px 6px; + + &.current-version { + font-size: 20px; + } + } + + .cont-body { + } + + ul { + font-size: 14px; + padding-left: 20px; + + li { + margin: 3px 0; + } + + &.sub-log-ul { + li { + margin: 1px 0; + } + } + } + + .cmd { + color: #d3bc8e; + display: inline-block; + border-radius: 3px; + background: rgba(0, 0, 0, 0.5); + padding: 0 3px; + margin: 1px 2px; + } + + .strong { + color: #24d5cd; + } + + .new { + display: inline-block; + width: 18px; + margin: 0 -3px 0 1px; + } + + .new:before { + content: "NEW"; + display: inline-block; + transform: scale(0.6); + transform-origin: 0 0; + color: #d3bc8e; + white-space: nowrap; + } +} + +.dev-cont { + background: none; + + .cont-title { + background: rgba(0, 0, 0, .7); + } + + .cont-body { + background: rgba(0, 0, 0, .5); + + &.dev-info { + background: rgba(0, 0, 0, .2); + } + } + + .strong { + font-size: 15px; + } +} \ No newline at end of file diff --git "a/Yunzai/plugins/miao-plugin/resources/profile/normal-character/\345\237\203\346\264\233\344\274\212.webp" "b/Yunzai/plugins/miao-plugin/resources/profile/normal-character/\345\237\203\346\264\233\344\274\212.webp" new file mode 100644 index 0000000000000000000000000000000000000000..10f34af9d81d7ff62c589a7ddc7eadffa5ec62d1 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/profile/normal-character/\345\237\203\346\264\233\344\274\212.webp" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/profile/normal-character/\350\215\247/\346\231\256\351\200\232.webp" "b/Yunzai/plugins/miao-plugin/resources/profile/normal-character/\350\215\247/\346\231\256\351\200\232.webp" new file mode 100644 index 0000000000000000000000000000000000000000..62ab194bad0b59f377e31607c23b3476b5fe02e7 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/profile/normal-character/\350\215\247/\346\231\256\351\200\232.webp" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/profile/normal-character/\350\215\247/\346\267\261\346\270\212\345\205\254\344\270\273.png" "b/Yunzai/plugins/miao-plugin/resources/profile/normal-character/\350\215\247/\346\267\261\346\270\212\345\205\254\344\270\273.png" new file mode 100644 index 0000000000000000000000000000000000000000..b03034f8a98912c1d1e9abfa59811cc83b936f2d Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/profile/normal-character/\350\215\247/\346\267\261\346\270\212\345\205\254\344\270\273.png" differ diff --git "a/Yunzai/plugins/miao-plugin/resources/profile/super-character/\350\276\276\350\276\276\345\210\251\344\272\232.webp" "b/Yunzai/plugins/miao-plugin/resources/profile/super-character/\350\276\276\350\276\276\345\210\251\344\272\232.webp" new file mode 100644 index 0000000000000000000000000000000000000000..8bec9cbd4cf07d9327d7b18678068c8514cae4b6 Binary files /dev/null and "b/Yunzai/plugins/miao-plugin/resources/profile/super-character/\350\276\276\350\276\276\345\210\251\344\272\232.webp" differ diff --git a/Yunzai/plugins/miao-plugin/resources/stat/abyss-pct.css b/Yunzai/plugins/miao-plugin/resources/stat/abyss-pct.css new file mode 100644 index 0000000000000000000000000000000000000000..4ab23341133e78a666d43d90558d7377c3c835ba --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/abyss-pct.css @@ -0,0 +1,80 @@ +.card-list { + display: flex; + flex-wrap: wrap; + justify-content: center; +} +.card-list .item { + margin: 0 0 10px 10px; + border-radius: 7px; + box-shadow: 0 2px 6px 0 rgba(132, 93, 90, 0.3); + height: 88px; + position: relative; + overflow: hidden; + background: #e7e5d9; +} +.card-list .item img { + width: 70px; + height: 70px; + border-radius: 7px 7px 20px 0; +} +.card-list .item.star5 img { + background-image: url(../common/item/bg5.png); + width: 100%; + height: 70px; + /*filter: brightness(1.1);*/ + background-size: 100%; + background-repeat: no-repeat; +} +.card-list .item.star4 img { + width: 100%; + height: 70px; + background-image: url(../common/item/bg4.png); + background-size: 100%; + background-repeat: no-repeat; +} +.card-list .item .num { + position: absolute; + top: 0; + right: 0; + z-index: 9; + font-size: 18px; + text-align: center; + color: #fff; + padding: 1px 5px; + border-radius: 4px; + background: rgba(0, 0, 0, 0.5); +} +.card-list .item .name, +.card-list .item .num_name { + position: absolute; + top: 70px; + left: 0; + z-index: 9; + font-size: 12px; + text-align: center; + width: 100%; + height: 16px; + line-height: 18px; +} +.card-list .item .num_name { + font-size: 16px; +} +.line_box { + height: 32px; + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 16px; + color: #fff; + padding-bottom: 5px; + margin-top: 15px; + margin-bottom: 5px; +} +.line_box .line { + height: 1px; + flex-grow: 1; + background-color: #ebebeb; + margin: 0px 10px; +} +/*# sourceMappingURL=abyss-pct.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/abyss-pct.html b/Yunzai/plugins/miao-plugin/resources/stat/abyss-pct.html new file mode 100644 index 0000000000000000000000000000000000000000..0f8d699f0f861b01b20c4bc94ccbc9e8634669d7 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/abyss-pct.html @@ -0,0 +1,55 @@ +{{extend defaultLayout}} + +{{block 'css'}} + + +{{/block}} + +{{block 'main'}} +
+
+ {{if chooseFloor == -1}} +
#深渊{{modeName}}
+ {{else}} +
#深渊第{{floorName[chooseFloor]}}{{modeName}}
+ {{/if}} +
【#深渊出场率】出场总数/总记录数
+
【#深渊使用率】出场总数/持有该角色的记录数
+ +
+
+
深渊出场率统计
+
+
    +
  • 数据来自DGP-Studio胡桃API,为Snap Hutao / Miao-Plugin 用户自主上传的角色池信息
  • +
  • 您可以通过#上传深渊数据命令来上传挑战记录,来帮助我们统计的更加及时准确。(上传命令仅会上传您的角色列表及当期深渊挑战数据,不会上传其他额外信息)
  • +
  • 可通过 #深渊{{modeName}}/#深渊12层{{modeName}}来查看整体或指定层的{{modeName}}数据
  • +
  • 由于是用户自主上传,数据可能有一定滞后,数据会在深渊开启后一段时间逐步稳定
  • +
  • 统计数据为本期深渊数据,{{if totalCount}}本期已提交用户数:{{totalCount}},{{/if}}数据更新时间:{{lastUpdate}}
  • +
+
+
+ <% let pct = function (num) { + return (num * 100).toFixed(2); + } %> + {{each abyss ds}} + {{if chooseFloor == -1 || chooseFloor == ds.floor}} +
+
+ + 第{{floorName[ds.floor]}} + +
+
+ {{each ds.avatars char}} +
+ +
{{pct(char.value)}}%
+
+ {{/each}} +
+
+ {{/if}} + {{/each}} +
+{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/abyss-pct.less b/Yunzai/plugins/miao-plugin/resources/stat/abyss-pct.less new file mode 100644 index 0000000000000000000000000000000000000000..8283d7760dc4e66db761539f6db01dbbc6b306e9 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/abyss-pct.less @@ -0,0 +1,88 @@ +.card-list { + display: flex; + flex-wrap: wrap; + justify-content: center; + + .item { + margin: 0 0 10px 10px; + border-radius: 7px; + box-shadow: 0 2px 6px 0 rgb(132 93 90 / 30%); + height: 88px; + position: relative; + overflow: hidden; + background: #e7e5d9; + + img { + width: 70px; + height: 70px; + border-radius: 7px 7px 20px 0; + } + + &.star5 img { + background-image: url(../common/item/bg5.png); + width: 100%; + height: 70px; + /*filter: brightness(1.1);*/ + background-size: 100%; + background-repeat: no-repeat; + } + + &.star4 img { + width: 100%; + height: 70px; + background-image: url(../common/item/bg4.png); + background-size: 100%; + background-repeat: no-repeat; + } + + .num { + position: absolute; + top: 0; + right: 0; + z-index: 9; + font-size: 18px; + text-align: center; + color: #fff; + padding: 1px 5px; + border-radius: 4px; + background: rgb(0 0 0 / 50%); + } + + .name, + .num_name { + position: absolute; + top: 70px; + left: 0; + z-index: 9; + font-size: 12px; + text-align: center; + width: 100%; + height: 16px; + line-height: 18px; + } + + .num_name { + font-size: 16px; + } + } +} + +.line_box { + height: 32px; + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 16px; + color: #fff; + padding-bottom: 5px; + margin-top: 15px; + margin-bottom: 5px; + + .line { + height: 1px; + flex-grow: 1; + background-color: #ebebeb; + margin: 0px 10px; + } +} diff --git a/Yunzai/plugins/miao-plugin/resources/stat/abyss-summary.css b/Yunzai/plugins/miao-plugin/resources/stat/abyss-summary.css new file mode 100644 index 0000000000000000000000000000000000000000..17c2cac0e0e7ca599dc27dd71ad0f592c80bfa79 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/abyss-summary.css @@ -0,0 +1,282 @@ +.font-YS { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.font-NZBZ { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +body, +.container { + width: 970px; +} +.container { + padding: 5px 0 10px 5px; +} +.head-box { + display: flex; + width: 100%; +} +.head-box .title { + font-size: 45px; + padding-bottom: 10px; + width: 70%; +} +.head-box .title span { + font-size: 30px; + margin-left: 10px; + color: #d3bc8e; +} +.head-box .uid { + text-align: right; + width: 30%; + padding-top: 25px; + padding-right: 10px; + font-size: 25px; +} +.abyss-stat-cont { + display: flex; + padding: 5px; +} +.abyss-stat { + display: flex; +} +.abyss-stat .cont { + margin: 5px 10px 5px 5px; +} +.abyss-stat strong { + text-shadow: 0 0 3px #000; +} +.abyss-stat .stat-title { + position: absolute; + top: 0; + background: rgba(0, 0, 0, 0.5); + padding: 5px 10px; + width: 100%; + text-shadow: 0 0 1px #000; +} +.abyss-stat .stat-title span { + display: block; + font-weight: normal; + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; + font-size: 24px; +} +.abyss-stat .stat-title strong { + display: block; + font-size: 30px; +} +.abyss-stat .stat-msg { + position: absolute; + bottom: 0; + background: rgba(0, 0, 0, 0.55); + backdrop-filter: blur(2px); + padding: 5px 10px; + width: 100%; + text-shadow: 0 0 1px #000; + font-size: 14px; +} +.abyss-stat .stat-msg .msg { + display: block; + line-height: 25px; +} +.abyss-stat .stat-msg .msg strong { + font-size: 20px; + padding: 0 2px; + font-weight: normal; + color: #d3bc8e; +} +.avatar-banner { + height: 300px; + width: 175px; + background-repeat: no-repeat; + background-size: 100% auto; + background-position: 0 10%; +} +.abyss-data { + display: flex; + padding: 0 6px; +} +.abyss-data .abyss-item { + color: #fff; + margin: 5px; +} +.abyss-data .abyss-item .info { + text-align: center; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; +} +.abyss-data .abyss-item .info strong { + display: block; + font-weight: normal; + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.abyss-data .abyss-item .info span { + font-size: 24px; + display: block; +} +.abyss-data .abyss-item .info span:after { + content: "次"; + font-size: 15px; + margin-left: 2px; +} +.abyss-title { + margin: -3px 0 8px; +} +.abyss-title strong { + color: #d3bc8e; + font-size: 18px; + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; + font-weight: normal; + margin-right: 10px; +} +.abyss-title .abyss-star { + font-size: 15px; + color: #fff; +} +.abyss-title .abyss-star:before { + content: ""; + vertical-align: bottom; + display: inline-block; + width: 20px; + height: 20px; + background: url("./imgs/star.png") center no-repeat; + background-size: contain; + margin-right: 5px; +} +.abyss-floor-team { + display: flex; +} +.abyss-floor-team .line { + width: 1px; + background: rgba(255, 255, 255, 0.5); + height: 80px; + vertical-align: middle; + margin: 15px 10px 0; +} +.abyss-team { + display: flex; +} +.abyss-detail { + display: flex; + width: calc(100% + 40px); + margin: 10px -15px -10px; +} +.abyss-level { + padding: 5px 10px 7px; + width: 33%; + box-shadow: 0 0 1px 0 #fff; +} +.abyss-level:nth-child(even) { + background: rgba(255, 255, 255, 0.1); +} +.abyss-level .info { + margin-bottom: 5px; + display: flex; + padding-left: 8px; +} +.abyss-level .title { + font-size: 16px; + white-space: nowrap; + font-weight: bold; +} +.abyss-level .star { + height: 18px; + display: inline-block; + background: url(./imgs/star.png); + background-size: 18px 18px; + margin-left: 5px; +} +.abyss-level .star.star1 { + width: 18px; + margin-right: 36px; +} +.abyss-level .star.star2 { + width: 36px; + margin-right: 18px; +} +.abyss-level .star.star3 { + width: 54px; + margin-right: 0; +} +.abyss-level .time { + text-align: right; + width: 60%; + color: #aaa; + font-size: 14px; +} +.abyss-level .avatars { + display: flex; + width: 100%; +} +.abyss-level .avatars .avatar-list { + display: flex; + position: relative; +} +.abyss-level .avatars .avatar-list.up { + padding-right: 15px; +} +.abyss-level .avatars .avatar-list.up:after { + content: ""; + display: block; + position: absolute; + width: 1px; + height: 16px; + background: rgba(255, 255, 255, 0.3); + right: 8px; + top: 50%; + margin-top: -8px; +} +.abyss-level .avatars .avatar-icon { + width: 33px; + height: 33px; + border-radius: 50%; + margin-right: 2px; +} +.abyss-level .avatars .avatar-icon .img { + background-size: auto 100%; + background-position: center; + width: 29px; + height: 29px; + margin: 2px; +} +.abyss-notice .cont-body { + font-size: 16px; +} +.avatar-banner.avatar-枫原万叶, +.img.wide.avatar-枫原万叶 { + background-position: 0 -13%; +} +.avatar-banner.avatar-九条裟罗, +.img.wide.avatar-九条裟罗 { + background-position: 0 0; +} +.avatar-banner.avatar-香菱, +.img.wide.avatar-香菱 { + background-position: 0 -16%; +} +.avatar-banner.avatar-行秋, +.img.wide.avatar-行秋 { + background-position: 0 -16%; +} +.avatar-banner.avatar-甘雨, +.img.wide.avatar-甘雨 { + background-position: 0 -8%; +} +.avatar-banner.avatar-刻晴, +.img.wide.avatar-刻晴 { + background-position: 0 -5%; +} +.avatar-banner.avatar-神里绫华, +.img.wide.avatar-神里绫华 { + background-position: 0 13%; +} +.avatar-banner.avatar-班尼特, +.img.wide.avatar-班尼特 { + background-position: 0 15%; +} +.avatar-banner.avatar-五郎, +.img.wide.avatar-五郎 { + background-position: 0 15%; +} +.avatar-banner.avatar-托马, +.img.wide.avatar-托马 { + background-position: 0 -5%; +} +/*# sourceMappingURL=abyss-summary.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/abyss-summary.html b/Yunzai/plugins/miao-plugin/resources/stat/abyss-summary.html new file mode 100644 index 0000000000000000000000000000000000000000..e47bf9afd4b2e88ed20d750f3dd21e3af151bb9d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/abyss-summary.html @@ -0,0 +1,113 @@ +{{extend defaultLayout}} + +{{block 'css'}} + + + +{{/block}} + +{{block 'main'}} +{{ set upDown = {up:'上半', down:'下半'} }} +
+
#上传深渊{{abyss.schedule}} · {{abyss.total}}次战斗
+
UID:{{uid}}
+
+
+ +
+ +
+ {{each stat ds}} + {{set avatar = avatars[ds.id]}} +
+ {{if avatar}} +
+ {{ds.title}} + {{ds.value}} +
+
+ + {{if ds.msg}} +
+ {{each ds.msg msg}} + {{if msg.txt}} +
{{msg.txt}}
+ {{else}} +
{{msg.title}}{{msg.value}}%的{{msg.name}}
+ {{/if}} + {{/each}} +
+ {{/if}} + {{/if}} +
+ {{/each}} +
+ +
+ {{set cardTypes={1:['wide wide2'],2:['wide','wide'],3:['wide','mini','mini'],4:['mini','mini','mini','mini']} }} + {{each abyss?.floors floor}} +
+ +
+
+ 第{{floor.index}}层 + {{floor.star}}/9 +
+
+
+ {{set ds=floor?.display?.up?.avatars||[] }} + {{each ds id idx}} + <% include(_tpl_path+'/avatar-card.html', [avatars[id],{_res_path, cardType:cardTypes[ds.length][idx]}]) %> + {{/each}} +
+
+
+ {{set ds=floor?.display?.down?.avatars||[] }} + {{each ds id idx}} + <% include(_tpl_path+'/avatar-card.html', [avatars[id],{_res_path, cardType:cardTypes[ds.length][idx]}]) %> + {{/each}} +
+
+
+ {{each floor.levels level idx}} +
+
+
+ 第{{idx}}间 +
+ +
{{level?.up?.time}}
+
+
+ {{each upDown v k}} +
+ {{each level[k]?.avatars||[] id}} + {{set avatar = avatars[id] || {} }} +
+ +
+ {{/each}} +
+ {{/each}} +
+
+ {{/each}} +
+
+
+ {{/each}} + +
+
+
    +
  • #上传深渊会上传你的角色列表及当期深渊挑战数据,不会上传其他信息,感谢支持,喵~
  • +
  • 统计服务由DGP-Studio胡桃API提供,上传的数据将会用于排名以及#深渊使用率#角色持有率等统计
  • +
  • 深渊排行为本期深渊排行,{{if totalCount}}本期已提交用户数:{{totalCount}},{{/if}}更新时间{{abyss.time}}。
  • +
  • 角色装备与圣遗物为当前最新状态;排名会随时间而更新,数据排名仅供娱乐~
  • +
+
+
+
+{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/abyss-summary.less b/Yunzai/plugins/miao-plugin/resources/stat/abyss-summary.less new file mode 100644 index 0000000000000000000000000000000000000000..6338f6c5e9159edae09571149a9e6790aa759aba --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/abyss-summary.less @@ -0,0 +1,334 @@ +@import "../common/base.less"; + +@scale: 1.4; +body, .container { + width: 970px; +} + +.container { + padding: 5px 0 10px 5px; +} + +.head-box { + display: flex; + width: 100%; + + .title { + font-size: 45px; + padding-bottom: 10px; + width: 70%; + + span { + font-size: 30px; + margin-left: 10px; + color: #d3bc8e; + } + } + + .uid { + text-align: right; + width: 30%; + padding-top: 25px; + padding-right: 10px; + font-size: 25px; + } +} + +.abyss-stat-cont { + display: flex; + padding: 5px; +} + +.abyss-stat { + display: flex; + + .cont { + margin: 5px 10px 5px 5px; + } + + strong { + text-shadow: 0 0 3px #000; + } + + .stat-title { + position: absolute; + top: 0; + background: rgba(0, 0, 0, 0.5); + padding: 5px 10px; + width: 100%; + text-shadow: 0 0 1px #000; + + span { + display: block; + font-weight: normal; + .font-NZBZ; + font-size: 24px; + } + + strong { + display: block; + font-size: 30px; + } + } + + .stat-msg { + position: absolute; + bottom: 0; + background: rgba(0, 0, 0, 0.55); + backdrop-filter: blur(2px); + padding: 5px 10px; + width: 100%; + text-shadow: 0 0 1px #000; + font-size: 14px; + + .msg { + display: block; + line-height: 25px; + + strong { + font-size: 20px; + padding: 0 2px; + font-weight: normal; + color: #d3bc8e; + } + } + } +} + + +.avatar-banner { + height: 300px; + width: 175px; + background-repeat: no-repeat; + background-size: 100% auto; + background-position: 0 10%; +} + +.abyss-data { + display: flex; + padding: 0 6px; + + .abyss-item { + color: #fff; + margin: 5px; + + .info { + text-align: center; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; + + strong { + display: block; + font-weight: normal; + .font-NZBZ; + } + + span { + font-size: 24px; + display: block; + + &:after { + content: "次"; + font-size: 15px; + margin-left: 2px; + } + } + } + } +} + +.abyss-title { + margin: -3px 0 8px; + + strong { + color: #d3bc8e; + font-size: 18px; + .font-NZBZ; + font-weight: normal; + margin-right: 10px; + } + + .abyss-star { + font-size: 15px; + color: #fff; + + &:before { + content: ""; + vertical-align: bottom; + display: inline-block; + width: 20px; + height: 20px; + background: url("./imgs/star.png") center no-repeat; + background-size: contain; + margin-right: 5px; + } + + } +} + +.abyss-floor-team { + display: flex; + + .line { + width: 1px; + background: rgba(255, 255, 255, .5); + height: 80px; + vertical-align: middle; + margin: 15px 10px 0; + } +} + +.abyss-team { + + display: flex; +} + +.abyss-detail { + display: flex; + width: calc(100% + 40px); + margin: 10px -15px -10px; +} + + +.abyss-level { + padding: 5px 10px 7px; + width: 33%; + box-shadow: 0 0 1px 0 #fff; + + &:nth-child(even) { + background: rgba(255, 255, 255, .1) + } + + + .info { + margin-bottom: 5px; + display: flex; + padding-left: 8px; + } + + .title { + font-size: 16px; + white-space: nowrap; + font-weight: bold; + } + + .star { + @size: 18px; + + height: @size; + display: inline-block; + background: url(./imgs/star.png); + background-size: @size @size; + margin-left: 5px; + + &.star1 { + width: @size; + margin-right: @size * 2; + } + + &.star2 { + width: @size * 2; + margin-right: @size; + } + + &.star3 { + width: @size * 3; + margin-right: 0; + } + } + + .time { + text-align: right; + width: 60%; + color: #aaa; + font-size: 14px; + } + + .avatars { + display: flex; + width: 100%; + + .avatar-list { + display: flex; + position: relative; + + &.up { + padding-right: 15px; + } + + &.up:after { + content: ""; + display: block; + position: absolute; + width: 1px; + height: 16px; + background: rgba(255, 255, 255, .3); + right: 8px; + top: 50%; + margin-top: -8px; + } + } + + .avatar-icon { + width: 33px; + height: 33px; + border-radius: 50%; + margin-right: 2px; + + .img { + background-size: auto 100%; + background-position: center; + width: 29px; + height: 29px; + margin: 2px; + } + } + } +} + +.abyss-notice { + .cont-body { + font-size: 16px; + } +} + +.avatar-banner, .img.wide { + &.avatar-枫原万叶 { + background-position: 0 -13%; + } + + &.avatar-九条裟罗 { + background-position: 0 0; + } + + &.avatar-香菱 { + background-position: 0 -16%; + } + + &.avatar-行秋 { + background-position: 0 -16%; + } + + &.avatar-甘雨 { + background-position: 0 -8%; + } + + &.avatar-刻晴 { + background-position: 0 -5%; + } + + &.avatar-神里绫华 { + background-position: 0 13%; + } + + &.avatar-班尼特 { + background-position: 0 15%; + } + + &.avatar-五郎 { + background-position: 0 15%; + } + + &.avatar-托马 { + background-position: 0 -5%; + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/abyss-team.css b/Yunzai/plugins/miao-plugin/resources/stat/abyss-team.css new file mode 100644 index 0000000000000000000000000000000000000000..918dca107a2bb2152439bb409e34a20a45ccc4af --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/abyss-team.css @@ -0,0 +1,93 @@ +.head-box { + margin-top: 0; + margin-bottom: 15px; +} +.cont { + margin-top: 10px; +} +.cont-table .title { + min-width: 30px; + padding-right: 5px; + padding-left: 5px; + text-align: center; +} +.cont-table .title .team-count { + display: block; + font-size: 12px; + color: #555; +} +.card-list { + display: flex; + flex-wrap: wrap; + justify-content: center; + padding: 5px 0; +} +.card-list .card { + margin: 3px; + border-radius: 5px; + box-shadow: 0 2px 6px 0 rgba(132, 93, 90, 0.3); + position: relative; + overflow: hidden; + background: #e7e5d9; + font-size: 12px; + color: #000; + text-align: center; +} +.card-list .has-character .for-no { + display: none; +} +.card-list .no-character .for-has { + display: none; +} +.card-list .no-character { + opacity: 0.5; +} +.card-list .no-label { + font-size: 12px; + color: #555; +} +.card-list .card img { + width: 50px; + height: 50px; + border-radius: 5px 5px 10px 0; + background-size: 100%; + background-repeat: no-repeat; + display: block; +} +.card-list .card.star5 img { + background-image: url(../common/item/bg5.png); +} +.card-list .card.star4 img { + background-image: url(../common/item/bg4.png); +} +.card-list .card .cons { + position: absolute; + top: 0; + right: 0; + padding: 3px; +} +.card-list .card .num { + position: absolute; + top: 0px; + right: 0px; + z-index: 9; + font-size: 18px; + text-align: center; + color: #fff; + border-radius: 3px; + padding: 1px 5px; + background: rgba(0, 0, 0, 0.5); +} +.card-list .card .name, +.card-list .card .num_name { + position: absolute; + top: 70px; + left: 0px; + z-index: 9; + font-size: 12px; + text-align: center; + width: 100%; + height: 16px; + line-height: 18px; +} +/*# sourceMappingURL=abyss-team.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/abyss-team.html b/Yunzai/plugins/miao-plugin/resources/stat/abyss-team.html new file mode 100644 index 0000000000000000000000000000000000000000..46549b795b40a246bcf680f164deb008fc4c646d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/abyss-team.html @@ -0,0 +1,64 @@ +{{extend defaultLayout}} + +{{block 'css'}} + + +{{/block}} + +{{block 'main'}} +
+
+
深渊配队建议
+ +
+ +
+
深渊配队说明
+
+
    +
  • 深渊出场数据来自DGP-Studio胡桃API,为Snap Hutao / Miao-Plugin 用户自主上传的角色池信息
  • +
  • 您可以通过#上传深渊数据命令来上传角色记录,来帮助我们获取更多组队信息。
  • +
  • 上传命令仅会上传您的角色列表及当期深渊挑战数据,不会上传其他额外信息
  • +
  • 月初及月中深渊刚刷新后挑战数据可能不足,请等待几天之后数据会逐步稳定
  • +
  • 若当前记录可用配队方案少于4组时,会使用未持有角色的方案进行补充
  • +
  • 配队列表仅供参考,可根据账号实际情况及个人倾向进行灵活调整
  • +
+
+
+ + {{each teams floorTeam floor}} +
+ +
+
+
{{floor}}层
+
上半
+
下半
+
+ {{each floorTeam team idx}} +
+
配队{{idx+1}}{{team.count}}次记录
+ {{each team teamData key}} + {{if key === "up" || key === "down"}} +
+
+ {{each teamData.teamArr id}} +
+ + {{avatars[id].cons}} + Lv.{{avatars[id].level}} + 暂无 +
+ {{/each}} +
+
+ {{/if}} + {{/each}} +
+ {{/each}} +
+
+ {{/each}} +
+{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/abyss-team.less b/Yunzai/plugins/miao-plugin/resources/stat/abyss-team.less new file mode 100644 index 0000000000000000000000000000000000000000..2738da930d707e13a19a5067b7eb453feb2e406a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/abyss-team.less @@ -0,0 +1,108 @@ +.head-box { + margin-top: 0; + margin-bottom: 15px; +} + +.cont { + margin-top: 10px; +} + +.cont-table .title { + min-width: 30px; + padding-right: 5px; + padding-left: 5px; + text-align: center; +} + +.cont-table .title .team-count { + display: block; + font-size: 12px; + color: #555; +} + +.card-list { + display: flex; + flex-wrap: wrap; + justify-content: center; + padding: 5px 0; +} + +.card-list .card { + margin: 3px; + border-radius: 5px; + box-shadow: 0 2px 6px 0 rgb(132 93 90 / 30%); + position: relative; + overflow: hidden; + background: #e7e5d9; + font-size: 12px; + color: #000; + text-align: center; +} + +.card-list .has-character .for-no { + display: none; +} + +.card-list .no-character .for-has { + display: none; +} + +.card-list .no-character { + opacity: .5; +} + +.card-list .no-label { + font-size: 12px; + color: #555; +} + +.card-list .card img { + width: 50px; + height: 50px; + border-radius: 5px 5px 10px 0; + background-size: 100%; + background-repeat: no-repeat; + display: block; +} + +.card-list .card.star5 img { + background-image: url(../common/item/bg5.png); +} + +.card-list .card.star4 img { + background-image: url(../common/item/bg4.png); +} + +.card-list .card .cons { + position: absolute; + top: 0; + right: 0; + padding: 3px; +} + +.card-list .card .num { + position: absolute; + top: 0px; + right: 0px; + z-index: 9; + font-size: 18px; + text-align: center; + color: #fff; + border-radius: 3px; + padding: 1px 5px; + background: rgb(0 0 0 / 50%); +} + +.card-list .card .name, +.card-list .card .num_name { + position: absolute; + top: 70px; + left: 0px; + z-index: 9; + font-size: 12px; + text-align: center; + width: 100%; + height: 16px; + line-height: 18px; +} + diff --git a/Yunzai/plugins/miao-plugin/resources/stat/character.css b/Yunzai/plugins/miao-plugin/resources/stat/character.css new file mode 100644 index 0000000000000000000000000000000000000000..cc644420a33c933e3c12d49888deda23172dbbd5 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/character.css @@ -0,0 +1,191 @@ +.weapon_mode .for_talent { + display: none !important; +} +.talent_mode .for_weapon { + display: none !important; +} +.data-box { + border-radius: 15px; + margin-top: 20px; + margin-bottom: 20px; + padding: 0px 15px 5px 15px; + overflow: hidden; + background: #f5f5f5; + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.15); + position: relative; +} +.tab_lable { + position: absolute; + top: -10px; + left: -8px; + background: #a98242; + color: #fff; + font-size: 14px; + padding: 3px 10px; + border-radius: 15px 0px 15px 15px; + z-index: 20; +} +.data_line { + display: flex; + justify-content: space-around; + margin-bottom: 14px; +} +.data_line_item { + width: 100px; + text-align: center; + /*margin: 0 20px;*/ +} +.num { + font-size: 24px; +} +.num .unit { + font-size: 12px; +} +.char-list { + display: table; + border-collapse: collapse; + width: calc(100% + 30px); + margin: 0 -15px -5px; + font-size: 12px; + /* border-radius: 0 0 15px 15px; */ + overflow: hidden; +} +.char-list .avatar { + display: table-row; + overflow: visible; +} +.char-list .avatar > div { + box-shadow: 0 0 1px 0 #555 inset; +} +.char-list .avatar:nth-child(odd) { + background: #e0e0e0; +} +.char-list .avatar:nth-child(1) { + background: #ccc; +} +.char-list .avatar > div { + display: table-cell; + text-align: center; + height: 30px; + vertical-align: middle; + line-height: 30px; +} +.char-list .avatar .index { + color: #333; + width: 30px; + padding-left: 5px; +} +.char-list .avatar .name_cont { + width: 80px; +} +.char-list .avatar .star4 { + background: rgba(137, 189, 233, 0.6); +} +.char-list .avatar .star5 { + background: rgba(239, 214, 137, 0.6); +} +.char-list .avatar .name_cont { + width: 80px; +} +.char-list .avatar .name { + text-align: left; + display: flex; + width: 80px; +} +.char-list .th, +.char-list .th div { + font-weight: bold; + height: 40px; + line-height: 40px; + overflow: hidden; +} +.char-list .th .name { + justify-content: center; +} +.char-list .avatar .name .avatar_img { + width: 26px; + height: 26px; + position: relative; + margin-right: 3px; +} +.char-list .avatar .name img { + width: 100%; + height: 100%; + position: absolute; + top: 2px; + margin-left: 3px; +} +.char-list .avatar .name .avatar_name { + white-space: nowrap; + overflow: hidden; + width: 48px; +} +.char-list .avatar .res { + font-size: 12px; + width: 90px; +} +.char-list .avatar .res img { + width: 20px; + height: 20px; + vertical-align: middle; +} +.char-list .avatar > div.fetter10 { + background: url("./hart.png") center center no-repeat; + background-size: contain; + color: #fff; +} +.char-list .char-cons { + width: 400px; + position: relative; + z-index: 98; + overflow: visible; +} +.char-list .cons-pct, +.char-list .cons-bg { + display: flex; +} +.char-list .th .cons-pct { + margin: 0; + color: #fff; + font-weight: bold; +} +.char-list .th .cons-pct > div:first-child { + padding-left: 10px; +} +.char-list .th .cons-pct > div:last-child { + padding-right: 10px; +} +.char-list .cons-pct { + margin: 0 10px; + z-index: 100; + position: relative; + color: #fff; +} +.char-list .cons-pct > div { + flex: 1; + font-size: 12px; + mix-blend-mode: difference; + font-weight: normal; + text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.7); +} +.char-list .life_bg { + background: #888; +} +.char-list .cons-bg { + position: absolute; + left: 5px; + right: 5px; + bottom: 5px; + height: 20px; + z-index: 99; + border-radius: 3px; + overflow: hidden; + background: #888; +} +.char-list .cons-bg > div { + height: 20px; +} +.char-list .cons-bg > div:last-child { + border-radius: 0 3px 3px 0; +} +/*# sourceMappingURL=character-talent.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/character.html b/Yunzai/plugins/miao-plugin/resources/stat/character.html new file mode 100644 index 0000000000000000000000000000000000000000..b694ec3c762699e8cb667fd3767e0ea49181b40e --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/character.html @@ -0,0 +1,99 @@ +{{extend defaultLayout}} + +{{block 'css'}} + + +{{/block}} + +<% let pct = function (num) { +return (num * 100).toFixed(2); +} %> + +{{block 'main'}} + + +
+
+ {{if mode === "char"}} +
#角色持有率
+
全角色综合持有率统计
+ {{else}} +
#角色{{conNum == -1 ? "命座" : "零一二三四五满"[conNum]+"命"}}统计
+
统计所有角色命座,无论角色是否出场
+ {{/if}} + +
+ +
+
角色持有率说明
+
+
    +
  • 数据来自DGP-Studio胡桃API,为Snap Hutao / Miao-Plugin用户自主上传的角色池信息
  • +
  • 百分比基于全部上传用户的数据进行统计,能够一定程度上反映角色持有情况,结果供参考
  • +
  • 您可以通过#上传深渊数据命令来上传角色记录,来帮助我们统计的更加全面
  • +
  • 上传命令仅会上传您的角色列表及当期深渊挑战数据,不会上传其他额外信息
  • +
  • 由于是用户自主上传,数据可能有一定滞后。新角色的持有率会在卡池结束后一段时间逐步稳定
  • +
  • {{if totalCount}}统计用户数:{{totalCount}},{{/if}}数据最后更新时间:{{lastUpdate}}
  • +
+
+
+ +
+
+
+
#
+
+ 角色 +
+
持有率
+
+
+
0命
+
1命
+
2命
+
3命
+
4命
+
5命
+
6命
+ {{if mode === "char"}} +
+ {{/if}} +
+ +
+
+ {{each chars char idx}} +
+
{{idx+1}}
+
+
+
+ +
+
+ {{char.abbr || char.name}} +
+
+
+
{{pct(char.hold)}}
+
+
+ {{each char.cons con idx}} +
{{pct(con.value)}}
+ {{/each}} + {{if mode ==="char"}} +
{{pct(1-char.hold)}}
+ {{/if}} +
+
+ {{each char.cons con idx}} +
+ {{/each}} +
+
+
+ {{/each}} +
+
+
+{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/character.less b/Yunzai/plugins/miao-plugin/resources/stat/character.less new file mode 100644 index 0000000000000000000000000000000000000000..6e5b45009ec153f76153101fa6c168bd73a63623 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/character.less @@ -0,0 +1,244 @@ + +.weapon_mode .for_talent { + display: none !important; +} + +.talent_mode .for_weapon { + display: none !important; +} + + +.data-box { + border-radius: 15px; + margin-top: 20px; + margin-bottom: 20px; + padding: 0px 15px 5px 15px; + overflow: hidden; + background: #f5f5f5; + box-shadow: 0 5px 10px 0 rgb(0 0 0 / 15%); + position: relative; +} + +.tab_lable { + position: absolute; + top: -10px; + left: -8px; + background: #a98242; + color: #fff; + font-size: 14px; + padding: 3px 10px; + border-radius: 15px 0px 15px 15px; + z-index: 20; +} + +.data_line { + display: flex; + justify-content: space-around; + margin-bottom: 14px; +} + +.data_line_item { + width: 100px; + text-align: center; + /*margin: 0 20px;*/ +} + +.num { + font-size: 24px; +} + +.num .unit { + font-size: 12px; +} + + +.data-box { + +} + +.char-list { + display: table; + border-collapse: collapse; + width: calc(100% + 30px); + margin: 0 -15px -5px; + font-size: 12px; + /* border-radius: 0 0 15px 15px; */ + overflow: hidden; + + .avatar { + display: table-row; + overflow: visible; + + & > div { + box-shadow: 0 0 1px 0 #555 inset; + } + + &:nth-child(odd) { + background: #e0e0e0; + } + + &:nth-child(even) { + + } + + &:nth-child(1) { + background: #ccc; + + } + + & > div { + display: table-cell; + text-align: center; + height: 30px; + vertical-align: middle; + line-height: 30px; + } + + .index { + color: #333; + width: 30px; + padding-left: 5px; + + } + + .name_cont { + width: 80px; + } + + + .star4 { + background: rgba(137, 189, 233, .6); + } + + .star5 { + background: rgba(239, 214, 137, .6); + } + + .name_cont { + width: 80px; + } + + .name { + text-align: left; + display: flex; + width: 80px; + } + } +} + +.char-list .th, +.char-list .th div { + font-weight: bold; + height: 40px; + line-height: 40px; + overflow: hidden; +} + +.char-list .th .name { + justify-content: center; +} + +.char-list .avatar .name .avatar_img { + width: 26px; + height: 26px; + position: relative; + margin-right: 3px; +} + +.char-list .avatar .name img { + width: 100%; + height: 100%; + position: absolute; + top: 2px; + margin-left: 3px; +} + +.char-list .avatar .name .avatar_name { + white-space: nowrap; + overflow: hidden; + width: 48px; +} + +.char-list .avatar .res { + font-size: 12px; + width: 90px; +} + +.char-list .avatar .res img { + width: 20px; + height: 20px; + vertical-align: middle; +} + +.char-list .avatar > div.fetter10 { + background: url("./hart.png") center center no-repeat; + background-size: contain; + color: #fff; +} + +.char-list .char-cons { + width: 400px; + position: relative; + z-index: 98; + overflow: visible; +} + +.char-list .cons-pct, +.char-list .cons-bg { + display: flex; +} + +.char-list .th .cons-pct { + margin: 0; + color: #fff; + font-weight: bold; +} + +.char-list .th .cons-pct > div:first-child { + padding-left: 10px; +} + +.char-list .th .cons-pct > div:last-child { + padding-right: 10px; +} + + +.char-list .cons-pct { + margin: 0 10px; + z-index: 100; + position: relative; + color: #fff; +} + +.char-list .cons-pct > div { + flex: 1; + font-size: 12px; + mix-blend-mode: difference; + font-weight: normal; + text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.7); +} + +.char-list .life_bg { + background: #888; +} + + +.char-list .cons-bg { + position: absolute; + left: 5px; + right: 5px; + bottom: 5px; + height: 20px; + z-index: 99; + border-radius: 3px; + overflow: hidden; + background: #888; + + & > div { + height: 20px; + + &:last-child { + border-radius: 0 3px 3px 0; + } + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/common.css b/Yunzai/plugins/miao-plugin/resources/stat/common.css new file mode 100644 index 0000000000000000000000000000000000000000..136fe219072285d56149f57adddfe9486bc226d2 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/common.css @@ -0,0 +1,75 @@ +.font-YS { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.font-NZBZ { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} +body { + font-size: 18px; + color: #1e1f20; + transform: scale(1.4); + transform-origin: 0 0; + background: url("./imgs/bg1.png") top left no-repeat #2a3860; + background-size: contain; + width: 600px; +} +.container { + width: 600px; + padding: 20px 15px 10px 15px; + background: url("./imgs/footer.png") left bottom no-repeat; + background-size: contain; +} +.head-box { + border-radius: 15px; + padding: 10px 20px; + position: relative; + color: #fff; + margin-top: 30px; +} +.head-box .title { + font-size: 36px; + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.head-box .genshin-logo { + position: absolute; + top: 1px; + right: 15px; + width: 97px; + background: url(../common/cont/logo.png) no-repeat center; + background-size: contain; +} +.head-box .label { + font-size: 16px; +} +.msg-cont { + margin-left: 0; + margin-right: 0; +} +.notice { + color: #888; + font-size: 12px; + text-align: right; + padding: 12px 5px 5px; +} +.notice-center { + color: #fff; + text-align: center; + margin-bottom: 10px; + text-shadow: 1px 1px 1px #333; +} +.copyright { + font-size: 16px; + text-align: center; + color: #fff; + position: relative; + padding-left: 10px; + text-shadow: 1px 1px 1px #000; + margin-bottom: 10px; +} +/*# sourceMappingURL=common.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/stat/common.less b/Yunzai/plugins/miao-plugin/resources/stat/common.less new file mode 100644 index 0000000000000000000000000000000000000000..b6fa577f7186637dac797188b16fb2c66bb020e0 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/stat/common.less @@ -0,0 +1,81 @@ +@import "../common/base.less"; + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} + +body { + font-size: 18px; + color: #1e1f20; + transform: scale(1.4); + transform-origin: 0 0; + background: url("./imgs/bg1.png") top left no-repeat #2a3860; + background-size: contain; + width: 600px; +} + +.container { + width: 600px; + padding: 20px 15px 10px 15px; + background: url("./imgs/footer.png") left bottom no-repeat; + background-size: contain; +} + + +.head-box { + border-radius: 15px; + padding: 10px 20px; + position: relative; + color: #fff; + margin-top: 30px; + + .title { + font-size: 36px; + .font-NZBZ; + } + + .genshin-logo { + position: absolute; + top: 1px; + right: 15px; + width: 97px; + background: url(../common/cont/logo.png) no-repeat center; + background-size: contain; + } + + .label { + font-size: 16px; + } +} + +.msg-cont { + margin-left: 0; + margin-right: 0; +} + +.notice { + color: #888; + font-size: 12px; + text-align: right; + padding: 12px 5px 5px; +} + +.notice-center { + color: #fff; + text-align: center; + margin-bottom: 10px; + text-shadow: 1px 1px 1px #333; +} + +.copyright { + font-size: 16px; + text-align: center; + color: #fff; + position: relative; + padding-left: 10px; + text-shadow: 1px 1px 1px #000; + margin-bottom: 10px; +} diff --git a/Yunzai/plugins/miao-plugin/resources/stat/imgs/bg1.png b/Yunzai/plugins/miao-plugin/resources/stat/imgs/bg1.png new file mode 100644 index 0000000000000000000000000000000000000000..cbf068c271316966c64e8f3779a36ce527f8c893 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/stat/imgs/bg1.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/stat/imgs/footer.png b/Yunzai/plugins/miao-plugin/resources/stat/imgs/footer.png new file mode 100644 index 0000000000000000000000000000000000000000..69a851f5f97a338f644c6c70d45b9946461153f5 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/stat/imgs/footer.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/stat/imgs/star.png b/Yunzai/plugins/miao-plugin/resources/stat/imgs/star.png new file mode 100644 index 0000000000000000000000000000000000000000..fb5901cf81f58aa2a9085e06b51072f94f22fc25 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/stat/imgs/star.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/calendar.css b/Yunzai/plugins/miao-plugin/resources/wiki/calendar.css new file mode 100644 index 0000000000000000000000000000000000000000..a1cbe79dd74656ffc051a7cd09e60beb215cccb7 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/calendar.css @@ -0,0 +1,453 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} +body { + font-size: 18px; + color: #1e1f20; + transform: scale(1); + transform-origin: 0 0; + width: 996px; +} +.container { + width: 996px; + padding: 10px 0px 10px 0px; + background-size: 100% 100%; +} +.logo { + font-size: 18px; + text-align: center; + color: #fff; + margin: 20px 0 10px 0; +} +.calendar { + min-height: 400px; + position: relative; + padding: 1px 0; + width: 956px; + margin: 20px; + box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.6); + border-radius: 10px; +} +.cal-bg { + position: absolute; + width: 956px; + top: 0; + left: 0; + right: 0; + bottom: 0; + text-align: center; + border-collapse: collapse; + height: 100%; + box-shadow: 0 0 1px 0 #fff inset; + border-radius: 10px; + overflow: hidden; +} +.cal-bg table { + height: 100%; +} +.cal-bg .tr.thead { + background: rgba(0, 0, 0, 0.8); + height: 40px; +} +.cal-bg td { + box-shadow: 0 0 1px 0 #fff; +} +.cal-bg td.date { + width: 7.692%; +} +.cal-bg td.date span { + display: block; + line-height: 18px; +} +.cal-bg td.date span.date-week { + line-height: 12px; + font-size: 12px; + color: #888; +} +.cal-bg td.date.current-date { + background: #d3bc8e; + border: 1px solid #d3bc8e; + color: #000; +} +.cal-bg td.date.current-date span.date-week { + color: #000; +} +.cal-bg td.line { + background: rgba(0, 0, 0, 0.4); + vertical-align: top; +} +.cal-bg td.line.current-date { + background: rgba(211, 188, 142, 0.4); +} +.cal-bg .card { + width: 65px; + height: 76px; + margin: 8px auto -4px; +} +.cal-bg .card .img { + height: 60px; +} +.cal-bg .card .char-name { + position: absolute; + bottom: 0; + left: 0; + right: 0; + line-height: 17px; + font-size: 12px; + background: #e8e2d8; +} +.cal-list { + position: relative; + padding-top: 80px; + overflow: hidden; +} +.cal-list.char-num-0 { + padding-top: 80px; +} +.cal-list.char-num-1 { + padding-top: 160px; +} +.cal-list.char-num-2 { + padding-top: 240px; +} +.cal-list.char-num-3 { + padding-top: 320px; +} +.cal-list .cal-item { + margin-bottom: 15px; + border-radius: 5px; + white-space: nowrap; + text-overflow: ellipsis; + position: relative; + overflow: hidden; + background: #e8e2d8; + z-index: 1; +} +.cal-list .cal-item:after { + content: ""; + display: block; + position: absolute; + left: 3px; + top: 3px; + right: 4px; + bottom: 4px; + box-shadow: 0 0 1px 0 #000 inset, 0 0 2px 0 #222a3b; + border-radius: 4px; +} +.cal-list .cal-item .info { + position: relative; + display: inline-block; + padding: 15px 50px 15px 55px; + min-width: calc(100% - 400px); + border-radius: 5px; + background-image: linear-gradient(to right, #E8E2D8, #E8E2D8 80%, rgba(232, 226, 216, 0) 100%); +} +.cal-list .cal-item .banner { + position: absolute; + width: 100%; + max-width: 500px; + top: 0; + bottom: 0; + right: 0; + background-size: 100% auto; + background-position: left 40%; +} +.cal-list .cal-item strong { + display: block; + font-weight: normal; +} +.cal-list .cal-item span { + display: block; + font-size: 12px; +} +.cal-list .cal-item.type-character { + overflow: visible; + margin-top: 20px; +} +.cal-list .cal-item.type-character .info { + padding-left: 65px; +} +.cal-list .cal-item.type-character .character-img { + height: 75px; + position: absolute; + bottom: 0; + left: 0; + z-index: 10; +} +.cal-list .cal-item.type-normal { + margin-top: 5px; + margin-bottom: 5px; +} +.cal-list .cal-item.type-normal:last-child { + margin-bottom: 15px; +} +.cal-list .cal-item.type-normal:after { + display: none; +} +.cal-list .cal-item.type-normal:first-of-type { + margin-top: 20px; +} +.cal-list .cal-item.type-normal .info { + padding: 8px 20px 8px 15px; + line-height: 16px; + color: #4b5366; +} +.cal-list .cal-item.type-normal .cal-icon { + width: 23px; + height: 23px; + top: 6px; + margin-left: -3px; + margin-right: 5px; +} +.cal-list .cal-item.type-normal strong { + font-size: 16px; +} +.cal-list .cal-item.type-normal .info { + padding-left: 38px; +} +.cal-list .cal-item.type-normal strong, +.cal-list .cal-item.type-normal span { + display: inline; +} +.cal-list .cal-item.type-normal.small-mode span { + display: block; + margin-left: 0; +} +.cal-list .cal-item.type-normal.li-col1 { + margin-top: -40px; +} +.cal-list .cal-item .cal-icon { + position: absolute; + width: 40px; + height: 40px; + left: 10px; + top: 10px; +} +.cal-list .cal-item.li-col1 { + margin-top: -82px; +} +.cal-list.char-2-1 .type-character.li-idx-2, +.cal-list.char-3-1 .type-character.li-idx-2 { + margin-top: -82px; +} +.cal-list.char-3-2 .type-character.li-idx-3 { + margin-top: -82px; +} +.cal-list.char-4-2 .type-character.li-idx-3 { + margin-top: -166px; +} +.cal-list .type-weapon.li-idx-2 { + margin-top: -82px; +} +.calendar .now-line { + position: absolute; + top: 86px; + bottom: -18px; + width: 2px; + box-shadow: 0 0 5px 0 #fff; + background: #fff; + opacity: 0.8; +} +.calendar .now-line:after { + content: ""; + display: block; + width: 0; + height: 0; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-bottom: 20px solid #fff; + position: absolute; + bottom: -8px; + left: -9px; + transform: scaleY(0.7); + transform-origin: bottom center; +} +.calendar .now-line.line2 { + z-index: 3; + opacity: 0.5; + background: #d3bc8d; + width: 2px; + box-shadow: none; +} +.now-time { + text-align: center; + padding-top: 5px; + margin-bottom: 5px; +} +.now-time span { + color: #fff; + background: rgba(0, 0, 0, 0.6); + border-radius: 30px; + padding: 10px 15px; + border: 1px solid #fff; + display: inline-block; +} +.cal-abyss-cont { + padding-top: 15px; + height: 80px; + position: relative; +} +.cal-abyss-cont .cal-item { + border-radius: 0; + background: url("./imgs/abyss.jpg") #333465 top right no-repeat; + position: absolute; +} +.cal-abyss-cont .cal-item .info { + background: none; + color: #d3bc8d; + background-image: linear-gradient(to right, #333465, #333465 80%, rgba(51, 52, 101, 0) 100%); +} +.cal-abyss-cont .cal-item:before { + content: ""; + display: block; + width: 3px; + left: 0; + top: 1px; + bottom: 1px; + position: absolute; + background: #d3bc8d; + z-index: 8; +} +.cal-abyss-cont .cal-item:after { + box-shadow: 0 0 1px 0 #fff; + border-radius: 0; +} +.calendar-mode .for-list-mode { + display: none; +} +.list-mode .container { + width: 740px; +} +.list-mode .for-calendar-mode { + display: none; +} +.list-mode .cal-bg { + width: initial; +} +.list-mode .cal-list { + padding: 45px 10px 0; +} +.list-mode .calendar { + width: 700px; +} +.list-mode .cal-abyss-cont { + height: initial !important; +} +.list-mode .cal-item { + position: relative; + margin-left: 0 !important; + width: initial !important; + left: 0 !important; +} +.list-mode .now-line { + display: none; +} +.daily-talent { + display: flex; + flex-wrap: wrap; + margin: 5px 10px 0; + background: rgba(0, 0, 0, 0.5); + padding: 10px 9px 10px; + border-radius: 10px; +} +.daily-talent .item-icon { + overflow: visible; +} +.daily-talent .card { + width: 87px; + height: 105px; + margin: 10px 0 15px; +} +.daily-talent .card .item-icon { + width: 77px; + margin: 0 6px; + height: 82px; + padding-top: 5px; +} +.daily-talent .card .img { + width: 77px; + height: 77px; +} +.daily-talent .card .weekly { + position: absolute; + width: 24px; + height: 24px; + border-radius: 50%; + bottom: -10px; + right: -3px; + background-color: rgba(232, 226, 216, 0.9); + box-shadow: 0 0 2px 0 #000; + overflow: visible; +} +.daily-talent .card .weekly .weekly-icon { + width: 30px; + height: 30px; + margin: -3px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; +} +.daily-talent .card .banner { + height: 20px; + padding-top: 1px; + line-height: 20px; + color: #fff; + position: relative; + margin-bottom: 8px; +} +.daily-talent .card .banner .title { + margin-right: -50px; + width: calc(100% + 50px); + display: flex; + position: absolute; + top: 0; + left: 0; + z-index: 2; + text-shadow: 0 0 1px rgba(0, 0, 0, 0.8), 1px 1px 2px rgba(0, 0, 0, 0.8); + padding-left: 45px; + font-size: 18px; +} +.daily-talent .card .banner .icon { + width: 40px; + height: 40px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + display: inline-block; + position: absolute; + left: 0; + top: -8px; +} +.daily-talent .card .banner .line { + height: 6px; + width: 100%; + margin-top: 13px; +} +.daily-talent .card .banner .line.first { + margin-left: 35%; + width: 65%; + border-radius: 3px 0 0 3px; +} +.daily-talent .card .banner .line.last { + width: 94%; + border-radius: 0 3px 3px 0; +} +.daily-talent .card .banner.city-1 .line { + background: #37c9b8; +} +.daily-talent .card .banner.city-2 .line { + background: #bca244; +} +.daily-talent .card .banner.city-3 .line { + background: #ac60c9; +} +.daily-talent .card .banner.city-4 .line { + background: #54b640; +} +.daily-talent .card .banner.city-5 .line { + background: #557dd6; +} +/*# sourceMappingURL=calendar.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/calendar.html b/Yunzai/plugins/miao-plugin/resources/wiki/calendar.html new file mode 100644 index 0000000000000000000000000000000000000000..37316ef53c6d62a9d71ec0b304dd5ac42a6928c1 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/calendar.html @@ -0,0 +1,123 @@ +{{extend elemLayout}} + +{{block 'css'}} + +{{/block}} + +{{block 'main'}} +{{set weekName = '一二三四五六日'.split('')}} +
+
+ + + {{each dateList d}} + + {{/each}} + + + {{each dateList d}}{{each d.date dn di}} + + {{/each}} {{/each}} + + + {{each dateList d}}{{each d.date dn}} + + {{/each}} {{/each}} + +
{{d.month}}月
+ {{dn}}日 + 周{{weekName[d.week[di]]}} +
+ {{if game === 'gs'}} + {{each charBirth[`${d.month}-${dn}`] char}} +
+
+
+ {{char.name.length>=4?char.name:`${char.name}生日`}} +
+
+ {{/each}} + {{/if}} +
+
+
+ + + + + + + +
活动列表
+
+
+
+ {{each abyss li}} +
+
+ + {{li.title}} + {{li.label}} +
+
+ {{/each}} +
+ {{each list lis}} + {{each lis li idx}} +
+ {{if li.banner2}} + + {{else if li.banner}} + + {{/if}} +
+ {{if li.type === "character"}} + + {{else if li.icon}} + + {{else}} + + {{/if}} + {{li.title}} + {{li.label}} +
+
+ {{/each}} + {{/each}} +
+
+
+
+
+ 当前时间:{{nowTime}} +
+{{if game === 'gs'}} +
+ {{each charTalent talent}} + {{each talent.chars char idx}} +
+ +
+
+
+
+
+
+
+ {{/each}} + {{/each}} +
+{{/if}} +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/calendar.less b/Yunzai/plugins/miao-plugin/resources/wiki/calendar.less new file mode 100644 index 0000000000000000000000000000000000000000..693b2de010eaeefe507f554d8c54a2c8a8d1c00a --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/calendar.less @@ -0,0 +1,574 @@ +//linear-gradient(to right, rgba(232, 226, 216, 1), rgba(232, 226, 216, 1) 80%, rgba(232, 226, 216, 0) 100%); + +.linear-bg(@color) { + background-image: linear-gradient(to right, @color, @color 80%, fade(@color, 0) 100%); +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} + +body { + font-size: 18px; + color: #1e1f20; + transform: scale(1); + transform-origin: 0 0; + width: 996px; +} + +.container { + width: 996px; + padding: 10px 0px 10px 0px; + background-size: 100% 100%; +} + +.logo { + font-size: 18px; + text-align: center; + color: #fff; + margin: 20px 0 10px 0; +} + +.calendar { + min-height: 400px; + position: relative; + padding: 1px 0; + width: 956px; + margin: 20px; + box-shadow: 0 0 0 10px rgba(0, 0, 0, .6); + border-radius: 10px; +} + +.cal-bg { + position: absolute; + width: 956px; + top: 0; + left: 0; + right: 0; + bottom: 0; + text-align: center; + border-collapse: collapse; + height: 100%; + box-shadow: 0 0 1px 0 #fff inset; + border-radius: 10px; + overflow: hidden; + + table { + height: 100%; + } + + + .tr.thead { + background: rgba(0, 0, 0, .8); + height: 40px; + + td { + } + } + + td { + box-shadow: 0 0 1px 0 #fff; + + &.date { + width: 7.692%; + + span { + display: block; + line-height: 18px; + } + + span.date-num { + + } + + span.date-week { + line-height: 12px; + font-size: 12px; + color: #888; + } + + &.current-date { + background: #d3bc8e; + border: 1px solid #d3bc8e; + color: #000; + + span.date-week { + color: #000; + } + } + + + } + + &.line { + background: rgba(0, 0, 0, 0.4); + vertical-align: top; + + &.current-date { + background: rgba(211, 188, 142, .4) + } + } + } + + .card { + width: 65px; + height: 76px; + margin: 8px auto -4px; + + .img { + height: 60px; + } + + .char-name { + position: absolute; + bottom: 0; + left: 0; + right: 0; + line-height: 17px; + font-size: 12px; + background: #e8e2d8; + } + } +} + +.cal-list { + position: relative; + padding-top: 80px; + overflow: hidden; + + &.char-num-0 { + padding-top: 80px; + } + + &.char-num-1 { + padding-top: 160px; + } + + &.char-num-2 { + padding-top: 240px; + } + + &.char-num-3 { + padding-top: 320px; + } + + .cal-item { + margin-bottom: 15px; + border-radius: 5px; + white-space: nowrap; + text-overflow: ellipsis; + position: relative; + overflow: hidden; + background: rgba(232, 226, 216, 1); + z-index: 1; + + &:after { + content: ""; + display: block; + position: absolute; + left: 3px; + top: 3px; + right: 4px; + bottom: 4px; + box-shadow: 0 0 1px 0 #000 inset, 0 0 2px 0 #222a3b; + border-radius: 4px; + } + + .info { + position: relative; + display: inline-block; + padding: 15px 50px 15px 55px; + min-width: calc(100% - 400px); + border-radius: 5px; + .linear-bg(#E8E2D8); + } + + .banner { + position: absolute; + width: 100%; + max-width: 500px; + top: 0; + bottom: 0; + right: 0; + background-size: 100% auto; + background-position: left 40%; + + } + + strong { + display: block; + font-weight: normal; + } + + span { + display: block; + font-size: 12px; + } + + + &.type-character { + overflow: visible; + margin-top: 20px; + + .info { + padding-left: 65px; + + } + + .character-img { + height: 75px; + position: absolute; + bottom: 0; + left: 0; + z-index: 10; + + } + } + + &.type-normal { + margin-top: 5px; + margin-bottom: 5px; + + &:last-child { + margin-bottom: 15px; + } + + &:after { + display: none; + } + + + &:first-of-type { + margin-top: 20px; + } + + .info { + padding: 8px 20px 8px 15px; + line-height: 16px; + color: #4b5366; + } + + .cal-icon { + + width: 23px; + height: 23px; + top: 6px; + margin-left: -3px; + margin-right: 5px; + } + + strong { + font-size: 16px; + } + + .info { + padding-left: 38px; + } + + + strong, + span { + display: inline; + } + + + &.small-mode span { + display: block; + margin-left: 0; + } + + &.li-col1 { + margin-top: -40px; + } + } + + .cal-icon { + position: absolute; + width: 40px; + height: 40px; + left: 10px; + top: 10px; + } + + &.li-col1 { + margin-top: -82px; + } + } + + &.char-2-1, + &.char-3-1 { + .type-character.li-idx-2 { + margin-top: -82px; + } + } + + &.char-3-2 { + .type-character.li-idx-3 { + margin-top: -82px; + } + } + + &.char-4-2 { + .type-character.li-idx-3 { + margin-top: -166px; + } + } + + .type-weapon.li-idx-2 { + margin-top: -82px; + } + + +} + +.calendar .now-line { + position: absolute; + top: 86px; + bottom: -18px; + width: 2px; + box-shadow: 0 0 5px 0 #fff; + background: #fff; + opacity: .8; + + &:after { + content: ""; + display: block; + width: 0; + height: 0; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-bottom: 20px solid #fff; + position: absolute; + bottom: -8px; + left: -9px; + transform: scaleY(.7); + transform-origin: bottom center; + } + + &.line2 { + z-index: 3; + opacity: .5; + background: rgb(211, 188, 141); + width: 2px; + box-shadow: none; + + &:after { + } + } +} + +.now-time { + text-align: center; + padding-top: 5px; + margin-bottom: 5px; + + span { + color: #fff; + background: rgba(0, 0, 0, 0.6); + border-radius: 30px; + padding: 10px 15px; + border: 1px solid #fff; + display: inline-block; + } +} + +.cal-abyss-cont { + padding-top: 15px; + height: 80px; + position: relative; + + .cal-item { + border-radius: 0; + background: url("./imgs/abyss.jpg") #333465 top right no-repeat; + position: absolute; + + .info { + background: none; + color: rgba(211, 188, 141, 1); + .linear-bg(#333465); + } + + &:before { + content: ""; + display: block; + width: 3px; + left: 0; + top: 1px; + bottom: 1px; + position: absolute; + background: #d3bc8d; + z-index: 8; + + } + + &:after { + box-shadow: 0 0 1px 0 #fff; + border-radius: 0; + } + } +} + +.calendar-mode { + .for-list-mode { + display: none; + } +} + +.list-mode { + + .container { + width: 740px; + } + + .for-calendar-mode { + display: none; + } + + .cal-bg { + width: initial; + } + + .cal-list { + padding: 45px 10px 0; + } + + .calendar { + width: 700px; + } + + .cal-abyss-cont { + height: initial !important; + } + + .cal-item { + position: relative; + margin-left: 0 !important; + width: initial !important; + left: 0 !important; + } + + .now-line { + display: none; + } +} + +@width: 77px; + +.daily-talent { + display: flex; + flex-wrap: wrap; + margin: 5px 10px 0; + background: rgba(0, 0, 0, .5); + padding: 10px 9px 10px; + border-radius: 10px; + + + .item-icon { + overflow: visible; + } + + .card { + width: @width + 10px; + height: @width + 28px; + margin: 10px 0 15px; + + + .item-icon { + width: @width; + margin: 0 6px; + height: @width + 5px; + padding-top: 5px; + } + + .img { + width: @width; + height: @width; + } + + .weekly { + position: absolute; + width: 24px; + height: 24px; + border-radius: 50%; + bottom: -10px; + right: -3px; + background-color: rgba(232, 226, 216, 0.9); + box-shadow: 0 0 2px 0 #000; + overflow: visible; + + .weekly-icon { + width: 30px; + height: 30px; + margin: -3px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + } + } + + .banner { + height: 20px; + padding-top: 1px; + line-height: 20px; + color: #fff; + position: relative; + margin-bottom: 8px; + + .title { + margin-right: -50px; + width: calc(100% + 50px); + display: flex; + position: absolute; + top: 0; + left: 0; + z-index: 2; + text-shadow: 0 0 1px rgba(0, 0, 0, .8), 1px 1px 2px rgba(0, 0, 0, .8); + padding-left: 45px; + font-size: 18px; + } + + .icon { + width: 40px; + height: 40px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + display: inline-block; + position: absolute; + left: 0; + top: -8px; + } + + .line { + height: 6px; + width: 100%; + margin-top: 13px; + + &.first { + margin-left: 35%; + width: 65%; + border-radius: 3px 0 0 3px; + } + + &.last { + width: 94%; + border-radius: 0 3px 3px 0; + } + } + + .city(@name, @bg) { + &.city-@{name} .line { + background: @bg; + } + } + .city(1, #37c9b8); + .city(2, #bca244); + .city(3, #ac60c9); + .city(4, #54b640); + .city(5, #557dd6) + } + } +} diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/character-material.css b/Yunzai/plugins/miao-plugin/resources/wiki/character-material.css new file mode 100644 index 0000000000000000000000000000000000000000..646ad68db05c69ddb514617cb16f6a9a86be9e86 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/character-material.css @@ -0,0 +1,221 @@ +.font-YS { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.font-NZBZ { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +body { + width: 600px; +} +.container { + width: 600px; + padding: 0; + background-size: cover; + overflow: hidden; +} +.char-title { + height: 100px; + padding-right: 10px; +} +.char-title .char-name { + font-size: 40px; +} +.char-title .char-name span { + font-size: 28px; + padding-right: 10px; +} +.basic { + height: 500px; +} +.char-desc { + padding-left: 200px; + font-size: 14px; +} +.char-meta { + padding-left: 370px; +} +.detail { + right: 18px; +} +.detail .cont { + margin-right: 0; +} +.detail ul.char-attr li { + width: 250px; + padding-left: 20px; +} +.detail ul.char-attr li strong { + position: initial; + color: #d3bc8e; +} +.detail ul.char-attr li span { + color: #fff; + right: 20px; + text-align: right; + width: 150px; +} +.material-list { + display: flex; + padding: 5px; + position: absolute; + left: 10px; + bottom: 6px; + z-index: 5; +} +.material-list .num { + font-size: 12px; + text-align: center; + color: #fff; + text-shadow: 0 0 1px #000, 0 0 1px #000, 0 0 3px rgba(0, 0, 0, 0.8); + display: block; + height: 14px; + margin-left: -10px; + margin-right: -10px; + width: calc(100% + 20px); +} +.material-list .item-card { + width: 47px; + margin: 2px; + overflow: hidden; +} +.material-list .item-card .item-icon { + background-size: cover; + padding: 6px 4px 17px; +} +.material-list .item-card .item-bg { + background-size: contain; + background-position: center; +} +.material-list .item-card .item-title { + display: block; + font-size: 12px; + position: absolute; + color: #fff; + bottom: 0; + left: 0; + white-space: nowrap; + background: rgba(0, 0, 0, 0.5); + padding: 4px 0; + width: 68px; + text-align: center; + transform-origin: left bottom; + transform: scale(0.7); + text-shadow: 0 0 2px #000; +} +.talent-notice { + color: #fff; + font-size: 13px; + text-align: center; + padding: 3px; + text-shadow: 0 0 1px #000, 1px 1px 2px #000; +} +.talent-notice strong { + color: #d3bc8e; + font-weight: normal; +} +.cont .cont-title.border-less { + padding: 10px 15px 3px; +} +.talent-cont { + text-align: center; +} +.talent-cont strong { + color: #d3bc8e; +} +.weapon-list { + padding: 3px; +} +.weapon-list .item { + margin: 3px; +} +.char-holding { + display: flex; + padding: 8px; +} +.char-holding .cons-title { + height: 15px; + line-height: 15px; + font-size: 13px; + color: #d3bc8e; + text-shadow: 0 0 2px #000; +} +.char-pct { + width: 125px; + margin-right: 10px; + text-align: center; + position: relative; +} +.char-pct strong { + margin-top: 10px; + display: block; + height: 60px; + line-height: 60px; + font-size: 30px; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; +} +.char-pct span { + display: block; + font-size: 13px; + color: #d3bc8e; + height: 15px; + line-height: 15px; +} +.char-pct:after { + content: ""; + display: block; + width: 1px; + height: 50px; + position: absolute; + right: 1px; + top: 30px; + background: rgba(255, 255, 255, 0.8); + transform: scaleX(0.7); +} +.char-cons { + position: initial; + width: initial; +} +.char-cons .cons0 .talent-icon { + opacity: 0.3; +} +.char-cons .cons-item { + width: 60px; + text-align: center; +} +.char-cons .cons-item .talent-icon { + width: 60px; + height: 60px; + margin: 0 auto; +} +.char-cons .cons-num { + margin-top: -5px; + height: 25px; + line-height: 25px; + font-size: 16px; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; +} +.item-value { + color: #000; + text-align: center; + line-height: 20px; + font-size: 15px; +} +.item-title { + font-size: 12px; + transform: scale(0.9); + margin-top: -3px; +} +.artis-list .artis-count2 { + position: relative; +} +.artis-list .artis-count2 .item-bg { + transform: scale(0.7); + transform-origin: left top; +} +.artis-list .artis-count2 .item-bg.artis2 { + position: absolute; + left: 0; + top: 0; + transform-origin: right bottom; +} +/*# sourceMappingURL=character-material.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/character-material.html b/Yunzai/plugins/miao-plugin/resources/wiki/character-material.html new file mode 100644 index 0000000000000000000000000000000000000000..fcbeb1503422c9d6fc60fece2eca7025c003ff34 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/character-material.html @@ -0,0 +1,57 @@ +{{extend elemLayout}} + +{{block 'css'}} + + + +{{/block}} + +{{set weapon = data.weapon}} +{{set dataSource = data.dataSource}} + + +{{block 'main'}} +
+
+
+
+
{{data.title}} · {{data.name}}
+
{{@data.desc}}
+
+
+
+
    +
  • 武器类型 {{data.weaponTypeName}}
  • +
  • 命之座 {{data.astro}}
  • +
  • 生日 {{data.birthday}}
  • +
  • 归属 {{data.allegiance}}
  • +
  • 中文CV {{data.cncv}}
  • +
  • 日文CV {{data.jpcv}}
  • +
+
+
+
90级基础属性
+
    + {{each attr ds}} +
  • {{ds.title}} {{ds.value}}
  • + {{/each}} +
+
+
+
+
+ {{each materials ds}} +
+
{{ds.num}}
+
+
+
+
+
{{ds.label}}
+
+
+ {{/each}} +
+
+{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/character-material.less b/Yunzai/plugins/miao-plugin/resources/wiki/character-material.less new file mode 100644 index 0000000000000000000000000000000000000000..aadcf2f5edc1807e0222bfdee42fb34a90bb3c2f --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/character-material.less @@ -0,0 +1,278 @@ +@import "../common/base.less"; + +body { + width: 600px; +} + +.container { + width: 600px; + padding: 0; + background-size: cover; + overflow: hidden; + + & > .cont { + + } +} + +.char-title { + height: 100px; + padding-right: 10px; + + .char-name { + font-size: 40px; + + span { + font-size: 28px; + padding-right: 10px; + } + } +} + +.basic { + height: 500px; + + &:after { + + } +} + +.char-desc { + padding-left: 200px; + font-size: 14px; +} + + +.char-meta { + padding-left: 370px; + + .title { + + } +} + +.detail { + right: 18px; + + .cont { + margin-right: 0; + } + + ul.char-attr { + + li { + width: 250px; + padding-left: 20px; + + strong { + position: initial; + color: #d3bc8e; + } + + span { + color: #fff; + right: 20px; + text-align: right; + width: 150px; + } + } + } +} + +.material-list { + display: flex; + padding: 5px; + position: absolute; + left: 10px; + bottom: 6px; + z-index: 5; + + .num { + font-size: 12px; + text-align: center; + color: #fff; + text-shadow: 0 0 1px #000, 0 0 1px #000, 0 0 3px rgba(0, 0, 0, 0.8); + display: block; + height: 14px; + margin-left: -10px; + margin-right: -10px; + width: calc(100% + 20px) + } + + + .item-card { + width: 47px; + margin: 2px; + overflow: hidden; + + .item-icon { + background-size: cover; + padding: 6px 4px 17px; + } + + .item-bg { + background-size: contain; + background-position: center; + } + + .item-title { + display: block; + font-size: 12px; + position: absolute; + color: #fff; + bottom: 0; + left: 0; + white-space: nowrap; + background: rgba(0, 0, 0, 0.5); + padding: 4px 0; + width: 68px; + text-align: center; + transform-origin: left bottom; + transform: scale(.7); + text-shadow: 0 0 2px #000; + } + } +} + +.talent-notice { + color: #fff; + font-size: 13px; + text-align: center; + padding: 3px; + text-shadow: 0 0 1px #000, 1px 1px 2px #000; + + strong { + color: #d3bc8e; + font-weight: normal; + } +} + +.cont .cont-title.border-less { + padding: 10px 15px 3px; +} + +.talent-cont { + text-align: center; + + strong { + color: #d3bc8e; + } +} + +.weapon-list { + padding: 3px; + + .item { + margin: 3px; + } +} + +.char-holding { + display: flex; + padding: 8px; + + .cons-title { + height: 15px; + line-height: 15px; + font-size: 13px; + color: #d3bc8e; + text-shadow: 0 0 2px #000; + } +} + +.char-pct { + width: 125px; + margin-right: 10px; + text-align: center; + position: relative; + + strong { + margin-top: 10px; + display: block; + height: 60px; + line-height: 60px; + font-size: 30px; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; + } + + span { + display: block; + font-size: 13px; + color: #d3bc8e; + height: 15px; + line-height: 15px; + } + + &:after { + content: ""; + display: block; + width: 1px; + height: 50px; + position: absolute; + right: 1px; + top: 30px; + background: rgba(255, 255, 255, .8); + transform: scaleX(.7); + } +} + +.char-cons { + position: initial; + width: initial; + + .cons0 { + .talent-icon { + opacity: .3; + } + } + + .cons-item { + width: 60px; + text-align: center; + + .talent-icon { + width: 60px; + height: 60px; + margin: 0 auto; + } + } + + .cons-num { + margin-top: -5px; + height: 25px; + line-height: 25px; + font-size: 16px; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; + } +} + +.item-value { + color: #000; + text-align: center; + line-height: 20px; + font-size: 15px; +} + +.item-title { + font-size: 12px; + transform: scale(.9); + margin-top: -3px; +} + +.artis-list { + .artis-count2 { + position: relative; + + .item-bg { + transform: scale(.7); + transform-origin: left top; + + &.artis2 { + position: absolute; + left: 0; + top: 0; + transform-origin: right bottom; + } + } + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/character-talent.css b/Yunzai/plugins/miao-plugin/resources/wiki/character-talent.css new file mode 100644 index 0000000000000000000000000000000000000000..eb12eef9cdb2d135d924d2f226499906ad7d0941 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/character-talent.css @@ -0,0 +1,371 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} +body { + font-size: 18px; + color: #1e1f20; + transform: scale(1); + transform-origin: 0 0; +} +.container { + width: 800px; + padding: 0 0 10px 0; + background-color: #ececec; +} +.head-box { + box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.25); + width: 100%; + height: 355px; + overflow: hidden; + position: relative; + background-size: cover; + color: #fff; + text-shadow: 0 0 3px rgba(0 0 0 / 70%); + margin: 0 0 25px; + border-radius: 0; +} +.head-box .head { + width: 128px; + height: 128px; + border-radius: 50%; + border: 3px solid #f0efe0; + box-shadow: 0 0 5px 6px rgba(0, 0, 0, 0.1); + position: absolute; + left: 52px; + top: 35px; + background-size: cover; +} +.head-box .head img { + width: 122px; + height: 122px; + border-radius: 50%; +} +.head-box .head-astro { + position: absolute; + width: 128px; + top: 198px; + font-size: 17px; + left: 52px; + text-align: center; +} +.head-box .head-icon { + position: absolute; + left: 35px; + top: 238px; + width: 172px; + background: rgba(0, 0, 0, 0.2); + height: 52px; + border-radius: 26px; +} +.head-box .head-icon img { + width: 42px; + height: 42px; + float: left; + margin: 4px 6px; +} +.head-box .head-detail { + position: absolute; + left: 225px; + top: 35px; + width: 540px; + font-size: 18px; +} +.head-box .name { + font-size: 38px; +} +.head-box .desc { + font-size: 20px; + margin-top: 17px; + height: 86px; +} +.head-box .ascension { + font-size: 17px; + height: 43px; +} +.head-box .material { + display: block; +} +.head-box .meterial_group { + float: left; + margin-right: 25px; +} +.head-box .material span { + display: block; + height: 24px; + font-size: 10px; +} +.head-box .meterial_group div { + width: 34px; + height: 40px; + overflow: hidden; + padding: 2px; + border-radius: 4px; + float: left; + background-size: cover; + margin-right: 5px; + box-shadow: 0 0 3px 0px rgba(0, 0, 0, 0.2); +} +.head-box .material span.meterial_desc { + display: block; + overflow: hidden; + clear: left; + padding-top: 5px; +} +.head-box .meterial_group div img { + width: 30px; + vertical-align: baseline; + vertical-align: -webkit-baseline-middle; +} +.head-box .genshin_logo { + position: absolute; + top: 1px; + right: 15px; + width: 97px; +} +.base_info { + position: relative; + padding-left: 10px; +} +.uid:before { + content: " "; + position: absolute; + width: 5px; + height: 24px; + border-radius: 1px; + left: 0; + top: 0; + background: #d3bc8d; +} +.head-box .data-box { + position: absolute; + left: 0; + right: 0; + top: 180px; + color: #000; + text-shadow: none; +} +.head-box .data-box .tab-label { + width: 170px; + left: 20px; + border-radius: 8px; + background: #272f43; +} +.data-box { + border-radius: 15px; + margin: 30px 15px; + padding: 30px 15px 5px 15px; + background: rgba(245, 245, 245, 0.8); + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.15); + position: relative; + background-size: contain; + color: #000; +} +.tab-label { + position: absolute; + top: -18px; + left: -8px; + background: #d4b98c; + color: #fff; + font-size: 20px; + padding: 6px 20px; + border-radius: 15px 0px 15px 15px; + z-index: 20; +} +.data-line { + display: flex; + justify-content: space-around; + margin-bottom: 14px; +} +.data_line_item { + flex: 1; + text-align: center; + /*margin: 0 20px;*/ +} +.num { + font-size: 40px; +} +.data-box .label { + font-size: 18px; + color: #7f858a; + line-height: 1; + margin-top: 3px; + text-shadow: none; + white-space: nowrap; +} +.talent-box { + border-radius: 25px; + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.15); + position: relative; + margin: 20px 15px 15px 15px; + background-size: 100% 100%; + overflow: hidden; +} +.talent-detail { + padding: 30px 15px 5px 15px; + background: url(./imgs/card-bg.png) left top repeat-x; + background-size: auto 100%; + margin: 0; +} +.talent-info { + position: relative; + padding-left: 140px; + font-size: 18px; + font-weight: normal; + min-height: 80px; + padding-bottom: 15px; + color: #fff; +} +.talent-icon { + width: 120px; + height: 120px; + padding: 5px; + display: table; + border-radius: 50%; + position: absolute; + left: 0px; + top: -10px; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; + z-index: 90; +} +.talent-icon img { + width: 46%; + height: 46%; + position: absolute; + top: 50%; + left: 50%; + margin: -22% 0 0 -23%; +} +.talent-info .talent-detail-table { + margin-left: -140px; +} +.talent-name { + display: block; + font-size: 30px; + margin: 0 0 15px 0; + color: #d3bc8e; + line-height: 45px; + font-weight: bold; +} +.talent-desc { + font-size: 18px; + line-height: 26px; + padding-right: 10px; +} +.talent-desc nobr { + color: #ffe699; + display: inline-block; + border-radius: 4px; + text-align: center; + padding: 0 3px; + margin: 0 2px; +} +.talent-desc h3 { + margin-top: 15px; + margin-bottom: 5px; + display: block; + font-weight: bold; + color: #d3bc8e; +} +.talent-desc i { + display: block; + color: #aaa; + padding-top: 10px; + margin-bottom: -5px; +} +.talent-line { + position: relative; + min-height: 100px; + margin-top: 35px; + margin-bottom: 25px; +} +.talent-line:first-child { + margin-top: 0; + margin-bottom: 0; +} +.talent-table { + text-align: center; + border-collapse: collapse; + margin: 10px -10px -5px -15px; + border-radius: 0 0 10px 10px; + display: table; + overflow: hidden; + width: calc(100% + 30px); + color: #fff; +} +.talent-table .th { + min-width: 0; + text-align: center; +} +.talent-table .td { + font-size: 15px; + white-space: normal; +} +.talent-table .td.colspan { + font-size: 16px; +} +.talent-table .talent-name { + min-width: 100px; + font-size: 18px; +} +.talent-table .talent-name span.unit { + display: block; + font-size: 13px; + color: #ccc; + font-weight: normal; +} +.talent-table .td, +.talent-table .th { + padding: 7px 3px; + line-height: 24px; +} +.talent-table .tr:last-child .td { + padding-bottom: 12px; +} +.talent-table .tr > div:last-child { + padding-right: 5px; +} +.passive-talent .talent-table { + display: none; + margin-right: 20px; + width: 100%; + margin-bottom: -15px; +} +.logo { + font-size: 24px; + text-align: center; + color: #7994a7; + margin: 20px 0 10px 0; +} +.talent-common-info { + display: flex; + flex-wrap: wrap; + padding-left: 135px; + margin-bottom: -5px; +} +.talent-common-info > div { + display: flex; + margin: 4px; + border-radius: 5px; + white-space: nowrap; + box-shadow: 1px 1px 2px 0 rgba(0, 0, 0, 0.8); +} +.talent-common-info > div strong, +.talent-common-info > div span { + padding: 5px 8px; +} +.talent-common-info > div strong { + background: rgba(0, 0, 0, 0.4); + color: #d3bc8e; + border-radius: 5px 0 0 5px; +} +.talent-common-info > div span { + background: rgba(50, 50, 50, 0.4); + border-radius: 0 5px 5px 0; + color: #fff; +} +/*# sourceMappingURL=character-talent.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/character-talent.html b/Yunzai/plugins/miao-plugin/resources/wiki/character-talent.html new file mode 100644 index 0000000000000000000000000000000000000000..181c85524d8a35c0f8d7fb03c649ef8d54b8db3d --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/character-talent.html @@ -0,0 +1,90 @@ +{{extend elemLayout}} + +{{block 'css'}} + +{{/block}} + +{{block 'main'}} + +
+
+ +
+
+
+ {{if game === 'gs'}} + {{title}}·{{name}} + {{else}} + {{name}} + {{/if}} +
+
+ {{if game === 'gs'}} + {{@desc}} + {{else}} + {{detail.desc}} + {{/if}} +
+
+ {{ if line[0]?.num !== 'NaN'}} +
+
90级基础数据
+
+ {{each line item}} +
+
{{item.num}}
+
{{item.label}}
+
+ {{/each}} +
+
+ {{else}} +
+
90级基础数据
+
+ 暂无详细数据 +
+
+ {{/if}} +
+ + +{{if mode == "talent"}} + +{{each detail.talent talent type}} +
+
+ {{set minLv = game === 'gs' ? 4 : (type==='a' || type ==='a2'?1:4) }} + {{set maxLv = game === 'gs' ? (type==='a'?11:13) : (type==='a' || type ==='a2'?7:12)}} + <% include(_tpl_path+'/talent-detail.html', [talent, {_res_path,lvs,type,icon:imgs[type],minLv,maxLv,game}]) %> +
+
+{{/each}} + +
+
+ {{if game === 'gs'}} + {{each detail.passive pass idx}} + <% include(_tpl_path+'/talent-detail.html', [pass, {_res_path,icon:imgs['passive'+idx],game}]) %> + {{/each}} + {{else}} + {{each detail.treeData treeData idx}} + {{if treeData.type === 'skill'}} + <% include(_tpl_path+'/talent-detail.html', [treeData, {_res_path,icon:imgs['tree'+treeData.idx],game}]) %> + {{/if}} + {{/each}} + {{/if}} +
+
+{{/if}} + +{{if mode == "cons"}} +
+
+ {{each detail.cons con idx}} + <% include(_tpl_path+'/talent-detail.html', [con, {_res_path,lvs,type,icon:imgs['cons'+idx],game}]) %> + {{/each}} +
+
+{{/if}} +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/character-talent.less b/Yunzai/plugins/miao-plugin/resources/wiki/character-talent.less new file mode 100644 index 0000000000000000000000000000000000000000..bf4ab406675260289fa1151bb9446b317b23f899 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/character-talent.less @@ -0,0 +1,431 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; +} + +body { + font-size: 18px; + color: #1e1f20; + transform: scale(1); + transform-origin: 0 0; +} + +.container { + width: 800px; + padding: 0 0 10px 0; + background-color: #ececec; +} + +.head-box { + box-shadow: 0 5px 5px 0 rgb(0 0 0 / 25%); + width: 100%; + height: 355px; + overflow: hidden; + position: relative; + background-size: cover; + color: #fff; + text-shadow: 0 0 3px rgba(0 0 0 / 70%); + margin: 0 0 25px; + border-radius: 0; + + + .head { + position: absolute; + width: 128px; + height: 128px; + border-radius: 50%; + border: 3px solid #f0efe0; + box-shadow: 0 0 5px 6px rgb(0 0 0 / 10%); + position: absolute; + left: 52px; + top: 35px; + background-size: cover; + + img { + width: 122px; + height: 122px; + border-radius: 50%; + } + } + + .head-astro { + position: absolute; + width: 128px; + top: 198px; + font-size: 17px; + left: 52px; + text-align: center; + } + + .head-icon { + position: absolute; + left: 35px; + top: 238px; + width: 172px; + background: rgba(0, 0, 0, 0.2); + height: 52px; + border-radius: 26px; + + img { + width: 42px; + height: 42px; + float: left; + margin: 4px 6px; + } + } + + .head-detail { + position: absolute; + left: 225px; + top: 35px; + width: 540px; + font-size: 18px; + } + + .name { + font-size: 38px; + } + + .desc { + font-size: 20px; + margin-top: 17px; + height: 86px; + } + + .ascension { + font-size: 17px; + height: 43px; + } + + .material { + display: block; + } + + .meterial_group { + float: left; + margin-right: 25px; + } + + .material span { + display: block; + height: 24px; + font-size: 10px; + } + + .meterial_group div { + width: 34px; + height: 40px; + overflow: hidden; + padding: 2px; + border-radius: 4px; + float: left; + background-size: cover; + margin-right: 5px; + box-shadow: 0 0 3px 0px rgb(0 0 0 / 20%); + } + + .material span.meterial_desc { + display: block; + overflow: hidden; + clear: left; + padding-top: 5px; + } + + .meterial_group div img { + width: 30px; + vertical-align: baseline; + vertical-align: -webkit-baseline-middle; + } + + .genshin_logo { + position: absolute; + top: 1px; + right: 15px; + width: 97px; + } +} + +.base_info { + position: relative; + padding-left: 10px; +} + +.uid:before { + content: " "; + position: absolute; + width: 5px; + height: 24px; + border-radius: 1px; + left: 0; + top: 0; + background: #d3bc8d; +} + +.head-box .data-box { + position: absolute; + left: 0; + right: 0; + top: 180px; + color: #000; + text-shadow: none; + + .tab-label { + width: 170px; + left: 20px; + border-radius: 8px; + background: #272f43; + } +} + +.data-box { + border-radius: 15px; + margin: 30px 15px; + padding: 30px 15px 5px 15px; + background: rgba(245, 245, 245, 0.8); + box-shadow: 0 5px 10px 0 rgb(0 0 0 / 15%); + position: relative; + background-size: contain; + color: #000; +} + +.tab-label { + position: absolute; + top: -18px; + left: -8px; + background: #d4b98c; + color: #fff; + font-size: 20px; + padding: 6px 20px; + border-radius: 15px 0px 15px 15px; + z-index: 20; +} + +.data-line { + display: flex; + justify-content: space-around; + margin-bottom: 14px; +} + +.data_line_item { + flex: 1; + text-align: center; + /*margin: 0 20px;*/ +} + +.num { + font-size: 40px; +} + +.data-box .label { + font-size: 18px; + color: #7f858a; + line-height: 1; + margin-top: 3px; + text-shadow: none; + white-space: nowrap; +} + +.talent-box { + border-radius: 25px; + box-shadow: 0 5px 10px 0 rgb(0 0 0 / 15%); + position: relative; + margin: 20px 15px 15px 15px; + background-size: 100% 100%; + overflow: hidden; +} + +.talent-detail { + padding: 30px 15px 5px 15px; + background: url(./imgs/card-bg.png) left top repeat-x; + background-size: auto 100%; + margin: 0; +} + +.talent-info { + position: relative; + padding-left: 140px; + font-size: 18px; + font-weight: normal; + min-height: 80px; + padding-bottom: 15px; + color: #fff; +} + +.talent-icon { + width: 120px; + height: 120px; + padding: 5px; + display: table; + border-radius: 50%; + position: absolute; + left: 0px; + top: -10px; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; + z-index: 90; +} + +.talent-icon img { + width: 46%; + height: 46%; + position: absolute; + top: 50%; + left: 50%; + margin: -22% 0 0 -23%; +} + +.talent-info .talent-detail-table { + margin-left: -140px; +} + +.talent-name { + display: block; + font-size: 30px; + margin: 0 0 15px 0; + color: #d3bc8e; + line-height: 45px; + font-weight: bold; +} + +.talent-desc { + font-size: 18px; + line-height: 26px; + padding-right: 10px; + + nobr { + color: #ffe699; + display: inline-block; + border-radius: 4px; + text-align: center; + padding: 0 3px; + margin: 0 2px; + } + + h3 { + margin-top: 15px; + margin-bottom: 5px; + display: block; + font-weight: bold; + color: #d3bc8e; + } + + i { + display: block; + color: #aaa; + padding-top: 10px; + margin-bottom: -5px; + } +} + +.talent-line { + position: relative; + min-height: 100px; + margin-top: 35px; + margin-bottom: 25px; +} + +.talent-line:first-child { + margin-top: 0; + margin-bottom: 0; +} + +.talent-table { + text-align: center; + border-collapse: collapse; + margin: 10px -10px -5px -15px; + border-radius: 0 0 10px 10px; + display: table; + overflow: hidden; + width: calc(100% + 30px); + color: #fff; + + .th { + min-width: 0; + text-align: center; + } + + .td { + font-size: 15px; + white-space: normal; + + &.colspan { + font-size: 16px; + } + } + + .talent-name { + min-width: 100px; + font-size: 18px; + + span.unit { + display: block; + font-size: 13px; + color: #ccc; + font-weight: normal; + } + } + + .td, .th { + padding: 7px 3px; + line-height: 24px; + } + + .tr:last-child .td { + padding-bottom: 12px; + } + + .tr > div:last-child { + padding-right: 5px; + } + +} + + +.passive-talent .talent-table { + display: none; + margin-right: 20px; + width: 100%; + margin-bottom: -15px; +} + + +.logo { + font-size: 24px; + text-align: center; + color: #7994a7; + margin: 20px 0 10px 0; +} + +.talent-common-info { + display: flex; + flex-wrap: wrap; + padding-left: 135px; + margin-bottom: -5px; + + & > div { + display: flex; + margin: 4px; + border-radius: 5px; + white-space: nowrap; + box-shadow: 1px 1px 2px 0 rgba(0, 0, 0, .8); + + strong, span { + padding: 5px 8px; + } + + strong { + background: rgba(0, 0, 0, 0.4); + color: #d3bc8e; + border-radius: 5px 0 0 5px; + } + + span { + background: rgba(50, 50, 50, 0.4); + border-radius: 0 5px 5px 0; + color: #fff; + } + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/character-wiki.css b/Yunzai/plugins/miao-plugin/resources/wiki/character-wiki.css new file mode 100644 index 0000000000000000000000000000000000000000..3c1795407e8973d7de81c82fb081226610958bae --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/character-wiki.css @@ -0,0 +1,227 @@ +.font-YS { + font-family: Number, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +.font-NZBZ { + font-family: Number, "印品南征北战NZBZ体", NZBZ, "汉仪文黑-65W", YS, PingFangSC-Medium, "PingFang SC", sans-serif; +} +body { + width: 600px; +} +.container { + width: 600px; + padding: 0; + background-size: cover; + overflow: hidden; +} +.char-title { + height: 100px; + padding-right: 10px; +} +.char-title .char-name { + font-size: 40px; +} +.char-title .char-name span { + font-size: 28px; + padding-right: 10px; +} +.basic { + height: 500px; +} +.char-desc { + padding-left: 200px; + font-size: 14px; +} +.char-meta { + padding-left: 370px; +} +.detail { + right: 18px; +} +.detail .cont { + margin-right: 0; +} +.detail ul.char-attr li { + width: 250px; + padding-left: 20px; +} +.detail ul.char-attr li strong { + color: #d3bc8e; + width: 85px; + font-weight: normal; +} +.detail ul.char-attr li span { + color: #fff; + text-align: right; + width: 130px; +} +.material-list { + display: flex; + padding: 5px; + position: absolute; + left: 10px; + bottom: 6px; + z-index: 5; +} +.material-list .num { + font-size: 12px; + text-align: center; + color: #fff; + text-shadow: 0 0 1px #000, 0 0 1px #000, 0 0 3px rgba(0, 0, 0, 0.8); + display: block; + height: 14px; + margin-left: -10px; + margin-right: -10px; + width: calc(100% + 20px); +} +.material-list .item-card { + width: 47px; + margin: 2px; + overflow: hidden; +} +.material-list .item-card .item-icon { + background-size: cover; + padding: 6px 4px 17px; +} +.material-list .item-card .item-bg { + background-size: contain; + background-position: center; +} +.material-list .item-card .item-title { + display: block; + font-size: 12px; + position: absolute; + color: #fff; + bottom: 0; + left: 0; + white-space: nowrap; + background: rgba(0, 0, 0, 0.5); + padding: 4px 0; + width: 68px; + text-align: center; + transform-origin: left bottom; + transform: scale(0.7); + text-shadow: 0 0 2px #000; +} +.talent-notice { + color: #fff; + font-size: 13px; + text-align: center; + padding: 3px; + text-shadow: 0 0 1px #000, 1px 1px 2px #000; +} +.talent-notice strong { + color: #d3bc8e; + font-weight: normal; +} +.cont .cont-title.border-less { + padding: 10px 15px 3px; +} +.talent-cont { + text-align: center; +} +.talent-cont strong { + color: #d3bc8e; +} +.char-holding { + display: flex; + padding: 8px; +} +.char-holding .cons-title { + height: 15px; + line-height: 15px; + font-size: 13px; + color: #d3bc8e; + text-shadow: 0 0 2px #000; +} +.char-pct { + width: 125px; + margin-right: 10px; + text-align: center; + position: relative; +} +.char-pct strong { + margin-top: 10px; + display: block; + height: 60px; + line-height: 60px; + font-size: 30px; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; +} +.char-pct span { + display: block; + font-size: 13px; + color: #d3bc8e; + height: 15px; + line-height: 15px; +} +.char-pct:after { + content: ""; + display: block; + width: 1px; + height: 50px; + position: absolute; + right: 1px; + top: 30px; + background: rgba(255, 255, 255, 0.8); + transform: scaleX(0.7); +} +.char-cons { + position: initial; + width: initial; +} +.char-cons .cons0 .talent-icon { + opacity: 0.3; +} +.char-cons .cons-item { + width: 60px; + text-align: center; +} +.char-cons .cons-item .talent-icon { + width: 60px; + height: 60px; + margin: 0 auto; +} +.char-cons .cons-num { + margin-top: -5px; + height: 25px; + line-height: 25px; + font-size: 16px; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; +} +.item-value { + color: #000; + text-align: center; + line-height: 20px; + font-size: 15px; +} +.item-title { + font-size: 12px; + transform: scale(0.9); + margin-top: -3px; +} +.weapon-list { + padding: 3px; +} +.weapon-list .item { + margin: 3px 3px 3px 4px; + width: 74px; +} +.artis-list .item-bg { + background-size: contain; + background-position: center; + transform: scale(0.92); +} +.artis-list .artis-count2 { + position: relative; +} +.artis-list .artis-count2 .item-bg { + transform: scale(0.65); + transform-origin: left top; +} +.artis-list .artis-count2 .item-bg.artis2 { + position: absolute; + left: 0; + top: 0; + transform-origin: right bottom; +} +/*# sourceMappingURL=character-wiki.css.map */ \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/character-wiki.html b/Yunzai/plugins/miao-plugin/resources/wiki/character-wiki.html new file mode 100644 index 0000000000000000000000000000000000000000..f6ec85474f55f29788564dfb500736cec6560291 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/character-wiki.html @@ -0,0 +1,129 @@ +{{extend elemLayout}} + +{{block 'css'}} + + + +{{/block}} + +{{set weapon = data.weapon}} +{{set dataSource = data.dataSource}} + + +{{block 'main'}} +
+
+
+
+
{{data.title}} · {{data.name}}
+
{{@data.desc}}
+
+
+
+
    +
  • 武器类型 {{data.weaponTypeName}}
  • +
  • 命之座 {{data.astro}}
  • +
  • 生日 {{data.birthday}}
  • +
  • 归属 {{data.allegiance}}
  • +
  • 中文CV {{data.cncv}}
  • +
  • 日文CV {{data.jpcv}}
  • +
+
+
+
90级基础属性{{if data.star}}({{data.star}}星){{/if}}
+
    + {{each attr ds}} +
  • {{ds.title}} {{ds.value}}
  • + {{/each}} +
+
+
+
+
+ {{each materials ds}} +
+
{{ds.num}}
+
+
+
+
+
{{ds.label}}
+
+
+ {{/each}} +
+
+ +{{if holding.num}} +{{set cNum ='零一二三四五满'.split('')}} +
+
+
+ {{holding.num}} +
角色持有率
+
+
+ {{each holding.cons cons}} +
+
+ {{if cons.cons > 0}} +
+ {{else}} +
+ {{/if}} +
+
{{cons.num}}
+
{{cNum[cons.cons]}}命
+
+ {{/each}} +
+
+
+{{/if}} + +
输入#{{data.abbr}}天赋、#{{data.abbr}}命座可查看详细天赋/命座信息
+{{set weapons = usage.weapons || [] }} +{{if weapons.length >0}} +
+
常用武器
+
+ {{each weapons weapon idx}} + {{if idx <7}} +
+
+
+
+
{{weapon.value}}
+
{{weapon.abbr}}
+
+ {{/if}} + {{/each}} +
+
+{{/if}} +{{set artis = usage.artis || [] }} +{{if artis.length >0}} +
+
常用圣遗物持有率、武器、圣遗物统计来自胡桃API,未经允许请勿使用此数据
+
+ {{each artis arti idx}} + {{if idx <7}} +
+
+ {{each arti.imgs img idx}} +
+ {{/each}} +
+
{{arti.value}}
+
{{arti.title}}
+
+ {{/if}} + {{/each}} +
+
+
+{{/if}} + +{{/block}} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/character-wiki.less b/Yunzai/plugins/miao-plugin/resources/wiki/character-wiki.less new file mode 100644 index 0000000000000000000000000000000000000000..dc2ad3a373f519251d27359d265ca037770a6eb5 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/resources/wiki/character-wiki.less @@ -0,0 +1,285 @@ +@import "../common/base.less"; + +body { + width: 600px; +} + +.container { + width: 600px; + padding: 0; + background-size: cover; + overflow: hidden; + + & > .cont { + + } +} + +.char-title { + height: 100px; + padding-right: 10px; + + .char-name { + font-size: 40px; + + span { + font-size: 28px; + padding-right: 10px; + } + } +} + +.basic { + height: 500px; + + &:after { + + } +} + +.char-desc { + padding-left: 200px; + font-size: 14px; +} + + +.char-meta { + padding-left: 370px; + + .title { + + } +} + +.detail { + right: 18px; + + .cont { + margin-right: 0; + } + + ul.char-attr { + + li { + width: 250px; + padding-left: 20px; + + strong { + color: #d3bc8e; + width: 85px; + font-weight: normal; + } + + span { + color: #fff; + text-align: right; + width: 130px; + } + } + } +} + +.material-list { + display: flex; + padding: 5px; + position: absolute; + left: 10px; + bottom: 6px; + z-index: 5; + + .num { + font-size: 12px; + text-align: center; + color: #fff; + text-shadow: 0 0 1px #000, 0 0 1px #000, 0 0 3px rgba(0, 0, 0, 0.8); + display: block; + height: 14px; + margin-left: -10px; + margin-right: -10px; + width: calc(100% + 20px) + } + + + .item-card { + width: 47px; + margin: 2px; + overflow: hidden; + + .item-icon { + background-size: cover; + padding: 6px 4px 17px; + } + + .item-bg { + background-size: contain; + background-position: center; + } + + .item-title { + display: block; + font-size: 12px; + position: absolute; + color: #fff; + bottom: 0; + left: 0; + white-space: nowrap; + background: rgba(0, 0, 0, 0.5); + padding: 4px 0; + width: 68px; + text-align: center; + transform-origin: left bottom; + transform: scale(.7); + text-shadow: 0 0 2px #000; + } + } +} + +.talent-notice { + color: #fff; + font-size: 13px; + text-align: center; + padding: 3px; + text-shadow: 0 0 1px #000, 1px 1px 2px #000; + + strong { + color: #d3bc8e; + font-weight: normal; + } +} + +.cont .cont-title.border-less { + padding: 10px 15px 3px; +} + +.talent-cont { + text-align: center; + + strong { + color: #d3bc8e; + } +} + +.char-holding { + display: flex; + padding: 8px; + + .cons-title { + height: 15px; + line-height: 15px; + font-size: 13px; + color: #d3bc8e; + text-shadow: 0 0 2px #000; + } +} + +.char-pct { + width: 125px; + margin-right: 10px; + text-align: center; + position: relative; + + strong { + margin-top: 10px; + display: block; + height: 60px; + line-height: 60px; + font-size: 30px; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; + } + + span { + display: block; + font-size: 13px; + color: #d3bc8e; + height: 15px; + line-height: 15px; + } + + &:after { + content: ""; + display: block; + width: 1px; + height: 50px; + position: absolute; + right: 1px; + top: 30px; + background: rgba(255, 255, 255, .8); + transform: scaleX(.7); + } +} + +.char-cons { + position: initial; + width: initial; + + .cons0 { + .talent-icon { + opacity: .3; + } + } + + .cons-item { + width: 60px; + text-align: center; + + .talent-icon { + width: 60px; + height: 60px; + margin: 0 auto; + } + } + + .cons-num { + margin-top: -5px; + height: 25px; + line-height: 25px; + font-size: 16px; + text-shadow: 0 0 1px #000, 1px 1px 3px #000; + } +} + +.item-value { + color: #000; + text-align: center; + line-height: 20px; + font-size: 15px; +} + +.item-title { + font-size: 12px; + transform: scale(.9); + margin-top: -3px; +} + +.weapon-list { + padding: 3px; + + .item { + margin: 3px 3px 3px 4px; + width: 74px; + } +} + +.artis-list { + .item-bg { + background-size: contain; + background-position: center; + transform: scale(.92); + } + + .artis-count2 { + position: relative; + + .item-bg { + transform: scale(.65); + transform-origin: left top; + + &.artis2 { + position: absolute; + left: 0; + top: 0; + transform-origin: right bottom; + } + } + } +} \ No newline at end of file diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/imgs/abyss-icon.png b/Yunzai/plugins/miao-plugin/resources/wiki/imgs/abyss-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f658b5142e066a386ee6903e99d12bbfb69a0cdc Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/wiki/imgs/abyss-icon.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/imgs/abyss.jpg b/Yunzai/plugins/miao-plugin/resources/wiki/imgs/abyss.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a9e67f7ad8f599c381da13b1e192a7208d57e6b9 Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/wiki/imgs/abyss.jpg differ diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/imgs/calendar-icon.png b/Yunzai/plugins/miao-plugin/resources/wiki/imgs/calendar-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..46b3ac5523de8a77c57a969da7f194a3e5a0d7ae Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/wiki/imgs/calendar-icon.png differ diff --git a/Yunzai/plugins/miao-plugin/resources/wiki/imgs/card-bg.png b/Yunzai/plugins/miao-plugin/resources/wiki/imgs/card-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..036d416e692030f7c0a8b07d30c5da5c4598dece Binary files /dev/null and b/Yunzai/plugins/miao-plugin/resources/wiki/imgs/card-bg.png differ diff --git a/Yunzai/plugins/miao-plugin/tools/web.js b/Yunzai/plugins/miao-plugin/tools/web.js new file mode 100644 index 0000000000000000000000000000000000000000..aedb808004bfa7191a610f1dda0e4d7e30c6aa79 --- /dev/null +++ b/Yunzai/plugins/miao-plugin/tools/web.js @@ -0,0 +1,76 @@ +import express from 'express' +import template from 'express-art-template' +import fs from 'fs' +import lodash from 'lodash' + +/* +* npm run app web-debug开启Bot后 +* 可另外通过 npm run web 开启浏览器调试 +* 访问 http://localhost:8000/ 即可看到对应页面 +* 页面内的资源需使用 {{_res_path}}来作为resources目录的根目录 +* 可编辑模板与页面查看效果 +* todo: 预览页面的热更 +* +* */ + +let app = express() + +let _path = process.cwd() + +app.engine('html', template) +app.set('views', _path + '/resources/') +app.set('view engine', 'art') +app.use(express.static(_path + '/resources')) +app.use('/plugins', express.static('plugins')) + +app.get('/', function (req, res) { + let pluginList = fs.readdirSync(_path + '/temp/ViewData/') || [] + let html = [ + '在npm run web-dev模式下触发截图消息后,可在下方选择页面进行调试', + '如果页面内资源路径不正确请使用{{_res_path}}作为根路径,对应之前的../../../../', + '可直接修改模板html或css刷新查看效果' + ] + let li = {} + for (let pIdx in pluginList) { + const plugin = pluginList[pIdx] + let fileList = fs.readdirSync(_path + `/temp/ViewData/${plugin}/`) || [] + for (let idx in fileList) { + let ret = /(.+)\.json$/.exec(fileList[idx]) + if (ret && ret[1]) { + let text = [plugin, ...ret[1].split('_')] + li[text.join('')] = (`
  • ${text.join(' / ')}
  • `) + } + } + } + res.send(html.join('
    ') + '
      ' + lodash.values(li).join('') + '
    ') +}) + +app.get('/:page', function (req, res) { + let [plugin, app, page] = req.params.page.split('_') + if (plugin == 'favicon.ico') { + return res.send('') + } + let data = JSON.parse(fs.readFileSync(_path + `/temp/ViewData/${plugin}/${app}_${page}.json`, 'utf8')) + data = data || {} + data._res_path = '' + data._sys_res_path = data._res_path + + if (data._plugin) { + data._res_path = `/plugins/${data._plugin}/resources/` + data.pluResPath = data._res_path + } + let htmlPath = '' + if (data._plugin === 'genshin') { + htmlPath = 'html/' + } + let tplPath = `${app}/${htmlPath}${page}/${page}.html` + if (data._plugin) { + tplPath = `../plugins/${data._plugin}/resources/${htmlPath}/${app}/${page}.html` + } else if (data._no_type_path) { + tplPath = `${app}/${page}.html` + } + res.render(tplPath, data) +}) + +app.listen(8000) +console.log('页面服务已启动,触发消息图片后访问 http://localhost:8000/ 调试页面') diff --git "a/Yunzai/plugins/miao-plugin/\350\257\264\346\230\216.txt" "b/Yunzai/plugins/miao-plugin/\350\257\264\346\230\216.txt" new file mode 100644 index 0000000000000000000000000000000000000000..240386288f5d39698f73a11ab0c23f34a9e6c192 --- /dev/null +++ "b/Yunzai/plugins/miao-plugin/\350\257\264\346\230\216.txt" @@ -0,0 +1,34 @@ +【Miao-Plugin说明】 +Miao-Plugin是一个Yunzai-Bot的插件, +提供包括角色查询等升级功能。部分功能因Yunzai-Bot存在类似功能暂时先在Miao-Plugin以插件形式提供,可按需选用。 +在一些功能逐步稳定之后会合并入Yunzai-Bot。 + +git地址:https://gitee.com/yoimiya-kokomi/miao-plugin + + +【使用说明】 +Miao-Plugin需要最新版本的Yunzai-Bot +将整个miao-plugin文件夹放置在Yunzai-Bot/plugins/目录下,重启Yunzai-Bot即可使用。 + +【#老婆 命令说明】 +#心海 #神里 #宵宫 : 查询角色卡片,与Yunzai命令一致,会以新版卡片样式进行展示 +#老婆 #老公 #女朋友:展示老婆、老公卡片,默认会在角色池符合条件的5个内随机挑选 +#老婆设置心海,神里,宵宫 :设置老婆,如需设置多个老婆可逗号分割。未持有或不符合的角色会自动忽略 +#老婆设置随机 : 设置为随机,角色池中所有符合条件的角色都会作为备选随机展示 +#老婆写真 #老婆照片: 会返回不包含任何信息的纯图片 + +【#角色/#深渊 命令说明】 +#角色持有率:查看当前所有玩家角色持有率统计 +#角色命座:查看当前所有玩家角色命座分布统计。如需查看自己的角色命座请使用 #命座 命令 +#角色6命:查看当前所有玩家角色命座分布统计,按照6命的比例进行排序 +#深渊出场率:查看当期9-12层深渊出场前14的角色 +#深渊12层出场率:查看当期12层深渊所有角色的出场率 +> 此版块的数据源来自 DGP Studio的胡桃数据库 + +【自定义角色背景图】 +如需添加自定义的图片,可放置在 miao-plugin/resources/characterImg 的对应角色名的目录下 +支持 jpg/jpeg/png/webp 格式的图片 +支持横版、纵版图片,不限制长宽比 +虽然所有尺寸图片都支持,【但如果图像非常大尽量压缩下图片尺寸】,以免服务器在处理角色图片时负载过高 +建议格式转为jpg,尺寸限在1500*1500像素内 +文件名任意,放进去就可识别。但为了防止与后续更新冲突,【尽量避免】文件名为1位或2位数字 \ No newline at end of file