支持定义新角色及别名
* 支持自定义角色,自定义角色可使用`#派蒙` `#派蒙图片`触发图片查看,后续会支持更多场景 * 新增角色 派蒙、瑶瑶、白术、伐难、散兵 的角色配置及图片 * 如需扩展可在喵喵config/character.js中定义
@ -5,6 +5,10 @@
|
||||
* `#刻晴` 角色卡片优先使用面板数据进行展示,无面板数据时使用米游社数据
|
||||
* 在未能获取到角色数据时也会展示角色卡片
|
||||
* 角色卡片后续会进行样式升级,按需展示更多内容
|
||||
* 支持定义新角色及别名
|
||||
* 支持自定义角色,自定义角色可使用`#派蒙` `#派蒙图片`触发图片查看,后续会支持更多场景
|
||||
* 新增角色 派蒙、瑶瑶、白术、伐难、散兵 的角色配置及图片
|
||||
* 如需扩展可在喵喵config/character.js中定义
|
||||
* `#深渊出场率`增加楼层排序,以防止服务侧数据乱序导致顺序错乱
|
||||
* B服面板的天赋与皇冠信息现在可以正确的展示了
|
||||
|
||||
|
@ -99,6 +99,11 @@ export async function character(e, { render, User }) {
|
||||
e.uid = await getTargetUid(e);
|
||||
e.avatar = char.id;
|
||||
|
||||
if (char.isCustom) {
|
||||
e.reply("自定义角色暂不支持此功能");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mode === "profile" || mode === "dmg") {
|
||||
return renderProfile(e, char, render, mode, { dmgIdx });
|
||||
} else if (mode === "refresh" || mode === "input") {
|
||||
|
@ -26,7 +26,6 @@ export async function renderAvatar(e, avatar, render, renderType = "card") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
let MysApi = await e.getMysApi({
|
||||
auth: "all",
|
||||
targetType: Cfg.get("char.queryOther", true) ? "all" : "self",
|
||||
@ -38,7 +37,9 @@ export async function renderAvatar(e, avatar, render, renderType = "card") {
|
||||
|
||||
let uid = e.targetUser.uid;
|
||||
|
||||
|
||||
if (char.isCustom) {
|
||||
avatar = { id: char.id, name: char.name, detail: false }
|
||||
} else {
|
||||
let profile = await Profile.get(uid, char.id, true);
|
||||
if (profile) {
|
||||
// 优先使用Profile数据
|
||||
@ -55,26 +56,27 @@ export async function renderAvatar(e, avatar, render, renderType = "card") {
|
||||
avatar = avatars[char.id] || { id: char.id, name: char.name, detail: false };
|
||||
}
|
||||
}
|
||||
}
|
||||
return await renderCard(e, avatar, render, renderType);
|
||||
}
|
||||
|
||||
// 渲染角色卡片
|
||||
async function renderCard(e, avatar, render, renderType = "card") {
|
||||
|
||||
|
||||
let talent = await getTalent(e, avatar);
|
||||
// 计算皇冠个数
|
||||
let crownNum = lodash.filter(lodash.map(talent, (d) => d.original), (d) => d >= 10).length;
|
||||
|
||||
let uid = e.uid || (e.targetUser && e.targetUser.uid);
|
||||
|
||||
let char = Character.get(avatar);
|
||||
|
||||
if (!char) {
|
||||
return false;
|
||||
}
|
||||
let bg = char.getCardImg(Cfg.get("char.se", false));
|
||||
let uid = e.uid || (e.targetUser && e.targetUser.uid);
|
||||
|
||||
let crownNum = 0, talent = {};
|
||||
if (!char.isCustom) {
|
||||
talent = await getTalent(e, avatar);
|
||||
// 计算皇冠个数
|
||||
crownNum = lodash.filter(lodash.map(talent, (d) => d.original), (d) => d >= 10).length;
|
||||
}
|
||||
let bg = char.getCardImg(Cfg.get("char.se", false));
|
||||
if (renderType === "photo") {
|
||||
e.reply(segment.image(process.cwd() + "/plugins/miao-plugin/resources/" + bg.img));
|
||||
} else {
|
||||
@ -86,6 +88,7 @@ async function renderCard(e, avatar, render, renderType = "card") {
|
||||
crownNum,
|
||||
talentMap: { a: "普攻", e: "战技", q: "爆发" },
|
||||
bg,
|
||||
custom: char.isCustom,
|
||||
...getCharacterData(avatar),
|
||||
ds: char.getData("name,id,title,desc"),
|
||||
}, { e, render, scale: 1.6 });
|
||||
@ -101,6 +104,10 @@ async function renderCard(e, avatar, render, renderType = "card") {
|
||||
//获取角色技能数据
|
||||
async function getTalent(e, avatars) {
|
||||
let talent = {}, cons = 0, char = Character.get(avatars.id), mode = "level";
|
||||
console.log('isCustom', char.isCustom, char.id);
|
||||
if (char.isCustom) {
|
||||
return {}
|
||||
}
|
||||
if (avatars.dataSource && avatars.talent) {
|
||||
// profile模式
|
||||
talent = avatars.talent || {};
|
||||
@ -133,6 +140,7 @@ async function getTalent(e, avatars) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return char.getAvatarTalent(talent, cons, mode);
|
||||
}
|
||||
|
||||
@ -257,5 +265,5 @@ export async function getAvatarList(e, type, MysApi) {
|
||||
}
|
||||
|
||||
export function checkWifeType(id, type) {
|
||||
return genshin.wifeData[type].includes(Number(id));
|
||||
return Chargenshin.wifeData[type].includes(Number(id));
|
||||
}
|
@ -129,7 +129,7 @@ export async function wife(e, { render, User }) {
|
||||
} else {
|
||||
wifeList = lodash.map(wifeList, (name) => {
|
||||
let char = Character.get(name);
|
||||
if (char && checkWifeType(char.id, targetCfg.type)) {
|
||||
if (char && char.checkWifeType(targetCfg.type)) {
|
||||
return char.name;
|
||||
}
|
||||
});
|
||||
|
@ -17,6 +17,10 @@ export async function renderProfile(e, char, render, mode = "profile", params =
|
||||
e.reply("暂不支持主角的面板信息查看");
|
||||
return true;
|
||||
}
|
||||
if (char.isCustom) {
|
||||
e.reply(`暂不支持自定义角色${char.name}的面板信息查看`);
|
||||
return true;
|
||||
}
|
||||
|
||||
let refresh = async () => {
|
||||
let refreshRet = await autoRefresh(e);
|
||||
|
@ -53,6 +53,11 @@ export async function wiki(e, { render }) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (char.isCustom) {
|
||||
e.reply("暂不支持自定义角色");
|
||||
return true;
|
||||
}
|
||||
|
||||
return await Common.render("wiki/character", {
|
||||
save_id: "天赋" + char.name,
|
||||
...char,
|
||||
|
@ -2,6 +2,8 @@ import lodash from "lodash";
|
||||
import fs from "fs";
|
||||
import request from "request";
|
||||
|
||||
const _path = process.cwd();
|
||||
|
||||
let Data = {
|
||||
|
||||
/*
|
||||
@ -52,6 +54,19 @@ let Data = {
|
||||
return fs.writeFileSync(`${path}/${file}`, JSON.stringify(data, null, space));
|
||||
},
|
||||
|
||||
async importModule(path, file, rootPath = _path) {
|
||||
if (!/\.js$/.test(file)) {
|
||||
file = file + ".js";
|
||||
}
|
||||
// 检查并创建目录
|
||||
Data.createDir(_path, path, true);
|
||||
if (fs.existsSync(`${_path}/${path}/${file}`)) {
|
||||
let data = await import (`file://${_path}/${path}/${file}`);
|
||||
return data || {};
|
||||
}
|
||||
return {}
|
||||
},
|
||||
|
||||
/*
|
||||
* 返回一个从 target 中选中的属性的对象
|
||||
*
|
||||
@ -173,7 +188,6 @@ let Data = {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export default Data;
|
||||
|
@ -2,16 +2,55 @@ import Base from "./Base.js";
|
||||
import lodash from "lodash";
|
||||
import fs from "fs";
|
||||
import Data from "../Data.js";
|
||||
import request from "request";
|
||||
import path from "path";
|
||||
import sizeOf from "image-size";
|
||||
import { customCharacters } from "../../config/character_default.js";
|
||||
|
||||
let characterMap = {};
|
||||
|
||||
let aliasMap = {}, idMap = {}, abbrMap = {}, wifeMap = {};
|
||||
const _path = process.cwd();
|
||||
let genshin = await import(`file://${_path}/config/genshin/roleId.js`);
|
||||
|
||||
const metaPath = `${_path}/plugins/miao-plugin/resources/meta/character/`
|
||||
|
||||
async function init() {
|
||||
let sysCfg = await Data.importModule(`config/genshin`, 'roleId.js'),
|
||||
charCfg = await Data.importModule(`plugins/miao-plugin/config`, 'character_default.js'),
|
||||
custom = await Data.importModule(`plugins/miao-plugin/config`, 'character.js');
|
||||
|
||||
lodash.forEach([charCfg.customCharacters, custom.customCharacters, sysCfg.roleId], (roleIds) => {
|
||||
lodash.forEach(roleIds || {}, (aliases, id) => {
|
||||
aliases = aliases || [];
|
||||
if (aliases.length === 0) {
|
||||
return;
|
||||
}
|
||||
// 建立别名映射
|
||||
lodash.forEach(aliases || [], (alias) => {
|
||||
aliasMap[alias] = id;
|
||||
})
|
||||
aliasMap[id] = id;
|
||||
idMap[id] = aliases[0];
|
||||
})
|
||||
})
|
||||
|
||||
lodash.forEach([sysCfg.wifeData, charCfg.wifeData, custom.wifeData], (wifeData) => {
|
||||
lodash.forEach(wifeData || {}, (ids, type) => {
|
||||
type = { girlfriend: 0, boyfriend: 1, daughter: 2, son: 3 }[type] || type;
|
||||
if (!wifeMap[type]) {
|
||||
wifeMap[type] = {};
|
||||
}
|
||||
lodash.forEach(ids, (id) => {
|
||||
id = idMap[id];
|
||||
if (id) {
|
||||
wifeMap[type][id] = true;
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
abbrMap = sysCfg.abbr;
|
||||
}
|
||||
|
||||
await init();
|
||||
|
||||
|
||||
class Character extends Base {
|
||||
constructor(name, id) {
|
||||
super();
|
||||
@ -26,17 +65,14 @@ class Character extends Base {
|
||||
if (name === "主角" || name === "旅行者" || /.主/.test(name)) {
|
||||
this.id = 20000000;
|
||||
}
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
getCardImg(se = false, def = true) {
|
||||
let name = this.name;
|
||||
|
||||
const charImgPath = `./plugins/miao-plugin/resources/character-img/${name}/`;
|
||||
|
||||
|
||||
let list = [];
|
||||
|
||||
let addImg = function (charImgPath, disable = false) {
|
||||
let dirPath = `./plugins/miao-plugin/resources/${charImgPath}`;
|
||||
|
||||
@ -154,6 +190,14 @@ class Character extends Base {
|
||||
let weaponType = this.weapon || "";
|
||||
return map[weaponType.toLowerCase()] || "";
|
||||
}
|
||||
|
||||
get isCustom() {
|
||||
return !/10\d{6}/.test(this.id);
|
||||
}
|
||||
|
||||
checkWifeType(type) {
|
||||
return !!wifeMap[type][this.id];
|
||||
}
|
||||
}
|
||||
|
||||
let getMeta = function (name) {
|
||||
@ -161,30 +205,30 @@ let getMeta = function (name) {
|
||||
}
|
||||
|
||||
Character.get = function (val) {
|
||||
let roleid, name;
|
||||
let id, name;
|
||||
if (!val) {
|
||||
return false;
|
||||
}
|
||||
if (typeof (val) === "number" || /^\d*$/.test(val)) {
|
||||
roleid = val;
|
||||
id = val;
|
||||
} else if (val.id) {
|
||||
roleid = val.id;
|
||||
name = val.name || YunzaiApps.mysInfo['roleIdToName'](roleid, true);
|
||||
id = val.id;
|
||||
name = val.name || idMap[id];
|
||||
} else {
|
||||
roleid = YunzaiApps.mysInfo['roleIdToName'](val);
|
||||
id = aliasMap[val];
|
||||
}
|
||||
if (!name) {
|
||||
name = YunzaiApps.mysInfo['roleIdToName'](roleid, true);
|
||||
name = idMap[id];
|
||||
}
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
return new Character(name, roleid);
|
||||
return new Character(name, id);
|
||||
};
|
||||
|
||||
|
||||
Character.getAbbr = function () {
|
||||
return genshin.abbr;
|
||||
return abbrMap;
|
||||
}
|
||||
|
||||
Character.getRandomImg = function (type) {
|
||||
@ -211,12 +255,10 @@ let idSort = {};
|
||||
lodash.forEach(charPosIdx, (chars, pos) => {
|
||||
chars = chars.split(",");
|
||||
lodash.forEach(chars, (name, idx) => {
|
||||
if (global.YunzaiApps) {
|
||||
let id = YunzaiApps.mysInfo['roleIdToName'](name);
|
||||
let id = aliasMap[name];
|
||||
if (id) {
|
||||
idSort[id] = pos * 100 + idx;
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
40
config/character_default.js
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 请不要直接修改此文件,防止后续冲突
|
||||
* 如需编辑可【复制】此文件,改名为character.js自行编辑
|
||||
* character.js character_default.js两份配置会叠加生效
|
||||
*
|
||||
* 暂未做热更新,修改完毕请重启yunzai
|
||||
* */
|
||||
|
||||
// 角色列表,首位需要是标准名字
|
||||
// 实装的角色需要以roleid为key,非实装请以英文为key
|
||||
export const customCharacters = {
|
||||
paimon: ["派蒙", "应急食物", "应急食品", "吉祥物", "宠物", "外置器官", "会说话的动物", "矮堇瓜", "飞行矮堇瓜", "最好的伙伴"],
|
||||
|
||||
// 啊, 原谅英语白痴。。
|
||||
sb: ["散兵", "国崩", "雷电国崩", "大炮", "雷电大炮", "逆子"],
|
||||
|
||||
baizhu: ["白术", "长生"],
|
||||
|
||||
yaoyao: ["瑶瑶", "遥遥无期"],
|
||||
|
||||
fanan: ["伐难", "水夜叉"]
|
||||
}
|
||||
|
||||
/*
|
||||
* 追加设置每个关系的可选角色,会与yunzai的设置同时起作用
|
||||
* 一个角色可以在多个关系中
|
||||
* */
|
||||
export const wifeData = {
|
||||
// 老婆&女朋友:成女、少女
|
||||
girlfriend: ['伐难'],
|
||||
|
||||
// 老公&男朋友:成男、少男
|
||||
boyfriend: ['散兵', '白术'],
|
||||
|
||||
// 女儿:萝莉
|
||||
daughter: ['派蒙', '瑶瑶'],
|
||||
|
||||
// 儿子:正太
|
||||
son: []
|
||||
}
|
BIN
resources/character-img/伐难/01.jpg
Normal file
After Width: | Height: | Size: 331 KiB |
BIN
resources/character-img/伐难/02.jpg
Normal file
After Width: | Height: | Size: 575 KiB |
BIN
resources/character-img/伐难/03.jpg
Normal file
After Width: | Height: | Size: 435 KiB |
BIN
resources/character-img/伐难/04.jpg
Normal file
After Width: | Height: | Size: 271 KiB |
BIN
resources/character-img/伐难/05.jpg
Normal file
After Width: | Height: | Size: 220 KiB |
BIN
resources/character-img/散兵/01.jpg
Normal file
After Width: | Height: | Size: 276 KiB |
BIN
resources/character-img/散兵/02.jpg
Normal file
After Width: | Height: | Size: 454 KiB |
BIN
resources/character-img/散兵/03.jpg
Normal file
After Width: | Height: | Size: 387 KiB |
BIN
resources/character-img/散兵/04.jpg
Normal file
After Width: | Height: | Size: 156 KiB |
BIN
resources/character-img/散兵/05.jpg
Normal file
After Width: | Height: | Size: 195 KiB |
BIN
resources/character-img/派蒙/01.jpg
Normal file
After Width: | Height: | Size: 293 KiB |
BIN
resources/character-img/派蒙/02.jpg
Normal file
After Width: | Height: | Size: 314 KiB |
BIN
resources/character-img/派蒙/03.jpg
Normal file
After Width: | Height: | Size: 360 KiB |
BIN
resources/character-img/派蒙/04.jpg
Normal file
After Width: | Height: | Size: 385 KiB |
BIN
resources/character-img/派蒙/05.jpg
Normal file
After Width: | Height: | Size: 351 KiB |
BIN
resources/character-img/瑶瑶/01.jpg
Normal file
After Width: | Height: | Size: 646 KiB |
BIN
resources/character-img/瑶瑶/02.jpg
Normal file
After Width: | Height: | Size: 640 KiB |
BIN
resources/character-img/瑶瑶/03.jpg
Normal file
After Width: | Height: | Size: 216 KiB |
BIN
resources/character-img/瑶瑶/04.jpg
Normal file
After Width: | Height: | Size: 188 KiB |
BIN
resources/character-img/瑶瑶/05.jpg
Normal file
After Width: | Height: | Size: 402 KiB |
BIN
resources/character-img/白术/01.jpg
Normal file
After Width: | Height: | Size: 1.3 MiB |
BIN
resources/character-img/白术/02.jpg
Normal file
After Width: | Height: | Size: 155 KiB |
BIN
resources/character-img/白术/03.jpg
Normal file
After Width: | Height: | Size: 438 KiB |
BIN
resources/character-img/白术/04.jpg
Normal file
After Width: | Height: | Size: 324 KiB |
BIN
resources/character-img/白术/05.jpg
Normal file
After Width: | Height: | Size: 305 KiB |
@ -56,8 +56,12 @@
|
||||
<div class="uid">ID:{{uid}}</div>
|
||||
<span>{{ds.name}}</span>
|
||||
</div>
|
||||
{{if custom}}
|
||||
<div class="no-info">自定义角色暂无角色信息</div>
|
||||
{{else}}
|
||||
<div class="no-info">未能获取到角色信息,请将角色放置在米游社角色展柜中</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<div class="copyright">{{@sys.copyright}}</div>
|
||||
<div>
|
||||
<img src="{{_res_path}}{{bg.img}}" title="{{name}}" class="bg"></div>
|
||||
|