2023-10-24 19:34:36 +00:00
|
|
|
|
import fs from 'node:fs'
|
2022-08-22 20:53:31 +00:00
|
|
|
|
import lodash from 'lodash'
|
2022-08-18 10:13:42 +00:00
|
|
|
|
import Base from './Base.js'
|
|
|
|
|
import { Character } from './index.js'
|
2023-10-19 09:48:52 +00:00
|
|
|
|
import DmgBuffs from './dmg/DmgBuffs.js'
|
|
|
|
|
import DmgAttr from './dmg/DmgAttr.js'
|
|
|
|
|
import DmgCalc from './dmg/DmgCalc.js'
|
2023-10-29 07:51:31 +00:00
|
|
|
|
import { MiaoError, Meta, Common } from '#miao'
|
2024-05-21 18:05:37 +00:00
|
|
|
|
import { miaoPath } from '#miao.path'
|
2022-08-18 10:13:42 +00:00
|
|
|
|
|
|
|
|
|
export default class ProfileDmg extends Base {
|
2024-04-13 12:33:08 +00:00
|
|
|
|
constructor (profile = {}, game = 'gs') {
|
2022-08-18 10:13:42 +00:00
|
|
|
|
super()
|
|
|
|
|
this.profile = profile
|
2023-05-21 18:13:38 +00:00
|
|
|
|
this.game = game
|
2023-11-01 19:14:09 +00:00
|
|
|
|
this._update = profile._update
|
2022-08-18 10:13:42 +00:00
|
|
|
|
if (profile && profile.id) {
|
|
|
|
|
let { id } = profile
|
|
|
|
|
this.char = Character.get(id)
|
|
|
|
|
}
|
2022-08-22 20:53:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-21 18:13:38 +00:00
|
|
|
|
static dmgRulePath (name, game = 'gs') {
|
2023-10-29 07:51:31 +00:00
|
|
|
|
let dmgFile = [
|
|
|
|
|
{ file: 'calc_user', name: '自定义伤害' },
|
|
|
|
|
{ file: 'calc_auto', name: '组团伤害', test: () => Common.cfg('teamCalc') },
|
|
|
|
|
{ file: 'calc', name: '喵喵' }
|
|
|
|
|
]
|
|
|
|
|
for (let ds of dmgFile) {
|
2024-05-21 18:05:37 +00:00
|
|
|
|
let path = `${miaoPath}/resources/meta-${game}/character/${name}/${ds.file}.js`
|
2023-10-29 07:51:31 +00:00
|
|
|
|
if (ds.test && !ds.test()) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2023-10-24 19:34:36 +00:00
|
|
|
|
if (fs.existsSync(path)) {
|
2023-10-29 07:51:31 +00:00
|
|
|
|
return { path, createdBy: ds.name }
|
2023-10-24 19:34:36 +00:00
|
|
|
|
}
|
2022-11-08 22:04:08 +00:00
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-22 20:53:31 +00:00
|
|
|
|
// 获取天赋数据
|
|
|
|
|
talent () {
|
|
|
|
|
let char = this.char
|
|
|
|
|
let profile = this.profile
|
|
|
|
|
let ret = {}
|
|
|
|
|
let talentData = profile.talent || {}
|
2022-11-20 20:45:27 +00:00
|
|
|
|
let detail = char.detail
|
2023-05-21 18:13:38 +00:00
|
|
|
|
let { isSr, isGs } = this
|
2023-11-17 15:24:13 +00:00
|
|
|
|
lodash.forEach((isSr ? 'a,a2,e,e2,q,q2,t' : 'a,e,q').split(','), (key) => {
|
2022-12-17 04:37:55 +00:00
|
|
|
|
let level = lodash.isNumber(talentData[key]) ? talentData[key] : (talentData[key]?.level || 1)
|
2023-11-17 18:58:57 +00:00
|
|
|
|
let keyRet = /^(a|e|q)2$/.exec(key)
|
|
|
|
|
if (keyRet) {
|
|
|
|
|
let tmpKey = keyRet[1]
|
2023-09-06 09:29:48 +00:00
|
|
|
|
level = lodash.isNumber(talentData[tmpKey]) ? talentData[tmpKey] : (talentData[tmpKey]?.level || 1)
|
|
|
|
|
}
|
2022-08-22 20:53:31 +00:00
|
|
|
|
let map = {}
|
2023-05-21 18:13:38 +00:00
|
|
|
|
if (isGs && detail.talentData) {
|
|
|
|
|
lodash.forEach(detail.talentData[key], (ds, key) => {
|
2022-11-20 20:45:27 +00:00
|
|
|
|
map[key] = ds[level - 1]
|
2022-08-22 20:53:31 +00:00
|
|
|
|
})
|
2023-07-30 07:15:11 +00:00
|
|
|
|
} else if (isSr && detail.talent && detail.talent[key]) {
|
2023-05-21 18:13:38 +00:00
|
|
|
|
lodash.forEach(detail.talent[key].tables, (ds) => {
|
|
|
|
|
map[ds.name] = ds.values[level - 1]
|
2022-11-20 20:45:27 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
2022-08-22 20:53:31 +00:00
|
|
|
|
ret[key] = map
|
|
|
|
|
})
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-21 18:13:38 +00:00
|
|
|
|
trees () {
|
|
|
|
|
let ret = {}
|
|
|
|
|
let reg = /\d{4}(\d{3})/
|
|
|
|
|
lodash.forEach(this.profile.trees, (t) => {
|
|
|
|
|
let regRet = reg.exec(t)
|
|
|
|
|
if (regRet && regRet[1]) {
|
|
|
|
|
ret[regRet[1]] = true
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-22 20:53:31 +00:00
|
|
|
|
// 获取buff列表
|
|
|
|
|
getBuffs (buffs) {
|
2023-05-21 18:13:38 +00:00
|
|
|
|
return DmgBuffs.getBuffs(this.profile, buffs, this.game)
|
2022-08-22 20:53:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getCalcRule () {
|
2023-11-13 08:37:07 +00:00
|
|
|
|
let ruleName = this.char?.name
|
|
|
|
|
if (['空', '荧'].includes(ruleName)) {
|
|
|
|
|
ruleName = `旅行者/${this.profile.elem}`
|
|
|
|
|
}
|
|
|
|
|
const cfgPath = ProfileDmg.dmgRulePath(ruleName, this.char?.game)
|
2022-08-22 20:53:31 +00:00
|
|
|
|
let cfg = {}
|
2022-11-08 22:04:08 +00:00
|
|
|
|
if (cfgPath) {
|
2023-10-29 07:51:31 +00:00
|
|
|
|
cfg = await import(`file://${cfgPath.path}`)
|
|
|
|
|
// 文件中定义了createBy的话,优先进行展示
|
|
|
|
|
let createdBy = cfg.createdBy || cfgPath.createdBy || '喵喵'
|
|
|
|
|
createdBy = createdBy.slice(0, 15)
|
2022-08-22 20:53:31 +00:00
|
|
|
|
return {
|
2023-10-29 07:51:31 +00:00
|
|
|
|
createdBy,
|
2022-08-22 20:53:31 +00:00
|
|
|
|
details: cfg.details || false, // 计算详情
|
|
|
|
|
buffs: cfg.buffs || [], // 角色buff
|
|
|
|
|
defParams: cfg.defParams || {}, // 默认参数,一般为空
|
|
|
|
|
defDmgIdx: cfg.defDmgIdx || -1, // 默认详情index
|
2022-11-08 22:04:08 +00:00
|
|
|
|
defDmgKey: cfg.defDmgKey || '',
|
2022-08-22 20:53:31 +00:00
|
|
|
|
mainAttr: cfg.mainAttr || 'atk,cpct,cdmg', // 伤害属性
|
2023-05-21 18:13:38 +00:00
|
|
|
|
enemyName: cfg.enemyName || this.isGs ? '小宝' : '弱点敌人' // 敌人名称
|
2022-08-22 20:53:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
2022-08-18 10:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-11 19:20:56 +00:00
|
|
|
|
async calcData ({ enemyLv = 91, mode = 'profile', dmgIdx = 0, idxIsInput = false }) {
|
2022-08-18 10:13:42 +00:00
|
|
|
|
if (!this.char || !this.profile) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2022-08-22 20:53:31 +00:00
|
|
|
|
let { profile } = this
|
2023-05-21 18:13:38 +00:00
|
|
|
|
let { game } = this.char
|
2023-05-23 19:30:30 +00:00
|
|
|
|
let sp = this.detail?.sp
|
2022-08-22 20:53:31 +00:00
|
|
|
|
let charCalcData = await this.getCalcRule()
|
2022-08-18 10:13:42 +00:00
|
|
|
|
|
|
|
|
|
if (!charCalcData) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2023-10-29 07:51:31 +00:00
|
|
|
|
let { createdBy, buffs, details, defParams, mainAttr, defDmgIdx, defDmgKey, enemyName } = charCalcData
|
2022-08-22 20:53:31 +00:00
|
|
|
|
|
|
|
|
|
let talent = this.talent()
|
2022-08-18 10:13:42 +00:00
|
|
|
|
|
|
|
|
|
let meta = {
|
2023-10-06 23:44:15 +00:00
|
|
|
|
level: profile.level,
|
2022-08-18 10:13:42 +00:00
|
|
|
|
cons: profile.cons * 1,
|
2023-05-21 18:13:38 +00:00
|
|
|
|
talent,
|
2024-05-23 16:12:25 +00:00
|
|
|
|
trees: this.trees(),
|
|
|
|
|
weapon: profile.weapon
|
2022-08-18 10:13:42 +00:00
|
|
|
|
}
|
2023-05-21 18:13:38 +00:00
|
|
|
|
|
2023-11-27 20:18:06 +00:00
|
|
|
|
let { id, weapon, attr, artis } = profile
|
2022-08-18 10:13:42 +00:00
|
|
|
|
|
2024-04-13 10:20:19 +00:00
|
|
|
|
defDmgKey = lodash.isFunction(defDmgKey) ? defDmgKey(meta) : defDmgKey
|
|
|
|
|
defDmgIdx = lodash.isFunction(defDmgIdx) ? defDmgIdx(meta) : defDmgIdx
|
|
|
|
|
defParams = lodash.isFunction(defParams) ? defParams(meta) : defParams || {}
|
2022-08-18 10:13:42 +00:00
|
|
|
|
|
2023-05-23 19:30:30 +00:00
|
|
|
|
let originalAttr = DmgAttr.getAttr({ id, weapon, attr, char: this.char, game, sp })
|
2022-08-18 10:13:42 +00:00
|
|
|
|
|
2022-08-22 20:53:31 +00:00
|
|
|
|
buffs = this.getBuffs(buffs)
|
2022-08-18 10:13:42 +00:00
|
|
|
|
|
2023-11-27 20:18:06 +00:00
|
|
|
|
let { msg } = DmgAttr.calcAttr({ originalAttr, buffs, artis, meta, params: defParams || {}, game })
|
2023-06-11 19:20:56 +00:00
|
|
|
|
let msgList = []
|
2022-08-18 10:13:42 +00:00
|
|
|
|
|
|
|
|
|
let ret = []
|
|
|
|
|
let detailMap = []
|
|
|
|
|
let dmgRet = []
|
|
|
|
|
let dmgDetail = {}
|
|
|
|
|
|
2023-06-11 19:20:56 +00:00
|
|
|
|
// 用户手动输入伤害序号
|
|
|
|
|
if (idxIsInput) {
|
|
|
|
|
// 从1开始,所以需要 - 1
|
|
|
|
|
dmgIdx = --dmgIdx < 0 ? 0 : dmgIdx
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-08 22:04:08 +00:00
|
|
|
|
if (mode === 'single') {
|
|
|
|
|
dmgIdx = defDmgIdx > -1 ? defDmgIdx : 0
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-18 10:13:42 +00:00
|
|
|
|
lodash.forEach(details, (detail, detailSysIdx) => {
|
2022-11-08 22:04:08 +00:00
|
|
|
|
if (mode === 'single') {
|
|
|
|
|
if (defDmgKey) {
|
|
|
|
|
if (detail.dmgKey !== defDmgKey) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
} else if (detailSysIdx !== dmgIdx) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-18 10:13:42 +00:00
|
|
|
|
if (lodash.isFunction(detail)) {
|
2023-11-27 20:18:06 +00:00
|
|
|
|
let { attr } = DmgAttr.calcAttr({ originalAttr, artis, buffs, meta })
|
2022-08-22 20:53:31 +00:00
|
|
|
|
let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta))
|
2022-08-18 10:13:42 +00:00
|
|
|
|
detail = detail({ ...ds, attr, profile })
|
|
|
|
|
}
|
2024-04-13 10:20:19 +00:00
|
|
|
|
let params = lodash.merge({}, defParams, lodash.isFunction(detail?.params) ? detail?.params(meta) : detail?.params || {})
|
2023-11-27 20:18:06 +00:00
|
|
|
|
let { attr, msg } = DmgAttr.calcAttr({ originalAttr, buffs, artis, meta, params, talent: detail.talent || '', game })
|
2022-11-24 03:54:27 +00:00
|
|
|
|
if (detail.isStatic) {
|
|
|
|
|
return
|
|
|
|
|
}
|
2023-11-27 20:18:06 +00:00
|
|
|
|
|
|
|
|
|
let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta, params))
|
|
|
|
|
ds.artis = artis
|
|
|
|
|
if (detail.check && !detail.check(ds)) {
|
2022-08-18 10:13:42 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (detail.cons && meta.cons < detail.cons * 1) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-21 18:13:38 +00:00
|
|
|
|
let dmg = DmgCalc.getDmgFn({ ds, attr, level: profile.level, enemyLv, showDetail: detail.showDetail, game })
|
2022-08-18 10:13:42 +00:00
|
|
|
|
let basicDmgRet
|
|
|
|
|
|
|
|
|
|
if (detail.dmg) {
|
|
|
|
|
basicDmgRet = detail.dmg(ds, dmg)
|
|
|
|
|
detail.userIdx = detailMap.length
|
|
|
|
|
detailMap.push(detail)
|
|
|
|
|
ret.push({
|
|
|
|
|
title: detail.title,
|
|
|
|
|
...basicDmgRet
|
|
|
|
|
})
|
|
|
|
|
}
|
2023-06-11 19:20:56 +00:00
|
|
|
|
msgList.push(msg)
|
2022-08-18 10:13:42 +00:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (mode === 'dmg') {
|
|
|
|
|
let detail
|
2023-06-11 19:20:56 +00:00
|
|
|
|
if (idxIsInput && detailMap[dmgIdx]) {
|
|
|
|
|
detail = detailMap[dmgIdx]
|
|
|
|
|
} else if (idxIsInput) {
|
|
|
|
|
// 当用户输入的下标错误时,提示错误
|
|
|
|
|
throw new MiaoError(`序号输入错误:${this.char.name}最多只支持${detailMap.length}种伤害计算哦`)
|
2022-08-18 10:13:42 +00:00
|
|
|
|
} else if (!lodash.isUndefined(defDmgIdx) && details[defDmgIdx]) {
|
|
|
|
|
detail = details[defDmgIdx]
|
|
|
|
|
} else {
|
|
|
|
|
detail = detailMap[0]
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-22 17:48:44 +00:00
|
|
|
|
if (lodash.isFunction(detail)) {
|
2023-11-27 20:18:06 +00:00
|
|
|
|
let { attr } = DmgAttr.calcAttr({ originalAttr, buffs, artis, meta })
|
2023-02-22 17:48:44 +00:00
|
|
|
|
let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta))
|
|
|
|
|
detail = detail({ ...ds, attr, profile })
|
|
|
|
|
}
|
2022-08-18 10:13:42 +00:00
|
|
|
|
dmgDetail = {
|
|
|
|
|
title: detail.title,
|
2023-02-22 17:48:44 +00:00
|
|
|
|
userIdx: detail.userIdx || defDmgIdx,
|
|
|
|
|
basicRet: lodash.merge({}, ret[detail.userIdx] || ret[defDmgIdx]),
|
2022-08-18 10:13:42 +00:00
|
|
|
|
attr: []
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-21 18:54:45 +00:00
|
|
|
|
let { attrMap } = Meta.getMeta(game, 'arti')
|
2023-05-21 18:13:38 +00:00
|
|
|
|
|
2022-11-24 15:27:03 +00:00
|
|
|
|
// 计算角色属性增减
|
2022-08-18 10:13:42 +00:00
|
|
|
|
mainAttr = mainAttr.split(',')
|
|
|
|
|
let params = lodash.merge({}, defParams, detail.params || {})
|
|
|
|
|
let basicDmg = dmgDetail.basicRet
|
|
|
|
|
lodash.forEach(mainAttr, (reduceAttr) => {
|
|
|
|
|
dmgDetail.attr.push(attrMap[reduceAttr])
|
|
|
|
|
let rowData = []
|
|
|
|
|
lodash.forEach(mainAttr, (incAttr) => {
|
|
|
|
|
if (incAttr === reduceAttr) {
|
|
|
|
|
rowData.push({ type: 'na' })
|
|
|
|
|
return
|
|
|
|
|
}
|
2022-08-22 20:53:31 +00:00
|
|
|
|
let { attr } = DmgAttr.calcAttr({
|
2022-08-18 10:13:42 +00:00
|
|
|
|
originalAttr,
|
|
|
|
|
buffs,
|
2023-11-27 20:18:06 +00:00
|
|
|
|
artis,
|
2022-08-18 10:13:42 +00:00
|
|
|
|
meta,
|
|
|
|
|
params,
|
|
|
|
|
incAttr,
|
|
|
|
|
reduceAttr,
|
2023-05-21 18:13:38 +00:00
|
|
|
|
talent: detail.talent || '',
|
|
|
|
|
game
|
2022-08-18 10:13:42 +00:00
|
|
|
|
})
|
2022-08-22 20:53:31 +00:00
|
|
|
|
let ds = lodash.merge({ talent }, DmgAttr.getDs(attr, meta, params))
|
2023-05-21 18:13:38 +00:00
|
|
|
|
let dmg = DmgCalc.getDmgFn({ ds, attr, level: profile.level, enemyLv, game })
|
2022-08-18 10:13:42 +00:00
|
|
|
|
if (detail.dmg) {
|
|
|
|
|
let dmgCalcRet = detail.dmg(ds, dmg)
|
|
|
|
|
rowData.push({
|
|
|
|
|
type: dmgCalcRet.avg === basicDmg.avg ? 'avg' : (dmgCalcRet.avg > basicDmg.avg ? 'gt' : 'lt'),
|
|
|
|
|
...dmgCalcRet
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
dmgRet.push(rowData)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-08 22:04:08 +00:00
|
|
|
|
if (mode === 'single') {
|
|
|
|
|
return ret[0]
|
|
|
|
|
}
|
2022-08-18 10:13:42 +00:00
|
|
|
|
return {
|
|
|
|
|
ret,
|
2023-06-11 19:20:56 +00:00
|
|
|
|
// 根据当前计算的伤害,显示对应的buff列表
|
|
|
|
|
msg: msgList[idxIsInput ? dmgIdx : (defDmgIdx > -1 ? defDmgIdx : dmgIdx)] || msg,
|
|
|
|
|
msgList,
|
2022-08-18 10:13:42 +00:00
|
|
|
|
dmgRet,
|
|
|
|
|
enemyName,
|
2023-02-21 19:49:49 +00:00
|
|
|
|
dmgCfg: dmgDetail,
|
2023-10-29 07:51:31 +00:00
|
|
|
|
enemyLv,
|
|
|
|
|
createdBy
|
2022-08-18 10:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|