调整圣遗物评分计算逻辑,修正Bug

This commit is contained in:
Kokomi 2023-10-19 15:46:08 +08:00
parent 3096374f4b
commit 20709c437b
18 changed files with 191 additions and 217 deletions

View File

@ -50,8 +50,8 @@ class Artifact extends Base {
}
// 传入为artis对象
if (name.game) {
return Artifact.get(name.id || name.name, name.game)
if (name.id || name.name) {
return Artifact.get(name.id || name.name, name.game || game)
}
if (game === 'sr') {
name = idMapSR[name]?.name || name

View File

@ -1,23 +1,27 @@
import lodash from 'lodash'
import AvatarBase from './avatar/AvatarBase.js'
import { Data, Cfg } from '#miao'
import { Data } from '#miao'
import { ProfileDmg } from './index.js'
import Attr from './attr/Attr.js'
import CharImg from './character/CharImg.js'
import Artis from './artis/Artis.js'
import Profile from './player/Profile.js'
import ArtisMark from './artis/ArtisMark.js'
export default class Avatar extends AvatarBase {
constructor (ds = {}, game = 'gs', calc = true) {
constructor (ds = {}, game = 'gs') {
super(ds, game)
this._artis = new Artis(this.game, true)
if (calc) {
this.calcAttr()
}
}
// 判断当前profileData是否具有有效数据
get hasData () {
return this.isProfile
// 是否是合法面板数据
get isProfile () {
return Profile.isProfile(this)
}
// profile.hasData 别名
get hasData(){
return Profile.isProfile(this)
}
get imgs () {
@ -25,42 +29,19 @@ export default class Avatar extends AvatarBase {
}
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`]
)
}
return CharImg.getCostumeSplash(this)
}
get hasDmg () {
return this.hasData && !!ProfileDmg.dmgRulePath(this.name, this.game)
return this.isProfile && !!ProfileDmg.dmgRulePath(this.name, this.game)
}
get artis () {
return this._artis
}
static create (ds, game = 'gs', calc = true) {
let profile = new Avatar(ds, game, calc)
static create (ds, game = 'gs') {
let profile = new Avatar(ds, game)
if (!profile) {
return false
}
@ -76,9 +57,9 @@ export default class Avatar extends AvatarBase {
}
calcAttr () {
this._attr = Attr.create(this)
this.attr = this._attr.calc(this)
this.base = this._attr.getBase()
let attr = this._attr = this._attr || Attr.create(this)
this.attr = attr.calc()
this.base = attr.getBase()
}
getArtis (isMysArtis = false) {
@ -92,10 +73,7 @@ export default class Avatar extends AvatarBase {
// 获取当前profileData的圣遗物评分withDetail=false仅返回简略信息
getArtisMark (withDetail = true) {
if (this.hasData) {
return this.artis.getMarkDetail(this, withDetail)
}
return {}
return ArtisMark.getMarkDetail(this, withDetail)
}
// 计算当前profileData的伤害信息

View File

@ -232,6 +232,7 @@ export default class Player extends Base {
// 获取指定角色的面板数据
getProfile (id) {
let avatar = this.getAvatar(id)
avatar.calcAttr()
return avatar
}

View File

@ -9,6 +9,7 @@ import { attrMap as attrMapGS } from '../../resources/meta/artifact/index.js'
import { attrMap as attrMapSR } from '../../resources/meta-sr/artifact/index.js'
import ArtisMarkCfg from './ArtisMarkCfg.js'
import ArtisBase from './ArtisBase.js'
import ArtisAttr from './ArtisAttr.js'
export default class Artis extends ArtisBase {
constructor (game = 'gs', isProfile = false) {
@ -18,107 +19,11 @@ export default class Artis extends ArtisBase {
// 有圣遗物词条
get hasAttr () {
if (this.isSr) {
return true
}
return ArtisMark.hasAttr(this.artis)
}
/**
* 获取角色配置
* @returns {{classTitle: *, weight: *, posMaxMark: {}, mark: {}, attrs: {}}}
*/
getCharCfg (profile) {
let char = profile.char
let { game, isGs } = char
let { attrWeight, title } = ArtisMarkCfg.getCharArtisCfg(char, 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
}
return ArtisAttr.hasAttr(this)
}
getMarkDetail (profile, withDetail = true) {
let charCfg = this.getCharCfg(profile)
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
return ArtisMark.getMarkDetail(profile, withDetail)
}
setArtis (idx = 1, ds = {}) {

View File

@ -94,8 +94,22 @@ let AttrSR = {
}
}
export default {
getData (arti, idx = 1, game = 'gs') {
let tmp = game === 'gs' ? AttrGS : AttrSR
return tmp.getData(arti.mainId, arti.attrIds, arti.level, arti.star, idx)
},
hasAttr(arti){
if (arti.isSr) {
return true
}
let ret = true
arti.forEach((ds) => {
if (ds.name) {
return !!(ds.mainId && ds.attrIds)
}
})
return ret
}
}

View File

@ -46,7 +46,7 @@ export default class ArtisBase extends Base {
forEach (fn) {
lodash.forEach(this.artis, (ds, idx) => {
if (ds.name) {
fn(ds, idx)
return fn(ds, idx)
}
})
}

View File

@ -1,23 +1,15 @@
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'
import { Data, Format } from '#miao'
import { attrMap as attrMapGS, attrNameMap, mainAttr as mainAttrGS, subAttr as subAttrGS } from '../../resources/meta/artifact/index.js'
import { attrMap as attrMapSR, mainAttr as mainAttrSR, subAttr as subAttrSR } from '../../resources/meta-sr/artifact/meta.js'
import ArtisMarkCfg from './ArtisMarkCfg.js'
import { Artifact } from '#miao.models'
let ArtisMark = {
// 根据Key获取标题
getKeyByTitle (title, game = 'gs') {
if (/元素伤害加成/.test(title) || Format.isElem(title)) {
let elem = Format.matchElem(title)
return elem
return Format.matchElem(title)
} else if (title === '物理伤害加成') {
return 'phy'
}
@ -110,7 +102,7 @@ let ArtisMark = {
// 获取评分档位
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]]
let scoreMap = [['D', 7], ['C', 14], ['B', 21], ['A', 28], ['S', 35], ['SS', 42], ['SSS', 49], ['ACE', 56], ['MAX', 70]]
for (let idx = 0; idx < scoreMap.length; idx++) {
if (pct < scoreMap[idx][1]) {
return scoreMap[idx][0]
@ -192,17 +184,50 @@ let ArtisMark = {
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
getMarkDetail (profile, withDetail = true) {
if (!profile.isProfile) {
return {}
}
let charCfg = ArtisMarkCfg.getCfg(profile)
let artisRet = {}
let setCount = {}
let totalMark = 0
let { game, artis, elem } = profile
artis.forEach((arti, idx) => {
let mark = ArtisMark.getMark({ charCfg, idx, arti, elem, game })
totalMark += mark
setCount[arti.set] = (setCount[arti.set] || 0) + 1
artisRet[idx] = {
_mark: mark,
mark: Format.comma(mark, 1),
markClass: ArtisMark.getMarkClass(mark)
}
if (withDetail) {
let artifact = Artifact.get(arti, game)
artisRet[idx] = {
...Data.getData(artifact, 'name,abbr,set:setName,img'),
level: arti.level,
main: ArtisMark.formatArti(arti.main, charCfg.attrs, true, game),
attrs: ArtisMark.formatArti(arti.attrs, charCfg.attrs, false, game),
...artisRet[idx]
}
}
})
let setData = artis.getSetData()
artis.mark = totalMark
artis.markClass = ArtisMark.getMarkClass(totalMark / 5)
let ret = {
classTitle: charCfg.classTitle,
artis: artisRet,
mark: Format.comma(totalMark, 1),
_mark: artis.mark,
markClass: artis.markClass,
...Data.getData(setData, 'sets,names,imgs'),
}
return true
if (withDetail) {
ret.charWeight = lodash.mapValues(charCfg.attrs, ds => ds.weight)
}
return ret
}
}

View File

@ -1,6 +1,9 @@
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'
import { attrMap as attrMapGS } from '../../resources/meta/artifact/index.js'
import { attrMap as attrMapSR } from '../../resources/meta-sr/artifact/index.js'
import ArtisMark from './ArtisMark.js'
const weaponCfg = {
磐岩结绿: {
@ -25,9 +28,8 @@ const weaponCfg = {
}
const ArtisMarkCfg = {
getCharArtisCfg (char, profile, artis) {
let { attr, weapon, elem } = profile
getCharArtisCfg (profile) {
let { attr, weapon, elem, char, artis } = profile
let { isGs } = char
let usefulAttr = isGs ? usefulAttrGS : usefulAttrSR
@ -85,12 +87,46 @@ const ArtisMarkCfg = {
}
let charRule = char.getArtisCfg() || function ({ def }) {
return def(usefulAttr[char.name] || { })
return def(usefulAttr[char.name] || {})
}
if (charRule) {
return charRule({ attr, elem, artis, rule, def, weapon, cons: profile.cons })
}
},
getCfg (profile) {
let { char } = profile
let { game, isGs } = char
let { attrWeight, title } = ArtisMarkCfg.getCharArtisCfg(profile)
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
}
}
}
export default ArtisMarkCfg

View File

@ -2,28 +2,18 @@
* 面板属性计算
* @type {{}}
*/
import Base from '../Base.js'
import { Format } from '#miao'
import { Weapon, ArtifactSet } from '#miao.models'
import AttrData from './AttrData.js'
import { weaponBuffs } from '../../resources/meta/weapon/index.js'
import lodash from 'lodash'
class Attr {
class Attr extends Base {
constructor (profile) {
super()
this.profile = profile
this.game = this.char.game
}
get isGs () {
return this.game === 'gs'
}
get isSr () {
return this.game === 'sr'
}
get char () {
return this.profile?.char
this.game = profile.game
}
/**
@ -59,7 +49,8 @@ class Attr {
* @returns {{}}
*/
calc () {
this.attr = AttrData.create(this.char, {})
let profile = this.profile
this.attr = AttrData.create(profile.char, {})
if (this.isGs) {
this.addAttr('recharge', 100, true)
this.addAttr('cpct', 5, true)
@ -78,18 +69,11 @@ class Attr {
addAttr (key, val, isBase = false) {
console.log(key, val, isBase)
if (isNaN(val)) {
cs.log(val)
}
this.attr.addAttr(key, val, isBase)
}
/**
* 计算角色属性
* @param affix
*/
setCharAttr (affix = '') {
// 计算角色属性
setCharAttr () {
let { char, level, promote, trees } = this.profile
let metaAttr = char.detail?.attr || {}
let self = this
@ -174,6 +158,7 @@ class Attr {
}
let wCalcRet = weapon.calcAttr(wData.level, wData.promote)
let self = this
let char = this.profile.char
if (this.isSr) {
// 星铁面板属性
@ -182,7 +167,7 @@ class Attr {
self.addAttr(k, v, true)
})
// 检查武器类型
if (weapon.type === this.char.weapon) {
if (weapon.type === char.weapon) {
// todo sr&gs 统一
let wBuffs = weapon.getWeaponAffixBuffs(wData.affix, true)
lodash.forEach(wBuffs, (buff) => {
@ -221,12 +206,13 @@ class Attr {
* 计算圣遗物属性
*/
setArtisAttr () {
let artis = this.profile?.artis
let profile = this.profile
let artis = profile?.artis
// 计算圣遗物词条
artis.forEach((arti) => {
this.calcArtisAttr(arti.main, this.char)
this.calcArtisAttr(arti.main, profile.char)
lodash.forEach(arti.attrs, (ds) => {
this.calcArtisAttr(ds, this.char)
this.calcArtisAttr(ds, profile.char)
})
})
// 计算圣遗物静态加成
@ -238,7 +224,7 @@ class Attr {
if (!buff.isStatic) {
return true
}
if (buff.elem && !this.char.isElem(buff.elem)) {
if (buff.elem && !profile.char.isElem(buff.elem)) {
return true
}
lodash.forEach(buff.data, (val, key) => {

View File

@ -34,11 +34,6 @@ export default class AvatarBase extends Base {
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)) {

View File

@ -4,6 +4,7 @@
import fs from 'fs'
import lodash from 'lodash'
import sizeOf from 'image-size'
import { Cfg } from '#miao'
const rPath = `${process.cwd()}/plugins/miao-plugin/resources`
const CharImg = {
@ -120,6 +121,8 @@ const CharImg = {
}
return imgs
},
// 获取星铁角色图像资源
getImgsSr (name, talentCons) {
let fileType = 'webp'
const nPath = `/meta-sr/character/${name}/`
@ -144,6 +147,37 @@ const CharImg = {
imgs.cons3 = imgs[talentCons[3]]
imgs.cons5 = imgs[talentCons[5]]
return imgs
},
getCostumeSplash (profile) {
let {char, name} = profile
if (!Cfg.get('costumeSplash', true)) {
return char.getImgs(profile._costume).splash
}
let costume = profile._costume
costume = profile.char.checkCostume(costume) ? '2' : ''
if (!Cfg.get('costumeSplash', true)) {
return this.char.getImgs(profile._costume).splash
}
let nPath = `meta/character/${name}`
let isSuper = false
let talent = profile.talent ? lodash.map(profile.talent, (ds) => ds.original).join('') : ''
if (profile.cons === 6 || ['ACE', 'MAX'].includes(profile.artis?.markClass) || talent === '101010') {
isSuper = true
}
if (isSuper) {
return CharImg.getRandomImg(
[`profile/super-character/${name}`, `profile/normal-character/${name}`],
[`${nPath}/imgs/splash0.webp`, `${nPath}/imgs/splash${costume}.webp`, `/${nPath}/imgs/splash.webp`]
)
} else {
return CharImg.getRandomImg(
[`profile/normal-character/${name}`],
[`${nPath}/imgs/splash${costume}.webp`, `/${nPath}/imgs/splash.webp`]
)
}
}
}
export default CharImg

View File

@ -208,7 +208,7 @@
<li><strong>最优主词缀比例: </strong>对主词条词缀非最优的圣遗物进行评分惩罚。若装备的圣遗物主词条不是当前位置的最高权重主词条或元素杯属性不符则依据权重差值比例进行分数扣减最多扣减50%。主词缀为充能时不进行扣减
</li>
<li><strong>最终得分:</strong>圣遗物最终得分 = 原始总分 * 总分对齐比例 * 最优主词缀比例</li>
<li><strong>得分级别:</strong>ACE²(&gt;56分) / ACE(&gt;49分) / SSS(&gt;42分) / SS(&gt;35分) / S(&gt;28分) / A / B / C / D
<li><strong>得分级别:</strong>MAX(&gt;56分) / ACE(&gt;49分) / SSS(&gt;42分) / SS(&gt;35分) / S(&gt;28分) / A / B / C / D
</li>
</ul>
</div>
@ -225,4 +225,4 @@
<li>目前为角色通用逻辑,后期会补充同角色不同流派(例如血牛钟离、暴力芭芭拉)的判定及评分逻辑,以使评分更加精准</li>
</ul>
</div>
{{/block}}
{{/block}}

View File

@ -514,7 +514,7 @@ body {
font-size: 14px;
}
.mark-ACE,
.mark-ACE² {
.mark-MAX {
color: #e85656;
font-weight: bold;
}
@ -1082,4 +1082,4 @@ body {
.copyright.ad {
font-size: 12px;
}
/*# sourceMappingURL=profile-detail.css.map */
/*# sourceMappingURL=profile-detail.css.map */

View File

@ -635,7 +635,7 @@ body {
}
.mark-ACE,
.mark-ACE² {
.mark-MAX {
color: #e85656;
font-weight: bold;
}

View File

@ -266,11 +266,11 @@ body {
text-align: left;
}
.cont .td-artis.class-ACE,
.cont .td-artis.class-ACE² {
.cont .td-artis.class-MAX {
background: rgba(255, 228, 180, 0.5);
}
.cont .td-artis.class-ACE .artis-mark-class,
.cont .td-artis.class-ACE² .artis-mark-class {
.cont .td-artis.class-MAX .artis-mark-class {
background: #ff5722;
}
.cont .td-artis.class-SSS,
@ -370,4 +370,4 @@ body {
.cont-notice span {
margin-left: 5px;
}
/*# sourceMappingURL=profile-stat.css.map */
/*# sourceMappingURL=profile-stat.css.map */

View File

@ -293,7 +293,7 @@ body {
text-align: left;
&.class- {
&ACE, &ACE² {
&ACE, &MAX {
background: rgba(255, 228, 180, .5);
.artis-mark-class {
@ -415,4 +415,4 @@ body {
span {
margin-left: 5px;
}
}
}

View File

@ -263,7 +263,7 @@ body {
z-index: 10;
}
.char-artis.class-ACE .artis-mark-class,
.char-artis.class-ACE² .artis-mark-class {
.char-artis.class-MAX .artis-mark-class {
background: #ff5722;
}
.char-artis.class-SSS .artis-mark-class,

View File

@ -302,7 +302,7 @@ body {
z-index: 10;
&.class- {
&ACE, &ACE² {
&ACE, &MAX {
.artis-mark-class {
background: #ff5722;
}
@ -408,4 +408,4 @@ body {
font-size: 12px;
color: #aaa
}
}
}