2022-09-25 13:56:10 +00:00
|
|
|
/*
|
|
|
|
* 角色数据
|
|
|
|
*
|
|
|
|
* 支持角色查询及Meta元数据获取
|
|
|
|
* 兼容处理自定义角色
|
|
|
|
* */
|
2022-07-23 20:32:10 +00:00
|
|
|
import lodash from 'lodash'
|
2022-08-18 10:13:42 +00:00
|
|
|
import Base from './Base.js'
|
2023-10-19 20:18:30 +00:00
|
|
|
import { Data, Format, Cfg, Meta } from '#miao'
|
2023-02-13 19:47:22 +00:00
|
|
|
import CharImg from './character/CharImg.js'
|
|
|
|
import CharTalent from './character/CharTalent.js'
|
|
|
|
import CharId from './character/CharId.js'
|
|
|
|
import CharMeta from './character/CharMeta.js'
|
|
|
|
import CharCfg from './character/CharCfg.js'
|
2022-07-23 20:32:10 +00:00
|
|
|
|
2023-10-21 18:54:45 +00:00
|
|
|
let metaKey = 'abbr,star,elem,weapon,talentId,talentCons,eta'.split(',')
|
|
|
|
const detailKey = 'title,allegiance,birth,astro,desc,cncv,jpcv,costume,baseAttr,growAttr,materials,talent,talentData,cons,passive,attr'.split(',')
|
|
|
|
|
2022-03-26 08:21:44 +00:00
|
|
|
class Character extends Base {
|
2023-02-12 11:56:47 +00:00
|
|
|
// 默认获取的数据
|
2023-10-21 18:54:45 +00:00
|
|
|
static _dataKey = 'id,name,abbr,title,star,elem,allegiance,weapon,birthday,astro,cncv,jpcv,desc,talentCons'
|
2023-02-12 11:56:47 +00:00
|
|
|
|
2023-05-14 20:19:33 +00:00
|
|
|
constructor ({ id, name = '', elem = '', game = 'gs' }) {
|
2022-07-23 20:32:10 +00:00
|
|
|
super()
|
2022-09-03 21:08:57 +00:00
|
|
|
// 检查缓存
|
2022-09-04 21:03:23 +00:00
|
|
|
let cacheObj = this._getCache(CharId.isTraveler(id) ? `character:${id}:${elem || 'anemo'}` : `character:${id}`)
|
2022-09-03 21:08:57 +00:00
|
|
|
if (cacheObj) {
|
|
|
|
return cacheObj
|
2022-04-10 05:36:31 +00:00
|
|
|
}
|
2022-09-03 21:08:57 +00:00
|
|
|
// 设置数据
|
2022-09-05 19:02:06 +00:00
|
|
|
this._id = id
|
2022-07-23 20:32:10 +00:00
|
|
|
this.name = name
|
2023-05-14 20:19:33 +00:00
|
|
|
this.game = game
|
2022-09-03 21:08:57 +00:00
|
|
|
if (!this.isCustom) {
|
2023-10-20 08:59:06 +00:00
|
|
|
let meta = Meta.getData(game, 'char', name)
|
2022-09-03 21:08:57 +00:00
|
|
|
this.meta = meta
|
2023-05-14 20:19:33 +00:00
|
|
|
if (this.isGs) {
|
|
|
|
this.elem = Format.elem(elem || meta.elem, 'anemo')
|
|
|
|
}
|
2022-09-03 21:08:57 +00:00
|
|
|
} else {
|
|
|
|
this.meta = {}
|
2022-04-10 05:36:31 +00:00
|
|
|
}
|
2022-09-08 20:34:32 +00:00
|
|
|
return this._cache()
|
2022-03-27 20:58:02 +00:00
|
|
|
}
|
2022-04-08 21:52:05 +00:00
|
|
|
|
2022-10-06 22:20:46 +00:00
|
|
|
// 是否为官方角色
|
|
|
|
get isOfficial () {
|
2023-05-14 20:19:33 +00:00
|
|
|
return this.game === 'sr' || /[12]0\d{6}/.test(this._id)
|
2022-09-05 19:02:06 +00:00
|
|
|
}
|
|
|
|
|
2022-10-06 22:20:46 +00:00
|
|
|
// 是否为实装官方角色
|
|
|
|
get isRelease () {
|
2022-09-30 13:02:24 +00:00
|
|
|
if (this.isCustom) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if (this.eta) {
|
|
|
|
return this.eta * 1 < new Date() * 1
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2022-10-06 22:20:46 +00:00
|
|
|
// 是否为自定义角色
|
|
|
|
get isCustom () {
|
2023-05-14 20:19:33 +00:00
|
|
|
return !this.isOfficial
|
2022-10-06 22:20:46 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 19:02:06 +00:00
|
|
|
get id () {
|
|
|
|
return this.isCustom ? this._id : this._id * 1
|
2022-09-03 21:08:57 +00:00
|
|
|
}
|
|
|
|
|
2023-10-21 18:54:45 +00:00
|
|
|
_get (key) {
|
2023-10-23 02:56:47 +00:00
|
|
|
|
2023-10-21 18:54:45 +00:00
|
|
|
if (metaKey.includes(key)) {
|
|
|
|
return this.meta[key]
|
|
|
|
}
|
|
|
|
if (detailKey.includes(key)) {
|
|
|
|
return this.getDetail()[key]
|
|
|
|
}
|
2023-05-14 20:19:33 +00:00
|
|
|
}
|
|
|
|
|
2022-10-06 22:20:46 +00:00
|
|
|
// 获取短名字
|
2022-09-18 20:54:01 +00:00
|
|
|
get sName () {
|
|
|
|
let name = this.name
|
|
|
|
let abbr = this.abbr
|
|
|
|
return name.length <= 4 ? name : (abbr || name)
|
|
|
|
}
|
|
|
|
|
2022-09-03 21:08:57 +00:00
|
|
|
// 是否是旅行者
|
|
|
|
get isTraveler () {
|
2023-05-14 20:19:33 +00:00
|
|
|
return this.isGs && CharId.isTraveler(this.id)
|
2022-09-03 21:08:57 +00:00
|
|
|
}
|
|
|
|
|
2022-08-31 18:26:36 +00:00
|
|
|
get weaponType () {
|
2022-11-26 08:12:32 +00:00
|
|
|
return this.weapon
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获取武器类型
|
|
|
|
get weaponTypeName () {
|
2023-05-14 20:19:33 +00:00
|
|
|
if (this.isSr) {
|
|
|
|
return this.weapon
|
|
|
|
}
|
2022-08-24 07:05:47 +00:00
|
|
|
const map = {
|
|
|
|
sword: '单手剑',
|
|
|
|
catalyst: '法器',
|
|
|
|
bow: '弓',
|
|
|
|
claymore: '双手剑',
|
|
|
|
polearm: '长柄武器'
|
|
|
|
}
|
2022-11-26 08:12:32 +00:00
|
|
|
let weaponType = this.weaponType || ''
|
2022-08-24 07:05:47 +00:00
|
|
|
return map[weaponType.toLowerCase()] || ''
|
|
|
|
}
|
|
|
|
|
2022-09-03 21:08:57 +00:00
|
|
|
// 获取元素名称
|
|
|
|
get elemName () {
|
2023-05-14 20:19:33 +00:00
|
|
|
if (this.isSr) {
|
|
|
|
return this.elem
|
|
|
|
}
|
2022-11-24 15:27:03 +00:00
|
|
|
return Format.elemName(this.elem)
|
2022-08-24 07:05:47 +00:00
|
|
|
}
|
|
|
|
|
2022-10-06 22:20:46 +00:00
|
|
|
// 获取角色描述
|
2022-09-05 03:32:33 +00:00
|
|
|
get desc () {
|
2023-10-22 18:22:58 +00:00
|
|
|
return CharMeta.getDesc(this.meta?._detail?.desc || '')
|
2022-09-05 03:32:33 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 21:08:57 +00:00
|
|
|
// 获取头像
|
|
|
|
get face () {
|
|
|
|
return this.getImgs().face
|
2022-08-24 07:05:47 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 21:08:57 +00:00
|
|
|
// 获取侧脸图像
|
|
|
|
get side () {
|
2023-05-14 20:19:33 +00:00
|
|
|
if (this.isSr) {
|
|
|
|
return this.getImgs().face
|
|
|
|
}
|
2022-09-03 21:08:57 +00:00
|
|
|
return this.getImgs().side
|
|
|
|
}
|
2022-03-27 20:58:02 +00:00
|
|
|
|
2022-11-23 20:26:07 +00:00
|
|
|
// gacha图像
|
2022-09-24 21:05:22 +00:00
|
|
|
get gacha () {
|
|
|
|
return this.getImgs().gacha
|
|
|
|
}
|
|
|
|
|
2022-11-23 20:26:07 +00:00
|
|
|
// 获取character相关图像
|
2022-09-18 20:54:01 +00:00
|
|
|
get imgs () {
|
|
|
|
return this.getImgs()
|
|
|
|
}
|
|
|
|
|
2022-09-03 21:08:57 +00:00
|
|
|
// 获取详情数据
|
|
|
|
get detail () {
|
|
|
|
return this.getDetail()
|
|
|
|
}
|
2022-04-08 21:52:05 +00:00
|
|
|
|
2022-11-23 20:26:07 +00:00
|
|
|
// 获取命座天赋等级
|
2022-10-18 18:13:23 +00:00
|
|
|
get talentCons () {
|
2023-05-14 20:19:33 +00:00
|
|
|
if (this.isSr) {
|
|
|
|
return this.meta?.talentCons || {}
|
|
|
|
}
|
2022-10-18 18:13:23 +00:00
|
|
|
if (this.isTraveler) {
|
|
|
|
return this.elem === 'dendro' ? { e: 3, q: 5 } : { e: 5, q: 3 }
|
|
|
|
}
|
|
|
|
return this.meta?.talentCons || {}
|
|
|
|
}
|
|
|
|
|
2023-02-12 11:56:47 +00:00
|
|
|
// 获取生日
|
|
|
|
get birthday () {
|
|
|
|
let birth = this.birth
|
|
|
|
if (!birth) {
|
|
|
|
return ''
|
|
|
|
}
|
|
|
|
birth = birth.split('-')
|
|
|
|
return `${birth[0]}月${birth[1]}日`
|
|
|
|
}
|
|
|
|
|
|
|
|
// 基于角色名获取Character
|
2023-05-14 20:19:33 +00:00
|
|
|
static get (val, game = 'gs') {
|
2023-10-20 08:59:06 +00:00
|
|
|
let id = CharId.getId(val, game)
|
2023-02-12 11:56:47 +00:00
|
|
|
if (!id) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return new Character(id)
|
|
|
|
}
|
|
|
|
|
2023-05-14 20:19:33 +00:00
|
|
|
static forEach (fn, type = 'all', game = 'gs') {
|
2023-10-20 08:59:06 +00:00
|
|
|
let ids = Meta.getIds(game, 'char')
|
|
|
|
lodash.forEach(ids, (id) => {
|
|
|
|
let char = Character.get(id)
|
2023-06-26 16:59:05 +00:00
|
|
|
if (char.game !== 'gs') {
|
2023-05-14 20:19:33 +00:00
|
|
|
return true
|
|
|
|
}
|
2023-02-12 11:56:47 +00:00
|
|
|
if (type === 'release' && !char.isRelease) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if (type === 'official' && !char.isOfficial) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return fn(char) !== false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获取排序ID
|
|
|
|
static sortIds (arr) {
|
2023-10-20 08:59:06 +00:00
|
|
|
return arr.sort((a, b) => a * 1 - b * 1)
|
2023-02-12 11:56:47 +00:00
|
|
|
}
|
|
|
|
|
2022-11-23 20:26:07 +00:00
|
|
|
// 获取attr列表
|
2022-09-04 21:03:23 +00:00
|
|
|
getAttrList () {
|
2023-10-22 18:22:58 +00:00
|
|
|
let { baseAttr, growAttr } = this
|
|
|
|
return CharMeta.getAttrList(baseAttr, growAttr, this.elemName)
|
2022-09-04 21:03:23 +00:00
|
|
|
}
|
|
|
|
|
2022-11-23 20:26:07 +00:00
|
|
|
// 获取素材
|
2022-10-07 13:13:46 +00:00
|
|
|
getMaterials (type = 'all') {
|
|
|
|
return CharMeta.getMaterials(this, type)
|
2022-09-04 21:03:23 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 21:08:57 +00:00
|
|
|
// 获取角色character-img图片
|
|
|
|
getCardImg (se = false, def = true) {
|
2022-09-04 06:15:00 +00:00
|
|
|
if (this.name === '旅行者') {
|
|
|
|
return CharImg.getCardImg(['空', '荧'], se, def)
|
2022-04-10 05:36:31 +00:00
|
|
|
}
|
2022-09-04 06:15:00 +00:00
|
|
|
return CharImg.getCardImg(this.name, se, def)
|
2022-04-10 05:36:31 +00:00
|
|
|
}
|
2022-06-05 07:53:13 +00:00
|
|
|
|
2023-05-16 05:04:43 +00:00
|
|
|
// 设置天赋数据
|
2022-11-26 08:12:32 +00:00
|
|
|
getAvatarTalent (talent = {}, cons = 0, mode = 'original') {
|
2023-05-16 05:04:43 +00:00
|
|
|
return CharTalent.getAvatarTalent(this, talent, cons, mode)
|
|
|
|
}
|
|
|
|
|
|
|
|
getTalentKey (id) {
|
|
|
|
if (this.talentId[id]) {
|
|
|
|
return this.talentId[id]
|
|
|
|
}
|
|
|
|
if (this.isSr) {
|
|
|
|
id = (id + '').replace(this.id, '')
|
|
|
|
return {
|
|
|
|
'001': 'a',
|
|
|
|
'002': 'e',
|
|
|
|
'003': 'q',
|
|
|
|
'004': 't',
|
|
|
|
'007': 'z'
|
|
|
|
}[id]
|
|
|
|
}
|
|
|
|
return false
|
2022-06-29 20:40:06 +00:00
|
|
|
}
|
|
|
|
|
2022-11-23 20:26:07 +00:00
|
|
|
// 检查老婆类型
|
2022-08-31 18:26:36 +00:00
|
|
|
checkWifeType (type) {
|
2023-10-21 18:54:45 +00:00
|
|
|
let { wifeData } = Meta.getMeta(this.game, 'char')
|
|
|
|
let key = ['girlfriend', 'boyfriend', 'daughter', 'son'][type] || 'girlfriend'
|
|
|
|
return !!wifeData[key]?.[this.id]
|
2022-06-29 23:05:31 +00:00
|
|
|
}
|
2022-08-31 18:26:36 +00:00
|
|
|
|
2022-11-23 20:26:07 +00:00
|
|
|
// 检查时装
|
2022-08-31 18:26:36 +00:00
|
|
|
checkCostume (id) {
|
2023-10-22 18:22:58 +00:00
|
|
|
let costume = this?.costume || []
|
2022-09-03 21:08:57 +00:00
|
|
|
return costume.includes(id * 1)
|
2022-08-31 18:26:36 +00:00
|
|
|
}
|
2022-09-01 20:09:59 +00:00
|
|
|
|
2022-11-23 20:26:07 +00:00
|
|
|
// 判断是否为某种元素角色
|
2022-11-22 20:25:36 +00:00
|
|
|
isElem (elem = '') {
|
|
|
|
elem = elem.toLowerCase()
|
|
|
|
return this.elem === elem || this.elemName === elem
|
|
|
|
}
|
|
|
|
|
2022-09-04 09:33:14 +00:00
|
|
|
// 获取角色插画
|
2022-09-04 07:59:30 +00:00
|
|
|
getImgs (costume = '') {
|
2023-02-12 11:56:47 +00:00
|
|
|
if (lodash.isArray(costume)) {
|
|
|
|
costume = costume[0]
|
2022-09-10 19:59:45 +00:00
|
|
|
}
|
2023-02-12 11:56:47 +00:00
|
|
|
let costumeIdx = this.checkCostume(costume) ? '2' : ''
|
|
|
|
let cacheId = `costume${costumeIdx}`
|
2022-09-04 07:59:30 +00:00
|
|
|
if (!this._imgs) {
|
|
|
|
this._imgs = {}
|
2022-09-01 20:09:59 +00:00
|
|
|
}
|
2022-11-29 20:55:50 +00:00
|
|
|
if (!this._imgs[cacheId]) {
|
2023-05-14 20:19:33 +00:00
|
|
|
if (this.isSr) {
|
2023-10-09 20:23:08 +00:00
|
|
|
this._imgs[cacheId] = CharImg.getImgsSr(this.name, this.talentCons)
|
2023-05-14 20:19:33 +00:00
|
|
|
} else {
|
|
|
|
this._imgs[cacheId] = CharImg.getImgs(this.name, costumeIdx, this.isTraveler ? this.elem : '', this.weaponType, this.talentCons)
|
|
|
|
}
|
2022-11-29 20:55:50 +00:00
|
|
|
}
|
2023-02-19 21:24:17 +00:00
|
|
|
let imgs = this._imgs[cacheId]
|
|
|
|
return {
|
|
|
|
...imgs,
|
2023-05-14 20:19:33 +00:00
|
|
|
qFace: Cfg.get('qFace') ? (imgs.qFace || imgs.face) : imgs.face
|
2023-02-19 21:24:17 +00:00
|
|
|
}
|
2022-09-03 21:08:57 +00:00
|
|
|
}
|
|
|
|
|
2023-02-12 11:56:47 +00:00
|
|
|
// 基于角色名获取Character
|
|
|
|
|
2022-09-03 21:08:57 +00:00
|
|
|
// 获取详情数据
|
|
|
|
getDetail (elem = '') {
|
2023-10-21 18:54:45 +00:00
|
|
|
if (this.meta?._detail) {
|
|
|
|
return this.meta._detail
|
2022-09-01 20:09:59 +00:00
|
|
|
}
|
2022-09-03 21:08:57 +00:00
|
|
|
if (this.isCustom) {
|
|
|
|
return {}
|
2022-09-01 20:09:59 +00:00
|
|
|
}
|
2022-09-03 21:08:57 +00:00
|
|
|
try {
|
2023-10-21 18:54:45 +00:00
|
|
|
let name = this.isTraveler ? `旅行者/${this.elem}` : this.name
|
2023-10-24 19:34:36 +00:00
|
|
|
this.meta._detail = Data.readJSON(`resources/meta-${this.game}/character/${name}/data.json`, 'miao')
|
2022-09-03 21:08:57 +00:00
|
|
|
} catch (e) {
|
|
|
|
console.log(e)
|
2022-09-01 20:09:59 +00:00
|
|
|
}
|
2023-10-21 18:54:45 +00:00
|
|
|
return this.meta._detail
|
2022-09-03 21:08:57 +00:00
|
|
|
}
|
|
|
|
|
2022-11-23 20:26:07 +00:00
|
|
|
// 获取伤害计算配置
|
2022-11-24 16:31:36 +00:00
|
|
|
getCalcRule () {
|
2022-11-22 20:25:36 +00:00
|
|
|
if (!this._calcRule && this._calcRule !== false) {
|
2022-11-24 16:31:36 +00:00
|
|
|
this._calcRule = CharCfg.getCalcRule(this)
|
2022-11-22 20:25:36 +00:00
|
|
|
}
|
|
|
|
return this._calcRule
|
|
|
|
}
|
2022-11-24 16:31:36 +00:00
|
|
|
|
|
|
|
getArtisCfg () {
|
|
|
|
if (!this._artisRule && this._artisRule !== false) {
|
|
|
|
this._artisRule = CharCfg.getArtisCfg(this)
|
|
|
|
}
|
|
|
|
return this._artisRule
|
|
|
|
}
|
2023-05-18 20:23:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 获取等级属性
|
|
|
|
* @param level
|
|
|
|
* @param promote
|
|
|
|
* @returns {{}|boolean}
|
|
|
|
*/
|
|
|
|
getLvAttr (level, promote) {
|
|
|
|
let metaAttr = this.detail?.attr
|
|
|
|
if (!metaAttr) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if (this.isSr) {
|
|
|
|
let lvAttr = metaAttr[promote]
|
|
|
|
let ret = {}
|
|
|
|
lodash.forEach(lvAttr.attrs, (v, k) => {
|
|
|
|
ret[k] = v * 1
|
|
|
|
})
|
|
|
|
lodash.forEach(lvAttr.grow, (v, k) => {
|
|
|
|
ret[k] = ret[k] * 1 + v * (level - 1)
|
|
|
|
})
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
}
|
2022-05-04 20:53:20 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 20:32:10 +00:00
|
|
|
export default Character
|