#角色面板#圣遗物列表 使用新的圣遗物评分逻辑计算评分

* 新的圣遗物评分规针对角色进行了细化,同时将得分进行了拉齐
 * 根据角色使用不同词条权重计算。感谢@糖炒栗子 @秋声 @49631073 等的权重梳理
 * 会在后续提供单独命令,供查看角色圣遗物及计算逻辑与计算逻辑
 * 因为计分逻辑变更,所以【分数值及档位】相较于升级之前可能有所变化。如有不合理计算请反馈给 @喵喵
 * 如需临时关闭新版评分,可编辑喵喵 lib/app/character.js, const isNewScore = false;
This commit is contained in:
yoimiya-kokomi 2022-06-10 04:53:38 +08:00
parent e503488a7e
commit 876b39e561
8 changed files with 306 additions and 26 deletions

View File

@ -1,13 +1,19 @@
# 1.7.2
# 1.7.3
* 为`#面板更新`命令增加uid合法性校验
* `#角色持有率`、`#深渊出场率` 页面细节样式调整
* `#角色面板`、`#圣遗物列表` 使用新的圣遗物评分逻辑计算评分
* 新的圣遗物评分规针对角色进行了细化,同时将得分进行了拉齐
* 根据角色使用不同词条权重计算。感谢@糖炒栗子 @秋声 @49631073 等的权重梳理
* 会在后续提供单独命令,供查看角色圣遗物及计算逻辑与计算逻辑
* 因为计分逻辑变更,所以【分数值及档位】相较于升级之前可能有所变化。如有不合理计算请反馈给 @喵喵
* 如需临时关闭新版评分,可编辑喵喵 lib/app/character.js, const isNewScore = false;
# 1.7.1
# 1.7.1~1.7.2
* `#更新面板` 功能fix
* `#更新面板` 功能升级及问题修正
* 修正武器类型、元素伤害字段导致的伤害计算问题
* 夜兰 请在游戏内不出场状况下获取面板属性
* 为`#面板更新`命令增加uid合法性校验
* `#角色持有率`、`#深渊出场率` 页面细节样式调整
# 1.7.0

View File

