完全重构伤害计算;支持异常伤害计算;支持所有武器、套装计算;新增悠真计算等

This commit is contained in:
UCPr 2025-01-14 02:18:42 +08:00
parent f7e1066773
commit 3f8e64af66
99 changed files with 4243 additions and 1615 deletions

172
model/damage/avatar.ts Normal file
View file

@ -0,0 +1,172 @@
import type { skill } from './Calculator.js'
import type { ZZZAvatarInfo } from '../avatar.js'
import { aliasToID } from '../../lib/convert/char.js'
import config from '../../../../lib/config/config.js'
import { buff, BuffManager } from './BuffManager.js'
import { pluginPath } from '../../lib/path.js'
import { elementEnum } from './BuffManager.js'
import { Calculator } from './Calculator.js'
import chokidar from 'chokidar'
import path from 'path'
import fs from 'fs'
const damagePath = path.join(pluginPath, 'model', 'damage')
export const charData: {
[id: number]: {
skill: { [skillName: string]: number[] }
buff: { [buffName: string]: number[] }
}
} = {}
const calcFnc: {
character: {
[id: number]: {
calc?: (buffM: BuffManager, calc: Calculator, avatar: ZZZAvatarInfo) => void
buffs: buff[]
skills: skill[]
}
}
weapon: {
[name: string]: {
calc?: (buffM: BuffManager, star: number) => void
buffs: buff[]
}
}
set: {
[name: string]: {
calc?: (buffM: BuffManager, count: number) => void
buffs: buff[]
}
}
} = {
character: {},
weapon: {},
set: {}
}
async function init() {
const isWatch = config.bot.log_level === 'debug' // debug模式下监听文件变化
await Promise.all(fs.readdirSync(path.join(damagePath, 'character')).filter(v => v !== '模板').map(v => importChar(v, isWatch)))
for (const type of ['weapon', 'set']) {
await Promise.all(
fs.readdirSync(path.join(damagePath, type)).filter(v => v !== '模板.js' && !v.endsWith('_user.js') && v.endsWith('.js'))
.map(v => importFile(type as 'weapon' | 'set', v.replace('.js', ''), isWatch))
)
}
}
function watchFile(path: string, fnc: () => void) {
if (!fs.existsSync(path)) return
const watcher = chokidar.watch(path, {
awaitWriteFinish: {
stabilityThreshold: 50
}
})
watcher.on('change', (path) => {
logger.debug('重载' + path)
fnc()
})
}
async function importChar(charName: string, isWatch = false) {
const id = aliasToID(charName)
if (!id) return logger.warn(`未找到角色${charName}的ID`)
const dir = path.join(damagePath, 'character', charName)
const calcFile = fs.existsSync(path.join(dir, 'calc_user.js')) ? 'calc_user.js' : 'calc.js'
const dataPath = path.join(dir, (fs.existsSync(path.join(dir, 'data_user.json')) ? 'data_user.json' : 'data.json'))
try {
if (isWatch) {
watchFile(path.join(dir, calcFile), () => importChar(charName))
watchFile(dataPath, () => charData[id] = JSON.parse(fs.readFileSync(dataPath, 'utf8')))
}
charData[id] = JSON.parse(fs.readFileSync(dataPath, 'utf8'))
const m = await import(`./character/${charName}/${calcFile}?${Date.now()}`)
if (!m.calc && (!m.buffs || !m.skills)) throw new Error('伤害计算文件格式错误')
calcFnc.character[id] = m
} catch (e) {
logger.error(`导入角色${charName}伤害计算错误:`, e)
}
}
async function importFile(type: 'weapon' | 'set', name: string, isWatch = false) {
const defaultFilePath = path.join(damagePath, type, `${name}.js`)
const userFilePath = path.join(damagePath, type, `${name}_user.js`)
const isUser = fs.existsSync(userFilePath)
const filePath = isUser ? userFilePath : defaultFilePath
try {
if (isWatch) {
watchFile(filePath, () => importFile(type, name))
}
const m = await import(`./${type}/${name}${isUser ? '_user' : ''}.js?${Date.now()}`)
if (!m.calc && !m.buffs) throw new Error(type + ' Buff计算文件格式错误')
calcFnc[type][name] = m
} catch (e) {
logger.error(`导入${type}/${name}.js错误`, e)
}
}
await init()
/** 角色计算 */
export function avatar_ability(avatar: ZZZAvatarInfo) {
const m = calcFnc.character[avatar.id]
if (!m) return []
const buffM = new BuffManager(avatar)
const calc = new Calculator(buffM)
logger.debug('initial_properties', avatar.initial_properties)
weapon_buff(avatar.weapon, buffM)
set_buff(avatar.equip, buffM)
if (m.buffs) buffM.new(m.buffs)
if (m.skills) calc.new(m.skills)
if (m.calc) m.calc(buffM, calc, avatar)
logger.debug(`Buff*${buffM.buffs.length}`, buffM.buffs)
return calc.calc()
}
/** 武器加成 */
export function weapon_buff(equipment: ZZZAvatarInfo['weapon'], buffM: BuffManager) {
const name = equipment.name
logger.debug('武器:' + name)
const m = calcFnc.weapon[name]
if (!m) return
buffM.default({ name, source: 'Weapon' })
if (m.buffs) buffM.new(m.buffs)
if (m.calc) m.calc(buffM, equipment.star)
buffM.default({})
}
/** 套装加成 */
export function set_buff(equip: ZZZAvatarInfo['equip'], buffM: BuffManager) {
buffM.default({ name: '', source: 'Set' })
const setCount: { [name: string]: number } = {}
for (const equip_detail of equip) {
if (equip_detail.equipment_type == 5) {
// 属伤加成
const index = [31503, 31603, 31703, 31803, 31903].indexOf(equip_detail.main_properties[0].property_id)
if (index > -1 && elementEnum[index]) {
// @ts-ignore
buffM.new({
name: '驱动盘5号位',
type: '增伤',
value: Number(equip_detail.main_properties[0].base.replace('%', '')) / 100,
isForever: true,
element: elementEnum[index]
})
}
}
const suit_name = String(equip_detail.equip_suit.name)
setCount[suit_name] = (setCount[suit_name] || 0) + 1
}
buffM.setCount = setCount
for (const [name, count] of Object.entries(setCount)) {
if (count < 2) continue
logger.debug(`套装:${name}*${count}`)
const m = calcFnc.set[name]
if (!m) continue
buffM.default('name', name)
if (m.buffs) buffM.new(m.buffs)
if (m.calc) m.calc(buffM, count)
}
buffM.default({})
}