调整mys天赋更新逻辑

This commit is contained in:
Kokomi 2023-10-20 00:31:35 +08:00
parent 2993021be9
commit 4eae5af34e
9 changed files with 457 additions and 447 deletions

View File

@ -1,31 +1,32 @@
# 2.4.8 # 2.5.1 dev
* 星铁面板支持面板变换功能 * 重构Models的结构尚未完全完成功能可能不稳定
* 面板变换支持更换圣遗物套装,例如`#甘雨换乐团`、`#镜流换快枪手封印站` * 原神的面板数据迁移至 **/data/PlayerData/gs**
* 微调面板页面的部分样式
# 2.4.1 ~ 2.4.7 # 2.5.0
* 初步支持星铁面板数据获取与展示 * 初步支持星铁面板数据获取与展示
* 可使用`#星铁更新面板`来获取面板信息,通过`#希儿面板`来进行查看 * 可使用`#星铁更新面板`来获取面板信息,通过`#希儿面板`来进行查看
* 星铁面板展示圣遗物评分,评分功能尚未完全完成,分值与样式不为最终版本 * 星铁面板展示圣遗物评分,评分功能尚未完全完成
* 部分角色的伤害计算,以及圣遗物评分功能仍在补全中
* 星铁面板天赋展示更新,支持展示行迹信息 * 星铁面板天赋展示更新,支持展示行迹信息
* 初步增加星铁的排名功能 **@Simplxss**
* 增加`#星铁日历`功能 **@Aluxes**
* 星铁面板支持面板变换功能
* 请配合使用Miao-Yunzai 3.1.0可达到最佳效果 * 请配合使用Miao-Yunzai 3.1.0可达到最佳效果
* Miao-Yunzai可使用`*`来代填`#星铁`前缀能区分游戏使用不同UID * Miao-Yunzai可使用`*`来代填`#星铁`前缀能区分游戏使用不同UID
* 其他Yunzai版本出现原神与星铁UID混淆情况为正常情况请手动切换UID或命令后附加UID查询 * 其他Yunzai版本出现原神与星铁UID混淆情况为正常情况请手动切换UID或命令后附加UID查询
* 角色数据及资源更新
* 增加原神4.0~4.2的角色信息,可通过`#水神天赋`、`#水神图鉴`查看
* 更新星铁1.2~1.3的角色数据与资源
* 伤害计算更新 * 伤害计算更新
* 增加林尼、卡夫卡、银狼的伤害计算**@Aluxes** * 增加林尼、卡夫卡、银狼的伤害计算**@Aluxes**
* 增加原神4.0相关的武器计算 **@SmallK111407** * 增加原神4.0相关的武器计算 **@SmallK111407**
* 增加菲米尼、符玄、玲可、三月七、娜塔莎、罗刹、黑塔的伤害计算 **@Aluxes** * 增加菲米尼、符玄、玲可、三月七、娜塔莎、罗刹、黑塔的伤害计算 **@Aluxes**
* 初步增加星铁的排名功能 **@Simplxss** * 面板功能升级
* 面板变换支持更换圣遗物套装,例如`#甘雨换乐团`、`#镜流换快枪手封印站`
* 增加`#重载面板`功能,用于手工修改面板数据后主动读取
* 微调面板页面的部分样式
* 角色数据及资源更新
* 增加原神4.0~4.2的角色信息,可通过`#水神天赋`、`#水神图鉴`查看
* 更新星铁1.2~1.3的角色数据与资源
* 增加`#喵喵api`命令用于查看喵ApiToken的有效期 * 增加`#喵喵api`命令用于查看喵ApiToken的有效期
* 增加`#星铁日历`功能 **@Aluxes**
* 增加`#重载面板`功能,用于手工修改面板数据后主动读取
* 停用旧面板格式数据非AttrIDs格式的数据不会展示部分角色面板数据不展示是正常情况重新更新面板数据即可
* 一些已知问题修复 * 一些已知问题修复
# 2.4.0 # 2.4.0

View File