@ -5,8 +5,8 @@ import { Cfg } from "../components/index.js";
import Profile from "../components/Profile.js";
import Format from "../components/Format.js"
import Reliquaries from "../components/models/Reliquaries.js";
import Reliquaries2 from "../components/models/Reliquaries2.js";
import Calc from "../components/Calc.js";
import fs from "fs";
import Common from "../components/Common.js";
@ -15,6 +15,8 @@ let nameID = "";
let genshin = {};
await init();
const isNewScore = true;
const relationMap = {
wife: {
keyword: "老婆,媳妇,妻子,娘子".split(","),
@ -495,7 +497,7 @@ async function autoRefresh(e) {
e.reply("请确认角色已在【游戏内】橱窗展示并开放了查看详情。设置完毕后请5分钟后使用 #面板更新 重新获取")
return false;
} else {
e.reply(`本次获取成功角色: ${ret.join(", ")} `)
// e.reply(`本次获取成功角色: ${ret.join(", ")} `)
return true;
}
}
@ -505,7 +507,6 @@ async function autoRefresh(e) {
export async function getProfile(e, mode = "refresh") {
let uid = await getTargetUid(e);
console.log('uid', uid)
if (!uid) {
return true;
}
@ -742,28 +743,35 @@ export async function renderProfile(e, char, render, mode = "profile", params =
dmgBonus: p(Math.max(a.dmgBonus * 1 || 0, a.phyBonus * 1 || 0))
};
/*
let avatar = await getAvatar(e, char, MysApi);
let talent = await getTalent(e, avatar);
*/
let reliquaries = [], totalMark = 0, totalMaxMark = 0;
let { titles: usefulTitles, mark: usefulMark } = Reliquaries.getUseful(char.name);
let newScore = Reliquaries2.getArtisMark(char.name, profile.artis);
lodash.forEach(profile.artis, (arti) => {
lodash.forEach(profile.artis, (arti, idx) => {
idx = idx.replace("arti", "");
let ds = arti;
let mark = Reliquaries.getMark(char.name, arti.attrs);
let mark = isNewScore ? newScore[idx] : Reliquaries.getMark(char.name, arti.attrs);
let maxMark = Reliquaries.getMaxMark(char.name, arti.main[0] || "");
totalMark += mark;
totalMaxMark += maxMark;
ds.mark = c(mark, 1);
ds.markType = Reliquaries.getMarkScore(mark, maxMark);
ds.markType = isNewScore ? Reliquaries2.getMarkScore(mark) : Reliquaries.getMarkScore(mark, maxMark);
ds.main = Profile.formatArti(arti.main);
ds.attrs = Profile.formatArti(arti.attrs);
reliquaries.push(ds);
});
let markScore, usefulMark;
if (isNewScore) {
let charCfg = Reliquaries2.getCharCfg(char.name);
usefulMark = charCfg.titleWeight;
markScore = Reliquaries2.getMarkScore(totalMark / 5);
} else {
let usefulData = Reliquaries.getUseful(char.name);
usefulMark = usefulData.mark;
markScore = Reliquaries.getMarkScore(totalMark, totalMaxMark);
}
let enemyLv = await selfUser.getCfg(`char.enemyLv`, 91);
let dmgMsg = [], dmgData = [];
@ -816,9 +824,7 @@ export async function renderProfile(e, char, render, mode = "profile", params =
enemyLv,
enemyName: dmgCalc.enemyName || "小宝",
totalMark: c(totalMark, 1),
totalMaxMark,
markScore: Reliquaries.getMarkScore(totalMark, totalMaxMark),
usefulTitles,
markScore,
usefulMark,
talentMap: { a: "普攻", e: "战技", q: "爆发" },
bodyClass: `char-${char.name}`,
@ -876,21 +882,25 @@ export async function getArtis(e, { render }) {
lodash.forEach(profiles || [], (ds) => {
let name = ds.name;
if (!name) {
if (!name || name === "空" || name === "荧") {
return;
}
let { mark: usefulMark } = Reliquaries.getUseful(name);
/* 处理圣遗物 */
if (ds.artis) {
lodash.forEach(ds.artis, (arti) => {
let newScore = Reliquaries2.getArtisMark(name, ds.artis);
lodash.forEach(ds.artis, (arti, idx) => {
if (!arti.name) {
return;
}
let mark = Reliquaries.getMark(name, arti.attrs);
idx = idx.replace("arti", "");
let mark = isNewScore ? newScore[idx] : Reliquaries.getMark(name, arti.attrs);
let maxMark = Reliquaries.getMaxMark(name, arti.main[0] || "");
arti.mark = Format.comma(mark, 1);
arti._mark = mark;
arti.markType = Reliquaries.getMarkScore(mark, maxMark);
arti.markType = isNewScore ? Reliquaries2.getMarkScore(mark) : Reliquaries.getMarkScore(mark, maxMark);
arti.main = Profile.formatArti(arti.main);
arti.attrs = Profile.formatArti(arti.attrs);
arti.usefulMark = usefulMark;

View File

@ -42,7 +42,7 @@ let Profile = {
e.reply("请求过快,请稍后重试..");
return false;
} else if (inCd === 'pending') {
e.reply("#ref距上次请求刷新成功间隔小于5分钟请稍后重试..");
e.reply("距上次请求刷新成功间隔小于5分钟请稍后重试..");
return false;
}
await redis.set(`miao:role-all:${uid}`, 'loading', { EX: 20 });

View File

@ -0,0 +1,157 @@
import {
attrValue,
attrNameMap,
attrMap,
mainAttr,
subAttr,
usefulAttr
} from "../../resources/meta/reliquaries/reliquaries-mark-new.js";
import { Character } from "../models.js";
import lodash from "lodash";
let charCfg = {};
let Reliquaries = {
getCharCfg(name) {
if (charCfg[name]) {
return charCfg[name]
}
let attrWeight = usefulAttr[name] || { atk: 75, cp: 100, cd: 100 };
let attrMark = {};
let char = Character.get(name);
let baseAttr = char.lvStat.detail['90'];
lodash.forEach(attrWeight, (weight, attr) => {
attrMark[attr] = weight / attrValue[attr];
});
// let baseAttr = [400, 500, 300];
if (attrMark.hp) {
attrMark.hpPlus = attrMark.hp / baseAttr[0] * 100;
}
if (attrMark.atk) {
attrMark.atkPlus = attrMark.atk / (baseAttr[1] + 400) * 100;
}
if (attrMark.def) {
attrMark.defPlus = attrMark.def / baseAttr[2] * 100;
}
let maxMark = Reliquaries.getMaxMark(attrWeight);
let titleMark = {}, titleWeight = {};
lodash.forEach(attrMark, (mark, attr) => {
titleMark[attrMap[attr]] = mark;
titleWeight[attrMap[attr]] = attrWeight[attr] || 0;
if (/大/.test(attrMap[attr])) {
let newAttr = attrMap[attr];
let newArr = newAttr.replace("大", "小");
titleWeight[newArr] = attrWeight[attr] || 0;
}
})
charCfg[name] = {
weight: attrWeight,
mark: attrMark,
titleMap: titleMark,
titleWeight,
maxMark
};
return charCfg[name];
},
getMaxAttr(charAttr = {}, list2 = [], maxLen = 1, banAttr = "") {
let tmp = [];
lodash.forEach(list2, (attr) => {
if (attr === banAttr) return;
if (!charAttr[attr]) return;
tmp.push({ attr, mark: charAttr[attr] });
});
tmp = lodash.sortBy(tmp, "mark");
tmp = tmp.reverse();
let ret = [];
lodash.forEach(tmp, (ds) => ret.push(ds.attr));
return ret.slice(0, maxLen);
},
getMaxMark(attrWeight) {
let ret = {};
for (let idx = 1; idx <= 5; idx++) {
let totalMark = 0, mMark = 0;
let mAttr = "";
if (idx === 1) {
mAttr = "hpPlus";
} else if (idx === 2) {
mAttr = "atkPlus";
} else if (idx >= 3) {
mAttr = Reliquaries.getMaxAttr(attrWeight, mainAttr[idx])[0];
mMark = attrWeight[mAttr];
totalMark += attrWeight[mAttr] * 2;
}
let sAttr = Reliquaries.getMaxAttr(attrWeight, subAttr, 4, mAttr);
lodash.forEach(sAttr, (attr, aIdx) => {
totalMark += attrWeight[attr] * (aIdx === 0 ? 6 : 1)
});
ret[idx] = totalMark;
ret['m' + idx] = mMark;
}
return ret;
},
getAttr(ds) {
let title = ds[0]
let attr = attrNameMap[title];
if (/元素伤害/.test(title)) {
attr = "dmg";
} else if (/物理|物伤/.test(title)) {
attr = "phy"
}
return attr;
},
getAttrMark(attrMark, ds) {
if (!ds || !ds[1]) {
return 0;
}
let attr = Reliquaries.getAttr(ds);
let val = ds[1];
return (attrMark[attr] || 0) * val;
},
getMark(charCfg, posIdx, mainAttr, subAttr) {
let ret = 0;
let { mark, maxMark, weight } = charCfg;
let mAttr = Reliquaries.getAttr(mainAttr);
let fixPct = 1;
if (posIdx >= 3) {
fixPct = Math.max(0, Math.min(1, (weight[mAttr] || 0) / (maxMark['m' + posIdx])));
ret += Reliquaries.getAttrMark(mark, mainAttr) / 4
}
lodash.forEach(subAttr, (ds) => {
ret += Reliquaries.getAttrMark(mark, ds)
});
return ret * (1 + fixPct) / 2 / maxMark[posIdx] * 66;
},
getArtisMark(charName = "", artis = {}) {
let total = 0;
let charCfg = Reliquaries.getCharCfg(charName);
let ret = {}
lodash.forEach(artis, (ds, idx) => {
idx = idx.replace("arti", "");
ret[idx] = Reliquaries.getMark(charCfg, idx, ds.main, ds.attrs)
});
return ret;
},
getMarkScore(mark) {
let pct = mark;
let scoreMap = [["D", 10], ["C", 16.5], ["B", 23.1], ["A", 29.7], ["S", 36.3], ["SS", 42.9], ["SSS", 50], ["ACE", 56.1], ["ACE²", 66]];
for (let idx = 0; idx < scoreMap.length; idx++) {
if (pct < scoreMap[idx][1]) {
return scoreMap[idx][0];
}
}
},
getSet(name) {
for (let idx in meta) {
if (meta[idx].name === name) {
return meta[idx];
}
}
}
}
export default Reliquaries;

View File

@ -488,6 +488,9 @@ body {
line-height: 26px;
height: 26px;
}
.artis ul.detail li.great span.title {
color: #ffe699;
}
.artis ul.detail li.nouse span {
color: #888;
}

View File

@ -84,7 +84,7 @@
<li class="arti-main"><span class="title">{{ds.main[0]}}</span><span class="val">+{{ds.main[1]}}</span></li>
{{each ds.attrs attr}}
{{if attr[0]}}
<li class="{{usefulMark[attr[0]] ? `useful`:`nouse`}}"><span class="title">{{attr[0]}}</span><span
<li class="{{usefulMark[attr[0]]*1 > 79.9 ?`great`:(usefulMark[attr[0]]*1>0 ? `useful`:`nouse`)}}"><span class="title">{{attr[0]}} </span><span
class="val">+{{attr[1]}}</span></li>
{{/if}}
{{/each}}

View File

@ -601,6 +601,9 @@ body {
height: 26px;
}
.artis ul.detail li.great span.title {
color: #ffe699;
}
.artis ul.detail li.nouse span {
color: #888;

View File

@ -0,0 +1,101 @@
export const attrValue = {
cp: 3.89,
cd: 7.77,
mastery: 23.31,
atk: 5.83,
hp: 5.83,
def: 7.29,
recharge: 6.48,
dmg: 5.825,
phy: 7.288,
heal: 4.487
};
export const attrMap = {
atk: "大攻击",
atkPlus: "小攻击",
def: "大防御",
defPlus: "小防御",
hp: "大生命",
hpPlus: "小生命",
cp: "暴击率",
cd: "暴击伤害",
mastery: "元素精通",
recharge: "充能效率",
dmg: "元素伤害",
phy: "物伤加成",
heal: "治疗加成",
};
let anMap = {};
for (let attr in attrMap) {
anMap[attrMap[attr]] = attr;
}
export const attrNameMap = anMap;
/* 当前位置主词条不可能出现词缀*/
export const banAttr = {
1: "hpPlus,dmg,phy,heal".split(","),
2: "atkPlus,dmg,phy,heal".split(","),
3: "dmg,phy,heal".split(","),
4: "heal".split(","),
5: "dmg,phy".split(",")
};
export const mainAttr = {
3: "atk,def,hp,mastery,recharge".split(","),
4: "atk,def,hp,mastery,dmg,phy".split(","),
5: "atk,def,hp,mastery,recharge,heal,cp,cd".split(",")
};
export const subAttr = "atk,def,hp,mastery,recharge,cp,cd".split(",")
export const usefulAttr = {
'神里绫人': { hp: 40, atk: 75, def: 0, cp: 100, cd: 100, mastery: 25, dmg: 100, phy: 0, recharge: 20, heal: 0 },
'八重神子': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 50, dmg: 100, phy: 0, recharge: 50, heal: 0 },
'申鹤': { hp: 0, atk: 100, def: 0, cp: 75, cd: 75, mastery: 0, dmg: 100, phy: 0, recharge: 70, heal: 0 },
'云堇': { hp: 0, atk: 25, def: 100, cp: 50, cd: 50, mastery: 0, dmg: 25, phy: 0, recharge: 90, heal: 0 },
'荒泷一斗': { hp: 0, atk: 50, def: 90, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 0, recharge: 30, heal: 0 },
'五郎': { hp: 0, atk: 50, def: 100, cp: 50, cd: 50, mastery: 0, dmg: 25, phy: 0, recharge: 90, heal: 0 },
'班尼特': { hp: 90, atk: 30, def: 0, cp: 50, cd: 50, mastery: 0, dmg: 70, phy: 0, recharge: 80, heal: 100 },
'枫原万叶': { hp: 0, atk: 60, def: 0, cp: 100, cd: 100, mastery: 100, dmg: 100, phy: 0, recharge: 55, heal: 0 },
'雷电将军': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 20, dmg: 75, phy: 0, recharge: 90, heal: 0 },
'行秋': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 20, dmg: 100, phy: 0, recharge: 65, heal: 0 },
'钟离': { hp: 80, atk: 70, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 50, recharge: 55, heal: 0 },
'神里绫华': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 30, dmg: 100, phy: 0, recharge: 20, heal: 0 },
'香菱': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 75, dmg: 100, phy: 0, recharge: 75, heal: 0 },
'胡桃': { hp: 80, atk: 30, def: 0, cp: 100, cd: 100, mastery: 75, dmg: 100, phy: 0, recharge: 35, heal: 0 },
'甘雨': { hp: 0, atk: 90, def: 0, cp: 100, cd: 100, mastery: 50, dmg: 100, phy: 0, recharge: 40, heal: 0 },
'温迪': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 60, dmg: 100, phy: 0, recharge: 80, heal: 0 },
'珊瑚宫心海': { hp: 100, atk: 50, def: 0, cp: 0, cd: 0, mastery: 0, dmg: 100, phy: 0, recharge: 65, heal: 100 },
'莫娜': { hp: 0, atk: 50, def: 0, cp: 100, cd: 100, mastery: 75, dmg: 100, phy: 0, recharge: 80, heal: 0 },
'阿贝多': { hp: 0, atk: 30, def: 80, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 0, recharge: 35, heal: 0 },
'迪奥娜': { hp: 85, atk: 50, def: 0, cp: 75, cd: 75, mastery: 0, dmg: 65, phy: 0, recharge: 55, heal: 100 },
'优菈': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 40, phy: 100, recharge: 45, heal: 0 },
'达达利亚': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 50, dmg: 100, phy: 0, recharge: 45, heal: 0 },
'魈': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 0, recharge: 20, heal: 0 },
'宵宫': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 75, dmg: 100, phy: 0, recharge: 0, heal: 0 },
'九条裟罗': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 0, recharge: 55, heal: 0 },
'琴': { hp: 0, atk: 90, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 100, recharge: 55, heal: 100 },
'菲谢尔': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 30, dmg: 100, phy: 60, recharge: 30, heal: 0 },
'罗莎莉亚': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 70, phy: 80, recharge: 40, heal: 0 },
'可莉': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 20, dmg: 100, phy: 0, recharge: 40, heal: 0 },
'凝光': { hp: 0, atk: 80, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 0, recharge: 40, heal: 0 },
'北斗': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 30, dmg: 100, phy: 0, recharge: 50, heal: 0 },
'刻晴': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 15, dmg: 100, phy: 100, recharge: 30, heal: 0 },
'托马': { hp: 75, atk: 50, def: 0, cp: 50, cd: 50, mastery: 0, dmg: 75, phy: 0, recharge: 55, heal: 40 },
'迪卢克': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 50, dmg: 100, phy: 0, recharge: 40, heal: 0 },
'芭芭拉': { hp: 80, atk: 50, def: 0, cp: 50, cd: 50, mastery: 15, dmg: 80, phy: 0, recharge: 55, heal: 100 },
'诺艾尔': { hp: 0, atk: 75, def: 100, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 0, recharge: 70, heal: 0 },
'旅行者': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 0, recharge: 55, heal: 0 },
'重云': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 0, recharge: 70, heal: 0 },
'七七': { hp: 0, atk: 100, def: 0, cp: 75, cd: 75, mastery: 0, dmg: 60, phy: 70, recharge: 25, heal: 100 },
'凯亚': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 100, recharge: 40, heal: 10 },
'烟绯': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 40, dmg: 100, phy: 0, recharge: 40, heal: 0 },
'早柚': { hp: 0, atk: 60, def: 0, cp: 70, cd: 70, mastery: 100, dmg: 80, phy: 0, recharge: 70, heal: 100 },
'安柏': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 75, dmg: 100, phy: 100, recharge: 35, heal: 0 },
'丽莎': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 40, dmg: 100, phy: 0, recharge: 45, heal: 0 },
'埃洛伊': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 100, phy: 0, recharge: 30, heal: 0 },
'辛焱': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 50, phy: 100, recharge: 30, heal: 0 },
'砂糖': { hp: 0, atk: 60, def: 0, cp: 70, cd: 70, mastery: 100, dmg: 40, phy: 0, recharge: 70, heal: 0 },
'雷泽': { hp: 0, atk: 75, def: 0, cp: 100, cd: 100, mastery: 0, dmg: 50, phy: 100, recharge: 35, heal: 0 },
'夜兰': { hp: 80, atk: 0, def: 0, cp: 100, cd: 100, mastery: 25, dmg: 100, phy: 0, recharge: 75, heal: 0 },
};