圣遗物数据底层存储格式与处理逻辑初步升级

This commit is contained in:
Kokomi 2022-11-24 04:26:07 +08:00
parent 9ecc6e5b31
commit c91741690e
26 changed files with 298 additions and 277 deletions

View File

@ -1,12 +1,14 @@
# 2.1.0
# 2.1.1
* 部分底层结构升级
* 底层增加面板计算逻辑,供后续功能使用
* 圣遗物数据底层存储格式与处理逻辑初步升级
* 圣遗物主词条评分规则微调,可能会影响部分角色评分
* 元素杯属性不符会触发主词缀评分惩罚
* 充能主词条不再触发主词缀评分惩罚
* 一些已知问题修正与优化
* 一些已知问题修正与样式优化
# 2.0.1~2.0.9
# 2.1.0
* 增加群内排名功能
* 默认关闭,如需启用可通过`#喵喵设置排名开启`进行打开

View File

@ -5,7 +5,7 @@
import lodash from 'lodash'
import { Profile, Common } from '../../components/index.js'
import { getTargetUid, profileHelp, autoGetProfile } from './ProfileCommon.js'
import { Artifact, Character } from '../../models/index.js'
import { Artifact, Character, ProfileArtis } from '../../models/index.js'
/*
* 角色圣遗物面板
@ -27,10 +27,12 @@ export async function profileArtis (e) {
}
let charCfg = profile.artis.getCharCfg()
let { artis, mark: totalMark, markClass: totalMarkClass, usefulMark } = profile.getArtisMark()
let { attrMap } = Artifact.getMeta()
let artisDetail = profile.getArtisMark()
let artisKeyTitle = ProfileArtis.getArtisKeyTitle()
// 渲染图像
return await Common.render('character/artis-mark', {
uid,
@ -38,10 +40,9 @@ export async function profileArtis (e) {
splash: char.getImgs(profile.costume).splash,
data: profile,
costume: profile.costume ? '2' : '',
artis,
totalMark,
totalMarkClass,
usefulMark,
artisDetail,
artisKeyTitle,
attrMap,
charCfg
}, { e, scale: 1.3 })
@ -72,7 +73,7 @@ export async function profileArtisList (e) {
}
let profileArtis = profile.getArtisMark()
lodash.forEach(profileArtis.artis, (arti, idx) => {
arti.usefulMark = profileArtis.usefulMark
arti.charWeight = profileArtis.charWeight
arti.avatar = name
arti.side = char.side
artis.push(arti)
@ -87,11 +88,13 @@ export async function profileArtisList (e) {
artis = lodash.sortBy(artis, '_mark')
artis = artis.reverse()
artis = artis.slice(0, 28)
let artisKeyTitle = ProfileArtis.getArtisKeyTitle()
// 渲染图像
return await Common.render('character/artis-list', {
save_id: uid,
uid,
artis
artis,
artisKeyTitle
}, { e, scale: 1.4 })
}

View File

@ -1,7 +1,7 @@
import lodash from 'lodash'
import { autoRefresh } from './ProfileCommon.js'
import { Common, Format, Profile } from '../../components/index.js'
import { MysApi, Avatar, ProfileRank } from '../../models/index.js'
import { MysApi, Avatar, ProfileRank, ProfileArtis } from '../../models/index.js'
export async function renderProfile (e, char, mode = 'profile', params = {}) {
let selfUser = await MysApi.initUser(e)
@ -55,7 +55,6 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) {
dmg: p(Math.max(a.dmg * 1 || 0, a.phy * 1 || 0))
}
let { artis, mark: totalMark, markClass: totalMarkClass, usefulMark, classTitle } = profile.getArtisMark()
let enemyLv = await selfUser.getCfg('char.enemyLv', 91)
let dmgMsg = []
@ -94,6 +93,10 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) {
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()
// 渲染图像
return await Common.render('character/profile-detail', {
save_id: uid,
@ -105,14 +108,11 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) {
dmgMsg,
dmgRet: dmgCalc.dmgRet || false,
dmgCfg: dmgCalc.dmgCfg || false,
artis,
artisDetail,
artisKeyTitle,
enemyLv,
imgs: char.getImgs(profile.costume),
enemyName: dmgCalc.enemyName || '小宝',
totalMark: c(totalMark, 1),
totalMarkClass,
classTitle,
usefulMark,
talentMap: { a: '普攻', e: '战技', q: '爆发' },
bodyClass: `char-${char.name}`,
mode

View File

@ -5,7 +5,7 @@
import lodash from 'lodash'
import { Cfg, Common, App, Data } from '../components/index.js'
import { Abyss, AvatarList, Character, MysApi } from '../models/index.js'
import HutaoApi from './stat/HutaoApi.js'
import HutaoApi from './wiki/HutaoApi.js'
let app = App.init({
id: 'stat',

View File

@ -110,11 +110,7 @@ async function renderWiki ({ e, char }) {
lodash.extend(data, char.getData('weaponType,elemName'))
// 命座持有
let holding = await CharWiki.getHolding(char.id)
// let usage = await CharWiki.getUsage(char.id)
let usage = {
weapons: await CharWiki.getWeapons(char.id),
artis: await CharWiki.getArtis(char.id)
}
let usage = await CharWiki.getUsage(char.id)
return await Common.render('wiki/character-wiki', {
data,
attr: char.getAttrList(),

View File

@ -1,10 +1,14 @@
import HutaoApi from '../stat/HutaoApi.js';
import lodash from 'lodash';
import { Format } from '../../components/index.js';
import { ArtifactSet, Weapon } from '../../models/index.js';
import HutaoApi from './HutaoApi.js'
import lodash from 'lodash'
import { Format } from '../../components/index.js'
import { ArtifactSet, Weapon } from '../../models/index.js'
let CharWiki = {
// 命座持有
/**
* 角色命座持有
* @param id
* @returns {Promise<{}>}
*/
async getHolding (id) {
let consData = (await HutaoApi.getCons()).data || {}
consData = lodash.find(consData, (ds) => ds.avatar === id)
@ -23,58 +27,12 @@ let CharWiki = {
}
return holding
},
async getWeapons (id) {
let wu = (await HutaoApi.getWeaponUsage()).data || {}
let weapons = []
if (wu[id]) {
lodash.forEach(wu[id], (ds) => {
let weapon = Weapon.get(ds.name)
if (weapon) {
weapons.push({
...weapon.getData('name,abbr,img,star'),
value: ds.value
})
}
})
}
weapons = lodash.sortBy(weapons, 'value')
weapons = weapons.reverse()
lodash.forEach(weapons, (ds) => {
ds.value = Format.percent(ds.value, 1)
})
return weapons
},
async getArtis (id) {
let au = (await HutaoApi.getArtisUsage()).data || {}
let artis = []
if (au[id]) {
lodash.forEach(au[id], (ds) => {
let imgs = []
let abbrs = []
let ss = ds.sets.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.value
})
})
}
artis = lodash.sortBy(artis, 'value')
artis = artis.reverse()
artis.forEach((ds) => {
ds.value = Format.percent(ds.value)
})
return artis
},
/**
* 角色武器圣遗物使用
* @param id
* @returns {Promise<{}|{artis: *[], weapons: *[]}>}
*/
async getUsage (id) {
let ud = (await HutaoApi.getUsage()).data || {}
if (!ud[id]) {
@ -86,6 +44,12 @@ let CharWiki = {
artis: CharWiki.getArtisData(ud.artis)
}
},
/**
* 武器使用
* @param data
* @returns {*[]}
*/
getWeaponsData (data = []) {
let weapons = []
@ -104,6 +68,12 @@ let CharWiki = {
})
return weapons
},
/**
* 圣遗物使用
* @param data
* @returns {*[]}
*/
getArtisData (data = []) {
let artis = []

View File

@ -57,14 +57,6 @@ let HutaoApi = {
return await HutaoApi.req('/Statistics/Avatar/AvatarCollocation')
},
async getWeaponUsage () {
return await HutaoApi.req('/Statistics/AvatarWeaponUsage')
},
async getArtisUsage () {
return await HutaoApi.req('/Statistics/AvatarReliquaryUsage')
},
async uploadData (data = {}) {
let body = JSON.stringify(data)
return await HutaoApi.req('/Record/UploadData', {

View File

@ -1,4 +1,7 @@
import lodash from 'lodash'
import { Character } from '../models/index.js'
let CharId = Character.CharId
let Format = {
int: function (d) {
@ -15,7 +18,25 @@ let Format = {
},
percent: function (num, fix = 1) {
return Format.pct(num * 100, fix)
},
elem: function (str, def = '') {
let ret = CharId.matchElem(str, def)
return ret ? ret.elem : def
},
elemName: function (elem, def = '') {
return CharId.getElemName(elem) || def
},
isElem (elem) {
return !!CharId.getElemName(elem)
},
elemTitleMap () {
return CharId.elemTitleMap
}
}
export default Format

View File

@ -152,12 +152,15 @@ let MiaoData = {
let tid = talentId[ds.id]
key = talentKey[tid]
elem = elem || talentElem[tid]
} else {
key = ['a', 'e', 'q'][idx++]
}
ret[key] = {
level: ds.level
}
} else {
key = ['a', 'e', 'q'][idx++]
ret[key] = ret[key] || {
level: ds.level
}
}
})
return {

View File

@ -11,6 +11,7 @@ import CharImg from './character-lib/CharImg.js'
import CharTalent from './character-lib/CharTalent.js'
import CharId from './character-lib/CharId.js'
import CharMeta from './character-lib/CharMeta.js'
import CharCfg from './character-lib/CharCfg.js'
let { abbrMap, wifeMap, idSort, idMap } = CharId
@ -112,10 +113,12 @@ class Character extends Base {
return this.getImgs().side
}
// gacha图像
get gacha () {
return this.getImgs().gacha
}
// 获取character相关图像
get imgs () {
return this.getImgs()
}
@ -125,6 +128,7 @@ class Character extends Base {
return this.getDetail()
}
// 获取命座天赋等级
get talentCons () {
if (this.isTraveler) {
return this.elem === 'dendro' ? { e: 3, q: 5 } : { e: 5, q: 3 }
@ -132,19 +136,17 @@ class Character extends Base {
return this.meta?.talentCons || {}
}
// 获取attr列表
getAttrList () {
let { meta } = this
return CharMeta.getAttrList(meta.baseAttr, meta.growAttr, this.elemName)
}
// 获取素材
getMaterials (type = 'all') {
return CharMeta.getMaterials(this, type)
}
getLvStat () {
return CharMeta.getLvStat(this)
}
// 获取生日
get birthday () {
let birth = this.birth
@ -167,15 +169,18 @@ class Character extends Base {
return CharTalent.getAvatarTalent(this.id, talent, cons, mode, this.talentCons)
}
// 检查老婆类型
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
@ -310,22 +315,10 @@ class Character extends Base {
return arr.sort((a, b) => (idSort[a] || 300) - (idSort[b] || 300))
}
// 获取伤害计算配置
async getCalcRule () {
if (!this._calcRule && this._calcRule !== false) {
let cfg = await Data.importModule(`resources/meta/character/${this.name}/calc.js`)
if (lodash.isEmpty(cfg)) {
this._calcRule = false
} else {
this._calcRule = {
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._calcRule = await CharCfg.getCalcRule(this)
}
return this._calcRule
}
@ -333,6 +326,12 @@ class Character extends Base {
static matchElem (str, def) {
return CharId.matchElem(str, def)
}
static matchElemName () {
}
}
Character.CharId = CharId
export default Character

View File

@ -1,12 +1,12 @@
/*
/**
* 面板圣遗物
* */
*/
import lodash from 'lodash'
import Base from './Base.js'
import { Artifact, ArtifactSet, Character } from './index.js'
import { Format, Data } from '../components/index.js'
import ArtisMark from './profile-lib/ArtisMark.js'
import { attrMap, attrNameMap, attrValue } from '../resources/meta/artifact/artis-mark.js'
import { attrMap, attrValue } from '../resources/meta/artifact/artis-mark.js'
import CharArtis from './profile-lib/CharArtis.js'
export default class ProfileArtis extends Base {
@ -87,16 +87,7 @@ export default class ProfileArtis extends Base {
if (!main) {
return ''
}
let title = main.title
if (/元素伤害/.test(title)) {
return 'dmg'
}
if (attrNameMap[main.title]) {
return attrNameMap[main.title]
} else {
console.log(main.title)
}
return ''
return ArtisMark.getKeyByTitle(main.key, true) || ''
}
is (check, pos = '') {
@ -126,6 +117,7 @@ export default class ProfileArtis extends Base {
return check
}
// 获取圣遗物数据
getArtisData () {
let ret = {}
this.forEach((ds, idx) => {
@ -139,6 +131,16 @@ export default class ProfileArtis extends Base {
return ret
}
/**
* 获取圣遗物套装数据
* @returns {*|{imgs: *[], names: *[], sets: {}, abbrs: *[], sName: string, name: (string|*)}}
* sets: 套装名:2/4
* names: [套装名]
* imgs: [img]
* abbrs[别名]
* name: '组合名字' 若为4件套会使用套装完整名
* sName: '简写名字'若为4件套也会使用简写
*/
getSetData () {
if (this._setData) {
return this._setData
@ -174,6 +176,10 @@ export default class ProfileArtis extends Base {
return this._setData
}
/**
* 获取角色配置
* @returns {{classTitle: *, weight: *, posMaxMark: {}, mark: {}, attrs: {}}}
*/
getCharCfg () {
let char = Character.get(this.charid)
let { attrWeight, title } = CharArtis.getCharArtisCfg(char, this.profile, this)
@ -200,15 +206,13 @@ export default class ProfileArtis extends Base {
}
attrs[key] = ret
})
let maxMark = ArtisMark.getMaxMark(attrs)
let posMaxMark = ArtisMark.getMaxMark(attrs)
// 返回内容待梳理简化
return {
attrs,
classTitle: title,
weight: attrWeight,
// 待删除
mark: lodash.mapValues(attrs, (ds) => ds.mark),
maxMark
posMaxMark
}
}
@ -216,10 +220,6 @@ export default class ProfileArtis extends Base {
let charCfg = this.getCharCfg()
let artis = {}
let setCount = {}
let usefulMark = {}
lodash.forEach(charCfg.attrs, (ds) => {
usefulMark[ds.title] = ds.weight
})
let totalMark = 0
this.forEach((arti, idx) => {
let mark = ArtisMark.getMark(charCfg, idx, arti.main, arti.attrs, this.elem)
@ -241,8 +241,8 @@ export default class ProfileArtis extends Base {
_mark: mark,
mark: Format.comma(mark, 1),
markClass: ArtisMark.getMarkClass(mark),
main: ArtisMark.formatArti(arti.main, charCfg.mark, true, this.elem || ''),
attrs: ArtisMark.formatArti(arti.attrs, charCfg.mark)
main: ArtisMark.formatArti(arti.main, charCfg.attrs, true, this.elem || ''),
attrs: ArtisMark.formatArti(arti.attrs, charCfg.attrs)
}
}
})
@ -270,7 +270,7 @@ export default class ProfileArtis extends Base {
classTitle: charCfg.classTitle
}
if (withDetail) {
ret.usefulMark = usefulMark
ret.charWeight = charCfg.weight
}
return ret
}
@ -290,4 +290,8 @@ export default class ProfileArtis extends Base {
eachArtisSet (fn) {
ProfileArtis._eachArtisSet(this.sets, fn)
}
static getArtisKeyTitle () {
return ArtisMark.getKeyTitleMap()
}
}

View File

@ -0,0 +1,25 @@
import { Data } from '../../components/index.js'
import lodash from 'lodash'
/**
* 角色相关配置
*/
let CharCfg = {
// 获取角色伤害计算相关配置
async getCalcRule (char) {
let cfg = await Data.importModule(`resources/meta/character/${char.name}/calc.js`)
if (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 || '小宝' // 敌人名称
}
}
}
export default CharCfg

View File

@ -1,4 +1,4 @@
/*
/**
* 角色别名及角色ID相关
* */
import lodash from 'lodash'
@ -143,6 +143,7 @@ const CharId = {
getElemName (elem = '') {
return elemTitleMap[CharId.getElem(elem)]
},
elemTitleMap,
// 名字匹配元素
matchElem (name = '', defElem = '') {

View File

@ -1,4 +1,4 @@
/*
/**
* 角色照片及角色图像资源相关
* */
import fs from 'fs'

View File

@ -149,10 +149,6 @@ const CharMeta = {
return type === 'all' ? ret : ret[0]
},
getLvStat (char) {
},
getDesc (desc) {
desc = desc.replace(/。$/, '')
desc = desc.replace('</br>', '')

View File

@ -1,4 +1,4 @@
/*
/**
* 角色天赋相关处理
* */
import lodash from 'lodash'

View File

@ -1,16 +1,47 @@
import lodash from 'lodash'
import { Format } from '../../components/index.js'
import { Character } from '../index.js'
import { attrNameMap, mainAttr, subAttr, attrMap } from '../../resources/meta/artifact/artis-mark.js'
let ArtisMark = {
// 根据Key获取标题
getKeyByTitle (title, dmg = false) {
if (/元素伤害加成/.test(title)) {
let elem = Format.elem(title)
return dmg ? 'dmg' : elem
} else if (title === '物理伤害加成') {
return 'phy'
}
return attrNameMap[title]
},
// 根据标题获取Key
getTitleByKey (key) {
// 检查是否是伤害字段
let dmg = Format.elemName(key, '')
if (dmg) {
return `${dmg}伤加成`
}
return attrMap[key].title
},
getKeyTitleMap () {
let ret = {}
lodash.forEach(attrMap, (ds, key) => {
ret[key] = ds.title
})
lodash.forEach(Format.elemTitleMap(), (name, key) => {
ret[key] = `${name}伤加成`
})
return ret
},
formatAttr (ds) {
if (!ds) {
return {}
}
if (lodash.isArray(ds) && ds[0] && ds[1]) {
return {
title: ds[0],
key: ArtisMark.getKeyByTitle(ds[0]),
value: ds[1]
}
}
@ -18,7 +49,7 @@ let ArtisMark = {
return {}
}
return {
title: ds.title || ds.name || ds.key || ds.id || '',
key: ds.key || ArtisMark.getKeyByTitle(ds.title || ds.name || ds.key || ds.id || ''),
value: ds.value || ''
}
},
@ -30,13 +61,14 @@ let ArtisMark = {
* @param isMain
* @returns {{title: *, value: string}|*[]}
*/
formatArti (ds, markCfg = false, isMain = false, elem = '') {
if (ds[0] && ds[0].title) {
formatArti (ds, charAttrCfg = false, isMain = false, elem = '') {
// 若为attr数组
if (ds[0] && (ds[0].title || ds[0].key)) {
let ret = []
let totalUpNum = 0
let ltArr = []
lodash.forEach(ds, (d) => {
let arti = ArtisMark.formatArti(d, markCfg)
let arti = ArtisMark.formatArti(d, charAttrCfg)
totalUpNum += arti.upNum
if (arti.hasLt) {
ltArr.push(arti)
@ -56,51 +88,39 @@ let ArtisMark = {
}
return ret
}
let key = ds.key
let title = ds.title || ds[0]
let key = ''
if (!key) {
key = ArtisMark.getKeyByTitle(title)
} else if (!title) {
title = ArtisMark.getTitleByKey(key)
}
let isDmg = Format.isElem(key)
let val = ds.value || ds[1]
let value = val
let num = ds.value || ds[1]
if (!title || title === 'undefined') {
if (!key || key === 'undefined') {
return {}
}
if (/伤害加成/.test(title) && val < 1) {
val = Format.pct(val * 100)
num = num * 100
} else if (/伤害加成|大|暴|充能|治疗/.test(title)) {
val = Format.pct(val)
} else {
val = Format.comma(val, 1)
}
if (/元素伤害加成/.test(title)) {
title = title.replace('元素伤害', '伤')
let mainElem = Character.matchElem(title)
if (elem && mainElem.elem !== elem) {
key = '_dmg'
} else {
key = 'dmg'
}
} else if (title === '物理伤害加成') {
title = '物伤加成'
key = 'phy'
}
let arrCfg = attrMap[isDmg ? 'dmg' : key]
key = key || attrNameMap[title]
val = Format[arrCfg.format](val, 1)
let ret = {
title,
key,
value: val
}
if (!isMain) {
let incRet = ArtisMark.getIncNum(title, value)
let incRet = ArtisMark.getIncNum(key, value)
ret.upNum = incRet.num
ret.hasGt = incRet.hasGt
ret.hasLt = incRet.hasLt
}
if (markCfg) {
let mark = markCfg[key] * num || 0
if (charAttrCfg) {
let mark = charAttrCfg[key]?.mark * num || 0
if (isMain) {
mark = mark / 4 + 0.01
ret.key = key
@ -111,8 +131,9 @@ let ArtisMark = {
return ret
},
getIncNum (title, value) {
let cfg = attrNameMap[title] && attrMap[attrNameMap[title]]
// 获取升级次数
getIncNum (key, value) {
let cfg = attrMap[key]
if (!value || !cfg || !cfg.value || !cfg.valueMin) {
return { num: 0 }
}
@ -130,6 +151,7 @@ let ArtisMark = {
}
},
// 获取评分档位
getMarkClass (mark) {
let pct = mark
let scoreMap = [['D', 10], ['C', 16.5], ['B', 23.1], ['A', 29.7], ['S', 36.3], ['SS', 42.9], ['SSS', 49.5], ['ACE', 56.1], ['ACE²', 66]]
@ -140,49 +162,31 @@ let ArtisMark = {
}
},
// 获取位置分数
getMark (charCfg, posIdx, mainAttr, subAttr, elem = '') {
let ret = 0
let { mark, maxMark, weight } = charCfg
let mAttr = ArtisMark.getAttr(mainAttr, elem)
let { attrs, posMaxMark } = charCfg
let key = mainAttr.key
let fixPct = 1
posIdx = posIdx * 1
if (posIdx >= 3) {
if (mAttr !== 'recharge') {
fixPct = Math.max(0, Math.min(1, (weight[mAttr] || 0) / (maxMark['m' + posIdx])))
let mainKey = key
if (key !== 'recharge') {
if (posIdx === 4 && Format.isElem(key) && key === elem) {
mainKey = 'dmg'
}
ret += ArtisMark.getAttrMark(mark, mainAttr) / 4
fixPct = Math.max(0, Math.min(1, (attrs[mainKey]?.weight || 0) / (posMaxMark['m' + posIdx])))
}
ret += (attrs[mainKey]?.mark || 0) * (mainAttr.value || 0) / 4
}
lodash.forEach(subAttr, (ds) => {
ret += ArtisMark.getAttrMark(mark, ds)
ret += (attrs[ds.key]?.mark || 0) * (ds.value || 0)
})
return ret * (1 + fixPct) / 2 / posMaxMark[posIdx] * 66
},
return ret * (1 + fixPct) / 2 / maxMark[posIdx] * 66
},
getAttr (ds, elem = '') {
let title = ds.title || ds[0] || ''
let attr = attrNameMap[title]
if (/元素伤害/.test(title)) {
attr = 'dmg'
if (elem && Character.matchElem(title).elem !== elem) {
attr = '_dmg'
}
} else if (/物理|物伤/.test(title)) {
attr = 'phy'
}
return attr
},
getAttrMark (attrMark, ds) {
if (!ds) {
return 0
}
let attr = ArtisMark.getAttr(ds)
if (!attr) {
return 0
}
let val = ds.value || ds[1]
return (attrMark[attr] || 0) * val
},
// 获取位置最高分
getMaxMark (attrs) {
let ret = {}
for (let idx = 1; idx <= 5; idx++) {
@ -208,6 +212,8 @@ let ArtisMark = {
}
return ret
},
// 获取最高分的属性
getMaxAttr (attrs = {}, list2 = [], maxLen = 1, banAttr = '') {
let tmp = []
lodash.forEach(list2, (attr) => {

View File

@ -3,8 +3,8 @@
* @type {{}}
*/
import { Weapon, ProfileAttr, Character } from '../index.js'
import { attrNameMap } from '../../resources/meta/artifact/artis-mark.js'
import { Weapon, ProfileAttr } from '../index.js'
import { Format } from '../../components/index.js'
import { calc as artisBuffs } from '../../resources/meta/artifact/index.js'
import { calc as weaponBuffs } from '../../resources/meta/weapon/index.js'
import lodash from 'lodash'
@ -185,19 +185,11 @@ class AttrCalc {
* @returns {boolean}
*/
calcArtisAttr (ds, char) {
let title = ds.title
let key = attrNameMap[title]
if (/元素伤害/.test(title)) {
let key = ds.key
if (Format.isElem(key) && char.elem === key) {
key = 'dmg'
let elem = Character.matchElem(title)
if (!char.isElem(elem.elem)) {
key = 'dmg2'
}
}
if (/物/.test(title)) {
key = 'phy'
}
if (!key) {
return false
}

View File

@ -9,17 +9,16 @@ async function init () {
let charPath = process.cwd() + '/plugins/miao-plugin/resources/meta/character'
let chars = fs.readdirSync(charPath)
for (let char of chars) {
if (fs.existsSync(`${charPath}/${char}/artis.js`)) {
charCfg[char] = await Data.importModule(`resources/meta/character/${char}/artis.js`)
}
// 允许自定义配置文件,会覆盖喵喵版评分规则
if (fs.existsSync(`${charPath}/${char}/artis_user.js`)) {
charCfg[char] = await Data.importModule(`resources/meta/character/${char}/artis_user.js`)
} else if (fs.existsSync(`${charPath}/${char}/artis.js`)) {
charCfg[char] = await Data.importModule(`resources/meta/character/${char}/artis.js`)
}
}
}
await init()
const CharArtis = {
reduceWeight (weight, key, plus, max) {
let original = weight[key] || 0

View File

@ -12,7 +12,7 @@
{{each artis ds}}
<div class="item arti">
{{if ds && ds.name && ds.main && ds.main.title && ds.main.title!="undefined"}}
{{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>
@ -24,11 +24,12 @@
<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">{{ds.main.title}}</span><span class="val">+{{ds.main.value}}</span></li>
<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.title}}
<li class="{{ds.usefulMark[attr.title]*1 > 79.9 ?`great`:(ds.usefulMark[attr.title]*1>0 ? `useful`:`nouse`)}}">
<span class="title"> {{if attr.upNum}}<i class="up-num up-{{attr.upNum}}"></i>{{/if}}{{attr.title}}</span>
{{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.upNum}}<i class="up-num up-{{attr.upNum}}"></i>{{/if}}{{artisKeyTitle[attr.key]}}</span>
<span class="val">+{{attr.value}}</span></li>
{{/if}}
{{/each}}

View File

@ -11,6 +11,7 @@
{{block 'main'}}
{{set ad = artisDetail}}
<div class="basic">
<div class="main-pic"
style="background-image:url({{_res_path}}{{splash}})"></div>
@ -22,8 +23,8 @@
<div class="item arti-stat">
<div class="arti-class-title">评分规则:{{charCfg.classTitle}}</div>
<div class="arti-stat-ret">
<div><strong class="mark-{{totalMarkClass}}">{{totalMarkClass}}</strong><span>圣遗物评级</span></div>
<div><strong>{{totalMark}}</strong><span>圣遗物总分</span></div>
<div><strong class="mark-{{artisDetail.markClass}}">{{ad.markClass}}</strong><span>圣遗物评级</span></div>
<div><strong>{{ad.mark}}</strong><span>圣遗物总分</span></div>
</div>
</div>
</div>
@ -33,13 +34,13 @@
<div class="artis">
<% for(let idx = 1; idx<=5; idx++) {
let ds = artis[idx]
let ds = ad?.artis[idx]
%>
{{if idx === 1 }}
<div class="item no-bg"></div>
{{/if}}
<div class="item arti {{idx}}">
{{if ds && ds.name && ds.main && ds.main.title && ds.main.title!="undefined"}}
{{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>
@ -50,7 +51,7 @@
</div>
<ul class="detail attr">
<li class="arti-main">
<span class="title">{{ds.main.title}}</span>
<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>
@ -59,9 +60,9 @@
{{/if}}
</li>
{{each ds.attrs attr}}
{{if attr.title}}
<li class="{{usefulMark[attr.title]*1 > 79.9 ?`great`:(usefulMark[attr.title]*1>0 ? `useful`:`nouse`)}}"><span
class="title">{{attr.title}} </span><span
{{if attr.key}}
<li class="{{ad.charWeight[attr.key]*1 > 79.9 ?`great`:(ad.charWeight[attr.key]*1>0 ? `useful`:`nouse`)}}"><span
class="title">{{artisKeyTitle[attr.key]}} </span><span
class="val">+{{attr.value}}</span>
<span class="mark">{{ ( 46.6 / 6 / 100 * attr._mark ).toFixed(1) }}</span>
</li>
@ -73,7 +74,7 @@
<li>
<span class="title">总分对齐</span>
<span class="val">
*{{( 66 / (46.6/6/100 * charCfg.maxMark[idx]) * 100).toFixed(1)}}%
*{{( 66 / (46.6/6/100 * charCfg.posMaxMark[idx]) * 100).toFixed(1)}}%
</span>
</li>
{{if idx>2}}
@ -83,8 +84,8 @@
{{if ds.main.title === '充能效率'}}
*100%
{{else}}
{{set mainWeight = charCfg?.weight[ds.main?.key] || 0}}
*{{(50 + 50 * mainWeight / charCfg.maxMark["m"+idx] ).toFixed(0)}}%
{{set mainWeight = charCfg?.weight[ds.main?.key===data.elem?'dmg':ds.main?.key] || 0}}
*{{(50 + 50 * mainWeight / charCfg.posMaxMark["m"+idx] ).toFixed(0)}}%
{{/if}}
</span>
</li>
@ -115,12 +116,14 @@
<div>副词条最高分</div>
<div>主词条最高分</div>
</div>
{{each attrMap ds key}}{{if ds.type!== "plus" && charCfg.weight[key] > 0}}
{{each attrMap ds key}}
{{if ds.type!== "plus" && charCfg.weight[key] > 0}}
<div class="tr">
<div class="th">{{ds.title}}</div>
<div class="td">{{charCfg.weight[key]}}</div>
<div class="td">{{ds.text}}</div>
<div class="td">{{charCfg.mark[key] > 0 ? (46.6/6 / 100 * charCfg.mark[key]).toFixed(2) : "-"}}</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)}}
&nbsp; &nbsp; -
@ -156,7 +159,7 @@
</div>
<div class="tr">
<div class="th">最高分(对齐前)</div>
{{each charCfg.maxMark m key}}
{{each charCfg.posMaxMark m key}}
{{if key.length === 1}}
<div>{{ mark( m / 6 )}}</div>
{{/if}}
@ -164,7 +167,7 @@
</div>
<div class="tr">
<div class="th">总分对齐比例</div>
{{each charCfg.maxMark m key}}
{{each charCfg.posMaxMark m key}}
{{if key.length === 1}}
<div>{{( 66 / (46.6/6/100 * m) * 100).toFixed(1)}}%</div>
{{/if}}
@ -174,9 +177,9 @@
<div class="th">最优主词缀权重</div>
<div>-</div>
<div>-</div>
<div>{{charCfg.maxMark.m3}}</div>
<div>{{charCfg.maxMark.m4}}</div>
<div>{{charCfg.maxMark.m5}}</div>
<div>{{charCfg.posMaxMark.m3}}</div>
<div>{{charCfg.posMaxMark.m4}}</div>
<div>{{charCfg.posMaxMark.m5}}</div>
</div>
</div>
<ul class="cont-msg">

View File

@ -64,6 +64,7 @@
</div>
{{if mode === "profile" && dataSource !== "input2"}}
{{set ad = artisDetail}}
<div class="artis">
<div>
<div class="item weapon">
@ -78,14 +79,14 @@
<div class="item arti-stat">
<div class="arti-class-title">评分规则:{{classTitle}}</div>
<div class="arti-stat-ret">
<div><strong class="mark-{{totalMarkClass}}">{{totalMarkClass}}</strong><span>圣遗物评级</span></div>
<div><strong>{{totalMark}}</strong><span>圣遗物总分</span></div>
<div><strong class="mark-{{ad.markClass}}">{{ad.markClass}}</strong><span>圣遗物评级</span></div>
<div><strong>{{ad.mark}}</strong><span>圣遗物总分</span></div>
</div>
</div>
</div>
{{each artis ds idx}}
{{each ad.artis ds idx}}
<div class="item arti">
{{if ds && ds.name && ds.main && ds.main.title && ds.main.title!="undefined"}}
{{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>
@ -95,11 +96,12 @@
<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">{{ds.main.title}}</span><span class="val">+{{ds.main.value}}</span></li>
<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.title}}
<li class="{{usefulMark[attr.title]*1 > 79.9 ?`great`:(usefulMark[attr.title]*1>0 ? `useful`:`nouse`)}}">
<span class="title"> {{if attr.upNum}}<i class="up-num up-{{attr.upNum}}"></i>{{/if}}{{attr.title}}</span>
{{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.upNum}}<i class="up-num up-{{attr.upNum}}"></i>{{/if}}{{artisKeyTitle[attr.key]}}</span>
<span class="val">+{{attr.value}}</span>
</li>
{{/if}}

View File

@ -122,12 +122,6 @@ body {
.talent-cont strong {
color: #d3bc8e;
}
.weapon-list {
padding: 3px;
}
.weapon-list .item {
margin: 3px;
}
.char-holding {
display: flex;
padding: 8px;
@ -205,6 +199,13 @@ body {
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;

View File

@ -88,7 +88,8 @@
<div class="cont">
<div class="cont-title border-less">常用武器</div>
<div class="item-list weapon-list">
{{each weapons weapon}}
{{each weapons weapon idx}}
{{if idx <7}}
<div class="item item-card">
<div class="item-icon star{{weapon.star}}">
<div class="item-bg" style="background-image:url({{_res_path}}{{weapon.img}})"></div>
@ -96,6 +97,7 @@
<div class="item-value">{{weapon.value}}</div>
<div class="item-title">{{weapon.abbr}}</div>
</div>
{{/if}}
{{/each}}
</div>
</div>
@ -105,7 +107,8 @@
<div class="cont">
<div class="cont-title border-less">常用圣遗物<span>持有率、武器、圣遗物统计来自胡桃API未经允许请勿使用此数据</span></div>
<div class="item-list weapon-list artis-list">
{{each artis arti}}
{{each artis arti idx}}
{{if idx <7}}
<div class="item item-card">
<div class="item-icon star5 artis-count{{arti.imgs.length}}">
{{each arti.imgs img idx}}
@ -116,6 +119,7 @@
<div class="item-value">{{arti.value}}</div>
<div class="item-title">{{arti.title}}</div>
</div>
{{/if}}
{{/each}}
</div>
</div>

View File

@ -159,14 +159,6 @@ body {
}
}
.weapon-list {
padding: 3px;
.item {
margin: 3px;
}
}
.char-holding {
display: flex;
padding: 8px;
@ -259,6 +251,15 @@ body {
margin-top: -3px;
}
.weapon-list {
padding: 3px;
.item {
margin: 3px 3px 3px 4px;
width: 74px;
}
}
.artis-list {
.item-bg {
background-size: contain;

View File

@ -47,7 +47,7 @@ app.get('/', function (req, res) {
app.get('/:page', function (req, res) {
let [plugin, app, page] = req.params.page.split('_')
if (page == 'favicon.ico') {
if (plugin == 'favicon.ico') {
return res.send('')
}
let data = JSON.parse(fs.readFileSync(_path + `/data/ViewData/${plugin}/${app}_${page}.json`, 'utf8'))