@ -53,7 +53,7 @@ let Avatar = {
data = avatar.getDetail() data = avatar.getDetail()
data.imgs = char.imgs data.imgs = char.imgs
data.source = avatar._source data.source = avatar._source
data.artis = avatar.getArtisDetail() data.artis = avatar.getArtisDetail(true)
data.updateTime = moment(new Date(avatar._time)).format('MM-DD HH:mm') data.updateTime = moment(new Date(avatar._time)).format('MM-DD HH:mm')
if (data.hasTalent) { if (data.hasTalent) {
data.talent = avatar.talent data.talent = avatar.talent

View File

@ -9,6 +9,9 @@ const ProfileStat = {
async avatarList (e) { async avatarList (e) {
return ProfileStat.render(e, true) return ProfileStat.render(e, true)
}, },
// 渲染
// isAvatarList true:练度统计 false角色列表
async render (e, isAvatarList = false) { async render (e, isAvatarList = false) {
// 缓存时间,单位小时 // 缓存时间,单位小时
let msg = e.msg.replace('#', '').trim() let msg = e.msg.replace('#', '').trim()

View File

@ -1,19 +1,259 @@
import lodash from 'lodash' import lodash from 'lodash'
import { Data } from '#miao' import { Data, Format } from '#miao'
import { ProfileDmg } from './index.js' import { Character, ProfileDmg, Weapon } from './index.js'
import AvatarBase from './avatar/AvatarBase.js' import Base from './Base.js'
import Attr from './attr/Attr.js' import Attr from './attr/Attr.js'
import Artis from './artis/Artis.js' import Artis from './artis/Artis.js'
import ProfileAvatar from './avatar/ProfileAvatar.js' import ProfileAvatar from './avatar/ProfileAvatar.js'
import ArtisMark from './artis/ArtisMark.js' import ArtisMark from './artis/ArtisMark.js'
import moment from 'moment'
export default class Avatar extends AvatarBase { const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName'.split(',')
export default class Avatar extends Base {
constructor (ds = {}, game = 'gs') { constructor (ds = {}, game = 'gs') {
super(ds, game) 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._mysArtis = new Artis(this.game)
this._artis = new Artis(this.game, true) this._artis = new Artis(this.game, true)
} }
get hasTalent () {
return this.talent && !lodash.isEmpty(this.talent) && !!this._talent
}
get name () {
return this.char?.name || ''
}
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)
}
// 已经到达当前等级的最大天赋
get isMaxTalent () {
let maxLv = [1, 2, 4, 6, 8, 10]?.[this.promote - 1] || 10
let minTalent = lodash.min(lodash.map(this.talent, (ds) => ds.original))
if (this.name === '卡维') {
console.log(
'kaka', maxLv, minTalent, this.promote
)
}
return minTalent >= maxLv
}
get mysArtis () {
return this._mysArtis
}
/**
* 获取圣遗物套装属性
* @returns {boolean|*|{imgs: *[], names: *[], sets: {}, abbrs: *[], sName: string, name: (string|*)}|{}}
*/
get artisSet () {
return this.mysArtis.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 ''
}
_get (key) {
if (charKey.includes(key)) {
return this.char[key]
}
}
/**
* 设置角色基础数据
* @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 = Math.max((ds.promote ? ds.promote : this.promote) * 1 || 0, Attr.calcPromote(this.level))
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 //最后更新时间包括mys
this._talent = ds._talent || this._talent || ds._time || now // 最后天赋更新时间包括mys
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) ? Attr.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
}
}
getProfile () {
if (!this.isProfile) {
return false
}
return this
}
// 判断当前profileData是否具备有效圣遗物信息
hasArtis () {
return this.isProfile && this.artis.length > 0
}
// 获取数据详情
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')
}
}
}
get isAvatar () { get isAvatar () {
return true return true
} }
@ -25,7 +265,7 @@ export default class Avatar extends AvatarBase {
// profile.hasData 别名 // profile.hasData 别名
get hasData () { get hasData () {
return !!(this.level > 1 || this?.weapon?.name || this?.talent?.a) return !!(this.level > 1 || this?.weapon?.name)
} }
get imgs () { get imgs () {
@ -52,8 +292,19 @@ export default class Avatar extends AvatarBase {
return profile return profile
} }
setAvatarBase (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)
let artis = ds.mysArtis || ds.artis
// 只要具备圣遗物信息就更新mysArtis
this._mysArtis.setArtisData(artis)
delete this._now
}
setAvatar (ds, source = '') { setAvatar (ds, source = '') {
super.setAvatar(ds, source) this.setAvatarBase(ds, source)
if (ds.artis && source !== 'mys') { if (ds.artis && source !== 'mys') {
this._artis.setArtisData(ds.artis) this._artis.setArtisData(ds.artis)
} }
@ -101,8 +352,11 @@ export default class Avatar extends AvatarBase {
'name,id,elem,level,promote,cons,talent:originalTalent,trees' 'name,id,elem,level,promote,cons,talent:originalTalent,trees'
let ret = { let ret = {
...this.getData(keys), ...this.getData(keys),
weapon: Data.getData(this.weapon, this.isGs ? 'name,level,promote,affix' : 'id,level,promote,affix'), weapon: Data.getData(this.weapon, this.isGs ? 'name,level,promote,affix' : 'id,level,promote,affix')
artis: this.artis.toJSON() }
let artis = this.artis.toJSON()
if (!lodash.isEmpty(artis)) {
ret.artis = artis
} }
if (!this.mysArtis.isSameArtis(this.artis)) { if (!this.mysArtis.isSameArtis(this.artis)) {
ret.mysArtis = this.mysArtis.toJSON() ret.mysArtis = this.mysArtis.toJSON()
@ -112,4 +366,8 @@ export default class Avatar extends AvatarBase {
...this.getData('_source,_time,_update,_talent') ...this.getData('_source,_time,_update,_talent')
} }
} }
getArtisDetail (mysArtis = false) {
return (mysArtis ? this.mysArtis : this.artis).getDetail()
}
} }

View File

@ -178,6 +178,10 @@ export default class Player extends Base {
// 设置角色数据 // 设置角色数据
setAvatar (ds, source = '') { setAvatar (ds, source = '') {
let avatar = this.getAvatar(ds.id, true) let avatar = this.getAvatar(ds.id, true)
if (!avatar.setAvatar) {
console.log(this._avatars)
console.log(avatar, ds)
}
avatar.setAvatar(ds, source) avatar.setAvatar(ds, source)
} }
@ -206,6 +210,7 @@ export default class Player extends Base {
id = avatars['10000005'] ? 10000005 : 10000007 id = avatars['10000005'] ? 10000005 : 10000007
} }
} }
if (!avatars[id]) { if (!avatars[id]) {
if (create) { if (create) {
avatars[id] = Avatar.create({ id }, this.game) avatars[id] = Avatar.create({ id }, this.game)
@ -213,16 +218,14 @@ export default class Player extends Base {
return false return false
} }
} }
let avatar = avatars[id] let avatar = avatars[id]
if (!avatar.isAvatar) { if (!avatar.isAvatar) {
let data = avatars[id] let data = avatars[id]
avatar = avatars[id] = Avatar.create(avatars[id], this.game) avatar = avatars[id] = Avatar.create(avatars[id], this.game)
avatar.setAvatar(data) avatar.setAvatar(data)
} }
if (avatar.hasData) { return avatar
return avatar
}
return false
} }
// 循环Avatar // 循环Avatar
@ -321,6 +324,17 @@ export default class Player extends Base {
return await MysAvatar.refreshTalent(this, ids, force) return await MysAvatar.refreshTalent(this, ids, force)
} }
/**
* 刷新角色数据
*
* @param cfg
* @param cfg.detail mys-detail数据更新级别角色列表与详情
* @param cfg.talent mys-talent数据更新级别角色天赋数据
* @param cfg.index mys-index数据更新级别游戏统计数据
* @param cfg.profile 刷新面板数据
* @param cfg.ids 刷新的角色列表
*/
async refresh (cfg) { async refresh (cfg) {
this.save(false) this.save(false)
try { try {
@ -331,7 +345,7 @@ export default class Player extends Base {
await this.refreshMysDetail(cfg.detail) await this.refreshMysDetail(cfg.detail)
} }
if (cfg.talent || cfg.talent === 0) { if (cfg.talent || cfg.talent === 0) {
await this.refreshTalent(cfg.ids, cfg.talent) await this.refreshTalent(cfg.ids || '', cfg.talent)
} }
if (cfg.profile || cfg.profile === 0) { if (cfg.profile || cfg.profile === 0) {
await this.refreshProfile(cfg.profile) await this.refreshProfile(cfg.profile)
@ -343,6 +357,18 @@ export default class Player extends Base {
this.save(true) this.save(true)
} }
/**
* 刷新并获取角色数据
*
* @param cfg
* @param cfg.detail mys-detail数据更新级别角色列表与详情
* @param cfg.talent mys-talent数据更新级别角色天赋数据
* @param cfg.index mys-index数据更新级别游戏统计数据
* @param cfg.retType 返回类型默认id为key对象设置为array时返回数组
* @param cfg.rank 返回为数组时数据是否排序排序规则等级星级天赋命座武器好感的顺序排序
* @returns {Promise<any[]|{}>}
*/
async refreshAndGetAvatarData (cfg) { async refreshAndGetAvatarData (cfg) {
await this.refresh(cfg) await this.refresh(cfg)
@ -360,8 +386,9 @@ export default class Player extends Base {
avatarRet[ds.id] = ds avatarRet[ds.id] = ds
let profile = avatar.getProfile() let profile = avatar.getProfile()
if (profile) { if (avatar.isProfile) {
let mark = profile.getArtisMark(false) ds.artisSet = avatar.artis.getSetData()
let mark = avatar.getArtisMark(false)
ds.artisMark = Data.getData(mark, 'mark,markClass,names') ds.artisMark = Data.getData(mark, 'mark,markClass,names')
if (rank) { if (rank) {
rank.getRank(profile) rank.getRank(profile)

View File

@ -2,33 +2,137 @@
* 面板圣遗物 * 面板圣遗物
*/ */
import lodash from 'lodash' import lodash from 'lodash'
import { Artifact, ArtifactSet, Character } from '#miao.models' import { Artifact, ArtifactSet } from '#miao.models'
import { Data, Format } from '#miao' import { Data, Format } from '#miao'
import ArtisMark from './ArtisMark.js' import Base from '../Base.js'
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' import ArtisAttr from './ArtisAttr.js'
import ArtisSet from './ArtisSet.js'
import ArtisMark from './ArtisMark.js'
export default class Artis extends ArtisBase { export default class Artis extends Base {
constructor (game = 'gs', isProfile = false) { constructor (game = 'gs', isProfile = false) {
super(game) super()
this.game = game
this.artis = {}
this.isProfile = !!isProfile this.isProfile = !!isProfile
} }
// 获取圣遗物套装数据
getSetData () {
return ArtisSet.getSetData(this)
}
get sets () {
return this.getSetData().sets || {}
}
get names () {
return this.getSetData().names || []
}
// 有圣遗物数据
get hasArtis () {
return !lodash.isEmpty(this.artis)
}
_get (key) {
let artis = this.artis
switch (key) {
case 'length':
return lodash.keys(artis).length
}
if (artis[key]) {
return artis[key]
}
}
forEach (fn) {
lodash.forEach(this.artis, (ds, idx) => {
if (ds.name) {
return fn(ds, idx)
}
})
}
eachIdx (fn) {
for (let idx = 1; idx <= (this.isGs ? 5 : 6); idx++) {
this.artis[idx] = this.artis[idx] || {}
let ret = fn(this.artis[idx], idx)
if (ret === false) {
break
}
}
}
setArtisData (ds = {}) {
this.eachIdx((arti, idx) => {
this.setArtis(idx, ds[idx] || ds[`arti${idx}`] || {})
})
}
getDetail () {
let ret = {}
for (let idx = 1; idx <= 5; idx++) {
let ds = this.artis[idx]
if (ds && (ds.name || ds.id)) {
let artis = Artifact.get(ds)
if (!artis) {
continue
}
let tmp = {
...artis?.getData('img,name,set'),
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
}
eachArtisSet (fn) {
ArtifactSet.eachSet(this.sets, fn, this.game)
}
// 有圣遗物词条 // 有圣遗物词条
get hasAttr () { get hasAttr () {
return ArtisAttr.hasAttr(this) return ArtisAttr.hasAttr(this)
} }
getMarkDetail (profile, withDetail = true) { setArtisBase (idx = 1, ds = {}) {
return ArtisMark.getMarkDetail(profile, withDetail) this.artis[idx] = this.artis[idx] || {}
let arti = this.artis[idx]
if (this.isSr) {
let 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
} 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
}
} }
setArtis (idx = 1, ds = {}) { setArtis (idx = 1, ds = {}) {
idx = idx.toString().replace('arti', '') * 1 || 1 idx = idx.toString().replace('arti', '') * 1 || 1
super.setArtis(idx, ds) this.setArtisBase(idx, ds)
if (!this.isProfile) { if (!this.isProfile) {
return return
} }
@ -55,14 +159,24 @@ export default class Artis extends ArtisBase {
toJSON () { toJSON () {
let ret = {} let ret = {}
this.eachIdx((ds, idx) => { this.eachIdx((ds, idx) => {
let tmp = this.isGs ? { name: ds.name } : { id: ds.id } let key = this.isGs ? 'name' : 'id'
tmp.level = ds.level || 1 let tmp = {
tmp.star = ds.star || 5 level: ds.level || 1,
ret[idx] = tmp star: ds.star || 5
// 如果不为面板数据则不保存mainId和attrIds }
if (!this.isProfile) { if (!ds[key]) {
return true return true
} }
tmp[key] = ds[key]
// 如果不为面板数据则不保存mainId和attrIds
if (!this.isProfile) {
ret[idx] = tmp
return true
}
if (!ds.mainId || !ds.attrIds) {
return true
}
ret[idx] = tmp
tmp.mainId = ds.mainId || ds.main?.id tmp.mainId = ds.mainId || ds.main?.id
if (this.isSr) { if (this.isSr) {
tmp.attrIds = [] tmp.attrIds = []
@ -126,7 +240,7 @@ export default class Artis extends ArtisBase {
let k = (ds) => [ds?.name || '', ds?.level || '', ds?.star || ''].join('|') let k = (ds) => [ds?.name || '', ds?.level || '', ds?.star || ''].join('|')
let ret = true let ret = true
this.eachIdx((ds, idx) => { this.eachIdx((ds, idx) => {
if (k[ds] !== k(target[idx])) { if (k(ds) !== k(target[idx])) {
return ret = false return ret = false
} }
}) })

View File

@ -1,120 +0,0 @@
/**
* 面板圣遗物
*/
import lodash from 'lodash'
import Base from '../Base.js'
import { Artifact, ArtifactSet } from '#miao.models'
import ArtisMark from './ArtisMark.js'
import ArtisSet from './ArtisSet.js'
export default class ArtisBase extends Base {
constructor (game = 'gs') {
super()
this.game = game
this.artis = {}
}
// 获取圣遗物套装数据
getSetData () {
return ArtisSet.getSetData(this)
}
get sets () {
return this.getSetData().sets || {}
}
get names () {
return this.getSetData().names || []
}
// 有圣遗物数据
get hasArtis () {
return !lodash.isEmpty(this.artis)
}
_get (key) {
let artis = this.artis
switch (key) {
case 'length':
return lodash.keys(artis).length
}
if (artis[key]) {
return artis[key]
}
}
forEach (fn) {
lodash.forEach(this.artis, (ds, idx) => {
if (ds.name) {
return fn(ds, idx)
}
})
}
eachIdx (fn) {
for (let idx = 1; idx <= (this.isGs ? 5 : 6); idx++) {
this.artis[idx] = this.artis[idx] || {}
let ret = fn(this.artis[idx], idx)
if (ret === false) {
break
}
}
}
setArtisData (ds = {}) {
this.eachIdx((arti, idx) => {
this.setArtis(idx, ds[idx] || ds[`arti${idx}`] || {})
})
}
setArtis (idx = 1, ds = {}) {
this.artis[idx] = this.artis[idx] || {}
let arti = this.artis[idx]
if (this.isSr) {
let 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
} 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
}
}
getDetail () {
let ret = {}
for (let idx = 1; idx <= 5; idx++) {
let ds = this.artis[idx]
if (ds) {
let artis = Artifact.get(ds.name)
let tmp = {
...artis?.getData('img,name,set'),
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
}
eachArtisSet (fn) {
ArtifactSet.eachSet(this.sets, fn, this.game)
}
}

View File

@ -1,276 +0,0 @@
import lodash from 'lodash'
import Base from '../Base.js'
import moment from 'moment'
import { Character, Avatar, Weapon } from '#miao.models'
import { Data, Format } from '#miao'
import Attr from '../attr/Attr.js'
import Artis from '../artis/Artis.js'
const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName'.split(',')
export default class AvatarBase 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._mysArtis = new Artis(this.game)
}
get hasTalent () {
return this.talent && !lodash.isEmpty(this.talent) && !!this._talent
}
get name () {
return this.char?.name || ''
}
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)
}
// 已经到达当前等级的最大天赋
get isMaxTalent () {
let maxLv = [1, 2, 4, 6, 8, 10]?.[this.promote - 1] || 10
let minTalent = lodash.min(lodash.map(this.talent, (ds) => ds.original))
return minTalent >= maxLv
}
get artis () {
return this._mysArtis
}
get mysArtis () {
return this._mysArtis
}
/**
* 获取圣遗物套装属性
* @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 AvatarBase(ds, game)
if (!avatar) {
return false
}
return avatar
}
_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)
let artis = ds.mysArtis || ds.artis
// 只要具备圣遗物信息就更新mysArtis
this._mysArtis.setArtisData(artis)
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 || Attr.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 //最后更新时间包括mys
this._talent = ds._talent || this._talent || ds._time || now // 最后天赋更新时间包括mys
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) ? Attr.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) {
this.mysArtis.setArtisData(ds.mysArtis || ds.artis)
}
getProfile () {
if (!this.isProfile) {
return false
}
return Avatar.create(this, this.game)
}
// 判断当前profileData是否具备有效圣遗物信息
hasArtis () {
return this.isProfile && this.artis.length > 0
}
// 获取数据详情
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()
}
}

View File

@ -5,6 +5,7 @@ import { chestInfo } from '../../resources/meta/info/index.js'
import AvatarUtil from './AvatarUtil.js' import AvatarUtil from './AvatarUtil.js'
const MysAvatar = { const MysAvatar = {
// 检查更新force值
checkForce (player, force) { checkForce (player, force) {
let e = player?.e let e = player?.e
let mys = e?._mys let mys = e?._mys
@ -15,6 +16,8 @@ const MysAvatar = {
if (!ck || player._ck === ck) { if (!ck || player._ck === ck) {
return force return force
} }
return force
// 暂时不处理ck变更
player._info = 0 player._info = 0
player._mys = 0 player._mys = 0
player.forEachAvatar((avatar) => { player.forEachAvatar((avatar) => {
@ -209,10 +212,10 @@ const MysAvatar = {
// 并发5请求天赋数据 // 并发5请求天赋数据
await Data.asyncPool(5, needReqIds, async (id) => { await Data.asyncPool(5, needReqIds, async (id) => {
let avatar = player.getAvatar(id) let avatar = player.getAvatar(id)
if (!avatar || avatar.isMaxTalent) { if (avatar) {
return false return false
} }
if (failCount > 5) { if (avatar.isMaxTalent || failCount > 5) {
avatar.setTalent(false, 'original', true) avatar.setTalent(false, 'original', true)
return false return false
} }