ZZZ-Plugin/model/damage/avatar.js

173 lines
6.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { aliasToID } from '../../lib/convert/char.js';
import { 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 = Object.create(null);
export const scoreFnc = Object.create(null);
const calcFnc = {
character: Object.create(null),
weapon: Object.create(null),
set: Object.create(null)
};
async function init() {
const isWatch = await (async () => {
try {
return (await import('../../../../lib/config/config.js')).default.bot.log_level === 'debug';
}
catch {
return false;
}
})();
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, v.replace('.js', ''), isWatch)));
}
}
function watchFile(path, fnc) {
if (!fs.existsSync(path))
return;
const watcher = chokidar.watch(path, {
awaitWriteFinish: {
stabilityThreshold: 251
}
});
watcher.on('change', (path) => {
logger.debug('重载' + path);
fnc();
});
}
async function importChar(charName, isWatch = false) {
const id = aliasToID(charName);
if (!id)
return logger.warn(`未找到角色${charName}的ID`);
const dir = path.join(damagePath, 'character', charName);
const getFileName = (name, ext) => fs.existsSync(path.join(dir, `${name}_user${ext}`)) ? `${name}_user${ext}` : `${name}${ext}`;
const dataPath = path.join(dir, getFileName('data', '.json'));
const calcFile = getFileName('calc', '.js');
const scoreFile = getFileName('score', '.js');
try {
const loadCharData = () => charData[id] = JSON.parse(fs.readFileSync(dataPath, 'utf8'));
const calcFilePath = path.join(dir, calcFile);
const loadCalcJS = async () => {
if (!fs.existsSync(calcFilePath))
return;
const m = await import(`./character/${charName}/${calcFile}?${Date.now()}`);
if (!m.calc && (!m.buffs || !m.skills))
throw new Error('伤害计算文件格式错误:' + charName);
calcFnc.character[id] = m;
};
const scoreFilePath = path.join(dir, scoreFile);
const loadScoreJS = async () => {
if (!fs.existsSync(scoreFilePath))
return;
const m = await import(`./character/${charName}/${scoreFile}?${Date.now()}`);
const fnc = m.default;
if (!fnc || typeof fnc !== 'function')
throw new Error('评分权重文件格式错误:' + charName);
scoreFnc[id] = fnc;
};
if (isWatch) {
watchFile(dataPath, loadCharData);
watchFile(calcFilePath, loadCalcJS);
watchFile(scoreFilePath, loadScoreJS);
}
loadCharData();
await loadCalcJS();
await loadScoreJS();
}
catch (e) {
logger.error(`导入角色${charName}计算文件错误:`, e);
}
}
async function importFile(type, name, 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);
}
}
init();
export function avatar_calc(avatar) {
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;
}
export function weapon_buff(weapon, buffM) {
const name = weapon?.name;
if (!name)
return;
logger.debug('武器:' + name);
const m = calcFnc.weapon[name];
if (!m)
return;
buffM.default({ name, source: '音擎' });
if (m.buffs)
buffM.new(m.buffs);
if (m.calc)
m.calc(buffM, weapon.star);
buffM.default({});
}
export function set_buff(equips, buffM) {
buffM.default({ name: '', source: '套装' });
const setCount = {};
for (const equip of equips) {
if (equip.equipment_type == 5) {
const index = [31503, 31603, 31703, 31803, 31903].indexOf(equip.main_properties[0].property_id);
if (index > -1 && elementEnum[index]) {
buffM.new({
name: '驱动盘5号位',
type: '增伤',
value: Number(equip.main_properties[0].base.replace('%', '')) / 100,
element: elementEnum[index]
});
}
}
const suit_name = equip.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({});
}