mirror of
https://github.com/ZZZure/ZZZ-Plugin.git
synced 2025-12-15 12:47:48 +00:00
172 lines
5.4 KiB
TypeScript
172 lines
5.4 KiB
TypeScript
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({})
|
||
}
|