优化%XX伤害

This commit is contained in:
UCPr 2025-05-04 15:41:31 +08:00
parent 9b7e609f6a
commit 800bc15007
10 changed files with 325 additions and 129 deletions

View file

@ -42,13 +42,14 @@ export class Damage extends ZZZPlugin {
skillIndex = damages.length - 1 skillIndex = damages.length - 1
else if (skillIndex < 0) else if (skillIndex < 0)
skillIndex = 0 skillIndex = 0
const differences = calc.calc_differences(damages[skillIndex]?.skill) const sub_differences = calc.calc_sub_differences(damages[skillIndex]?.skill)
if (skillIndex === '') { if (skillIndex === '') {
const _s_ = differences[0]?.[0].damage.skill const _s_ = sub_differences[0]?.[0].damage.skill
skillIndex = ((_s_ && damages.findIndex(({ skill }) => skill.name === _s_.name && skill.type === _s_.type) + 1) || damages.length) - 1 skillIndex = ((_s_ && damages.findIndex(({ skill }) => skill.name === _s_.name && skill.type === _s_.type) + 1) || damages.length) - 1
} }
const damage = damages[skillIndex] const damage = damages[skillIndex]
const skill = damage.skill const skill = damage.skill
const main_differences = calc.calc_main_differences(skill)
await parsedData.get_detail_assets() await parsedData.get_detail_assets()
const finalData = { const finalData = {
uid, uid,
@ -56,7 +57,8 @@ export class Damage extends ZZZPlugin {
command: `%${parsedData.name_mi18n}伤害${skillIndex + 1}`, command: `%${parsedData.name_mi18n}伤害${skillIndex + 1}`,
damage, damage,
damages, damages,
differences, sub_differences,
main_differences,
skill: { skill: {
...skill, ...skill,
index: skillIndex index: skillIndex

View file

@ -101,10 +101,23 @@ export const nameToShortName3 = propName => {
/** /**
* 属性名转id * 属性名转id
* @param {string} propName 属性名 * @param {string} propName 属性名
* @returns {string}
*/ */
export const nameToId = (propName) => { export const nameToId = (propName) => {
for (const id in propertyData) { for (const id in propertyData) {
if (propertyData[id]?.[1] === propName) return Number(id); if (propertyData[id]?.[1] === propName) return Number(id);
}; };
return null; return '';
}; };
/**
* 中文属性名转英文属性名
* @param {string} propNameZH 属性名
* @returns {string}
*/
export const nameZHToNameEN = (propNameZH) => {
for (const id in propertyData) {
if (propertyData[id]?.[1] === propNameZH) return propertyData[id][0];
};
return '';
}

View file

@ -4,7 +4,7 @@ import { getMapData } from '../../utils/file.js';
import { charData } from './avatar.js'; import { charData } from './avatar.js';
import _ from 'lodash'; import _ from 'lodash';
const elementType2element = (elementType) => elementEnum[[0, 1, 2, 3, -1, 4][elementType - 200]]; const elementType2element = (elementType) => elementEnum[[0, 1, 2, 3, -1, 4][elementType - 200]];
const baseValueData = { const subBaseValueData = {
"生命值百分比": [0.03, '3.0%'], "生命值百分比": [0.03, '3.0%'],
"生命值": [112, '112'], "生命值": [112, '112'],
"攻击力百分比": [0.03, '3.0%'], "攻击力百分比": [0.03, '3.0%'],
@ -16,6 +16,23 @@ const baseValueData = {
"穿透值": [9, '9'], "穿透值": [9, '9'],
"异常精通": [9, '9'] "异常精通": [9, '9']
}; };
const mainBaseValueData = {
"生命值百分比": [0.3, '30%'],
"攻击力百分比": [0.3, '30%'],
"防御力百分比": [0.48, '48%'],
"暴击率": [0.24, '24%'],
"暴击伤害": [0.48, '48%'],
"异常精通": [92, '92'],
"穿透率": [0.24, '24%'],
"物理属性伤害加成": [0.3, '30%'],
"火属性伤害加成": [0.3, '30%'],
"冰属性伤害加成": [0.3, '30%'],
"电属性伤害加成": [0.3, '30%'],
"以太属性伤害加成": [0.3, '30%'],
"异常掌控": [0.3, '30%'],
"冲击力": [0.18, '18%'],
"能量自动回复": [0.6, '60%']
};
const AnomalyData = getMapData('AnomalyData'); const AnomalyData = getMapData('AnomalyData');
export class Calculator { export class Calculator {
buffM; buffM;
@ -195,78 +212,129 @@ export class Calculator {
} }
}).filter(v => v && v.result?.expectDMG && !v.skill?.isHide); }).filter(v => v && v.result?.expectDMG && !v.skill?.isHide);
} }
calc_differences(skill, types) { calc_sub_differences(skill, types) {
if (!skill) {
skill = this.skills.find((skill) => skill.isMain)
|| this.calc().sort((a, b) => b.result.expectDMG - a.result.expectDMG)[0]?.skill;
}
if (!types || !types.length) { if (!types || !types.length) {
types = Object.entries(this.avatar.scoreWeight) types = Object.entries(this.avatar.scoreWeight)
.reduce((acc, [id, weight]) => { .reduce((acc, [id, weight]) => {
if (weight > 0) { if (weight > 0) {
const type = prop.idToName(id); const type = prop.idToName(id);
if (type && baseValueData[type]) { if (type && subBaseValueData[type]) {
acc.push({ type, weight }); acc.push({ type, weight });
} }
} }
return acc; return acc;
}, []) }, [])
.slice(0, 7)
.sort((a, b) => b.weight - a.weight) .sort((a, b) => b.weight - a.weight)
.slice(0, 6)
.map(({ type }) => type); .map(({ type }) => type);
} }
const base = {}; const base = {};
types.forEach(type => base[type] = type.includes('百分比') ? this.avatar.base_properties[type.includes('攻击力') ? 'ATK' : type.includes('生命值') ? 'HP' : 'DEF'] * baseValueData[type][0] : baseValueData[type][0]); types.forEach(t => base[t] = t.includes('百分比') ? this.avatar.base_properties[prop.nameZHToNameEN(t.replace('百分比', ''))] * subBaseValueData[t][0] : subBaseValueData[t][0]);
logger.debug(logger.red('词条变化值:'), base); logger.debug(logger.red('词条变化值:'), base);
const buffs = types.map(t => ({ const buffs = types.map(t => ({
name: t, name: t,
shortName: prop.nameToShortName3(t), shortName: prop.nameToShortName3(t),
type: t.replace('百分比', ''), type: t.replace('百分比', ''),
value: base[t], value: base[t],
valueBase: baseValueData[t][1] valueBase: subBaseValueData[t][1]
})); }));
return this._calc_differences(skill, buffs); buffs.push({
name: '空白对照',
shortName: '对照组',
type: '',
value: 0,
valueBase: '0'
});
return this.calc_differences(buffs, skill);
} }
_calc_differences(skill, buffs) { calc_main_differences(skill, types) {
if (typeof skill === 'string') { if (!types || !types.length) {
types = Object.entries(this.avatar.scoreWeight)
.reduce((acc, [id, weight]) => {
if (weight > 0) {
const type = prop.idToName(id);
if (type && mainBaseValueData[type]) {
acc.push({ type, weight });
}
}
return acc;
}, [])
.sort((a, b) => b.weight - a.weight)
.slice(0, 6)
.map(({ type }) => type);
}
const base = {};
types.forEach(t => base[t] = (t.includes('百分比') || ['异常掌控', '冲击力', '能量自动回复'].includes(t)) ? this.avatar.base_properties[prop.nameZHToNameEN(t.replace('百分比', ''))] * mainBaseValueData[t][0] : mainBaseValueData[t][0]);
logger.debug(logger.red('词条变化值:'), base);
const buffs = types.map(t => ({
name: t,
shortName: prop.nameToShortName3(t),
type: (t.includes('属性伤害加成') ? '增伤' : t.replace('百分比', '')),
value: base[t],
element: t.includes('属性伤害加成') ? prop.nameZHToNameEN(t).replace('DMGBonus', '') : undefined,
valueBase: mainBaseValueData[t][1]
}));
buffs.push({
name: '空白对照',
shortName: '对照组',
type: '',
value: 0,
valueBase: '0'
});
const equips = this.avatar.equip.reduce((acc, e) => {
if (e.equipment_type < 4)
return acc;
const name = e.main_properties[0]?.property_name;
if (name)
acc.push(name);
return acc;
}, ['空白对照']);
return this.calc_differences(buffs, skill).filter(v => equips.includes(v[0].del.name.replace('百分比', '')));
}
calc_differences(buffs, skill) {
if (!skill) {
skill = this.skills.find((skill) => skill.isMain)
|| this.calc().sort((a, b) => b.result.expectDMG - a.result.expectDMG)[0]?.skill;
}
else if (typeof skill === 'string') {
const MySkill = this.skills.find(s => s.type === skill); const MySkill = this.skills.find(s => s.type === skill);
if (!MySkill) if (!MySkill)
return []; return [];
return this._calc_differences(MySkill, buffs); return this.calc_differences(buffs, MySkill);
} }
const oriDamage = this.calc_skill(skill); const oriDamage = this.calc_skill(skill);
this.cache = Object.create(null);
const result = []; const result = [];
for (const i_del in buffs) { for (const i_del in buffs) {
result[i_del] = []; result[i_del] = [];
const data_del = buffs[i_del]; const buff_del = buffs[i_del];
const { type: type_del, name: name_del = type_del, value: value_del } = data_del; const { name: name_del = buff_del.type, value: value_del } = buff_del;
logger.debug(logger.blue(`差异计算:${name_del}`)); logger.debug(logger.blue(`差异计算:${name_del}`));
this.buffM.buffs.push({ this.buffM.buffs.push({
...buff_del,
name: logger.green(`差异计算:${name_del}`), name: logger.green(`差异计算:${name_del}`),
type: type_del,
value: ({ calc }) => -calc.calc_value(value_del) value: ({ calc }) => -calc.calc_value(value_del)
}); });
for (const i_add in buffs) { for (const i_add in buffs) {
const data_add = buffs[i_add]; const buff_add = buffs[i_add];
data_add.name ??= data_add.type; buff_add.name ??= buff_add.type;
const { type: type_add, name: name_add = type_add, value: value_add } = data_add;
const data = result[i_del][i_add] = { const data = result[i_del][i_add] = {
add: data_add, add: buff_add,
del: data_del, del: buff_del,
damage: oriDamage, damage: oriDamage,
difference: 0 difference: 0
}; };
const { name: name_add = buff_add.type } = buff_add;
if (name_del === name_add) if (name_del === name_add)
continue; continue;
logger.debug(logger.yellow(`差异计算:${name_del}->${name_add}`)); logger.debug(logger.yellow(`差异计算:${name_del}->${name_add}`));
this.cache = Object.create(null);
this.buffM.buffs.push({ this.buffM.buffs.push({
name: logger.green(`差异计算:${name_del}->${name_add}`), ...buff_add,
type: type_add, name: logger.green(`差异计算:${name_del}->${name_add}`)
value: value_add
}); });
const newDamage = this.calc_skill(skill); const newDamage = this.calc_skill(skill);
this.buffM.buffs.pop(); this.buffM.buffs.pop();
this.cache = Object.create(null);
data.damage = newDamage; data.damage = newDamage;
data.difference = newDamage.result.expectDMG - oriDamage.result.expectDMG; data.difference = newDamage.result.expectDMG - oriDamage.result.expectDMG;
logger.debug(logger.magenta(`差异计算:${name_del}->${name_add} 伤害变化:${data.difference}`)); logger.debug(logger.magenta(`差异计算:${name_del}->${name_add} 伤害变化:${data.difference}`));
@ -431,13 +499,13 @@ export class Calculator {
} }
get_Pen(skill, usefulBuffs) { get_Pen(skill, usefulBuffs) {
let Pen = this.get('穿透值', this.initial_properties.Pen, skill, usefulBuffs); let Pen = this.get('穿透值', this.initial_properties.Pen, skill, usefulBuffs);
Pen = Math.max(0, Math.min(Pen, 1000)); Pen = Math.min(Pen, 1000);
Pen && logger.debug(`穿透值:${Pen}`); Pen && logger.debug(`穿透值:${Pen}`);
return Pen; return Pen;
} }
get_PenRatio(skill, usefulBuffs) { get_PenRatio(skill, usefulBuffs) {
let PenRatio = this.get('穿透率', this.initial_properties.PenRatio, skill, usefulBuffs); let PenRatio = this.get('穿透率', this.initial_properties.PenRatio, skill, usefulBuffs);
PenRatio = Math.max(0, Math.min(PenRatio, 2)); PenRatio = Math.min(PenRatio, 2);
PenRatio && logger.debug(`穿透率:${PenRatio}`); PenRatio && logger.debug(`穿透率:${PenRatio}`);
return PenRatio; return PenRatio;
} }

View file

@ -112,7 +112,7 @@ export interface damage {
const elementType2element = (elementType: number) => elementEnum[[0, 1, 2, 3, -1, 4][elementType - 200]] as element const elementType2element = (elementType: number) => elementEnum[[0, 1, 2, 3, -1, 4][elementType - 200]] as element
const baseValueData = { const subBaseValueData = {
"生命值百分比": [0.03, '3.0%'], "生命值百分比": [0.03, '3.0%'],
"生命值": [112, '112'], "生命值": [112, '112'],
"攻击力百分比": [0.03, '3.0%'], "攻击力百分比": [0.03, '3.0%'],
@ -125,7 +125,27 @@ const baseValueData = {
"异常精通": [9, '9'] "异常精通": [9, '9']
} as const } as const
type statKeys = keyof typeof baseValueData type subStatKeys = keyof typeof subBaseValueData
const mainBaseValueData = {
"生命值百分比": [0.3, '30%'],
"攻击力百分比": [0.3, '30%'],
"防御力百分比": [0.48, '48%'],
"暴击率": [0.24, '24%'],
"暴击伤害": [0.48, '48%'],
"异常精通": [92, '92'],
"穿透率": [0.24, '24%'],
"物理属性伤害加成": [0.3, '30%'],
"火属性伤害加成": [0.3, '30%'],
"冰属性伤害加成": [0.3, '30%'],
"电属性伤害加成": [0.3, '30%'],
"以太属性伤害加成": [0.3, '30%'],
"异常掌控": [0.3, '30%'],
"冲击力": [0.18, '18%'],
"能量自动回复": [0.6, '60%']
} as const
type mainStatKeys = keyof typeof mainBaseValueData
const AnomalyData = getMapData('AnomalyData') as { const AnomalyData = getMapData('AnomalyData') as {
name: string, name: string,
@ -343,103 +363,161 @@ export class Calculator {
} }
/** /**
* *
* @param types * @param types
*/ */
calc_differences(skill?: skill, types?: statKeys[]) { calc_sub_differences(skill?: skill['type'] | skill, types?: subStatKeys[]) {
if (!skill) {
skill = this.skills.find((skill) => skill.isMain) // 主技能
|| this.calc().sort((a, b) => b.result.expectDMG - a.result.expectDMG)[0]?.skill // 伤害最高技能
}
// 未指定types时筛选评分权重大于0的词条进行差异计算 // 未指定types时筛选评分权重大于0的词条进行差异计算
if (!types || !types.length) { if (!types || !types.length) {
types = Object.entries(this.avatar.scoreWeight) types = Object.entries(this.avatar.scoreWeight)
.reduce((acc: { type: statKeys, weight: number }[], [id, weight]) => { .reduce((acc: { type: subStatKeys, weight: number }[], [id, weight]) => {
if (weight > 0) { if (weight > 0) {
const type = prop.idToName(id) as statKeys const type = prop.idToName(id) as subStatKeys
if (type && baseValueData[type]) { if (type && subBaseValueData[type]) {
acc.push({ type, weight }) acc.push({ type, weight })
} }
} }
return acc return acc
}, []) }, [])
.slice(0, 7) // 默认最多7个
.sort((a, b) => b.weight - a.weight) // 按权重从大到小排序 .sort((a, b) => b.weight - a.weight) // 按权重从大到小排序
.slice(0, 6) // 默认最多6个
.map(({ type }) => type) .map(({ type }) => type)
} }
const base: { [type: string]: number } = {} const base: { [type: string]: number } = {}
types.forEach(type => base[type] = type.includes('百分比') ? this.avatar.base_properties[ types.forEach(t => base[t] = t.includes('百分比') ? this.avatar.base_properties[prop.nameZHToNameEN(t.replace('百分比', '')) as keyof ZZZAvatarInfo['base_properties']] * subBaseValueData[t][0] : subBaseValueData[t][0])
type.includes('攻击力') ? 'ATK' : type.includes('生命值') ? 'HP' : 'DEF'
] * baseValueData[type][0] : baseValueData[type][0])
logger.debug(logger.red('词条变化值:'), base) logger.debug(logger.red('词条变化值:'), base)
const buffs = types.map(t => ({ const buffs = types.map(t => ({
name: t, name: t,
shortName: prop.nameToShortName3(t), shortName: prop.nameToShortName3(t),
type: t.replace('百分比', '') as buff['type'], type: t.replace('百分比', '') as buff['type'],
value: base[t], value: base[t],
valueBase: baseValueData[t][1] valueBase: subBaseValueData[t][1]
})) }))
return this._calc_differences(skill, buffs) buffs.push({
// @ts-expect-error
name: '空白对照',
shortName: '对照组',
// @ts-expect-error
type: '',
value: 0,
// @ts-expect-error
valueBase: '0'
})
// @ts-expect-error
return this.calc_differences(buffs, skill)
}
/**
*
* @param types
*/
calc_main_differences(skill?: skill['type'] | skill, types?: mainStatKeys[]) {
// 未指定types时筛选评分权重大于0的词条进行差异计算
if (!types || !types.length) {
types = Object.entries(this.avatar.scoreWeight)
.reduce((acc: { type: mainStatKeys, weight: number }[], [id, weight]) => {
if (weight > 0) {
const type = prop.idToName(id) as mainStatKeys
if (type && mainBaseValueData[type]) {
acc.push({ type, weight })
}
}
return acc
}, [])
.sort((a, b) => b.weight - a.weight) // 按权重从大到小排序
.slice(0, 6)
.map(({ type }) => type)
}
const base: { [type: string]: number } = {}
types.forEach(t => base[t] = (t.includes('百分比') || ['异常掌控', '冲击力', '能量自动回复'].includes(t)) ? this.avatar.base_properties[prop.nameZHToNameEN(t.replace('百分比', '')) as keyof ZZZAvatarInfo['base_properties']] * mainBaseValueData[t][0] : mainBaseValueData[t][0])
logger.debug(logger.red('词条变化值:'), base)
const buffs = types.map(t => ({
name: t,
shortName: prop.nameToShortName3(t),
type: (t.includes('属性伤害加成') ? '增伤' : t.replace('百分比', '')) as buff['type'],
value: base[t],
element: t.includes('属性伤害加成') ? prop.nameZHToNameEN(t).replace('DMGBonus', '') : undefined,
valueBase: mainBaseValueData[t][1]
}))
buffs.push({
// @ts-expect-error
name: '空白对照',
shortName: '对照组',
// @ts-expect-error
type: '',
value: 0,
// @ts-expect-error
valueBase: '0'
})
const equips = this.avatar.equip.reduce((acc: string[], e) => {
if (e.equipment_type < 4) return acc
const name = e.main_properties[0]?.property_name
if (name) acc.push(name)
return acc
}, ['空白对照'])
// @ts-expect-error 只保留装备的主词条del
return this.calc_differences(buffs, skill).filter(v => equips.includes(v[0].del.name!.replace('百分比', '')))
} }
/* 计算已注册技能差异 */ /* 计算已注册技能差异 */
_calc_differences<B extends { name: skill['type'], type: buff['type'], value: buff['value'] }>( calc_differences<B extends Partial<buff>>(
skill: string, buffs: B[],
buffs: B[] skill: skill['type']
): { add: B, del: B, damage: damage, difference: number }[][] ): { add: B, del: B, damage: damage, difference: number }[][]
/* 计算技能差异 */ /* 计算技能差异 */
_calc_differences<B extends { name: string, type: buff['type'], value: buff['value'] }>( calc_differences<B extends Partial<buff>>(
skill: skill, buffs: B[],
buffs: B[] skill?: skill
): { add: B, del: B, damage: damage, difference: number }[][] ): { add: B, del: B, damage: damage, difference: number }[][]
/** /**
* buff形式两两组合进行差异计算 * buff形式两两组合进行差异计算
* @param buffs buffs * @param buffs buffs
* @returns `buffs.length维` * @returns `buffs.length维`
*/ */
_calc_differences<B extends { name: string, type: buff['type'], value: buff['value'] }>( calc_differences<B extends buff>(
skill: skill['type'] | skill, buffs: B[],
buffs: B[] skill?: skill['type'] | skill
): { add: B, del: B, damage: damage, difference: number }[][] { ): { add: B, del: B, damage: damage, difference: number }[][] {
if (typeof skill === 'string') { if (!skill) {
skill = this.skills.find((skill) => skill.isMain) // 主技能
|| this.calc().sort((a, b) => b.result.expectDMG - a.result.expectDMG)[0]?.skill // 伤害最高技能
} else if (typeof skill === 'string') {
const MySkill = this.skills.find(s => s.type === skill) const MySkill = this.skills.find(s => s.type === skill)
if (!MySkill) return [] if (!MySkill) return []
return this._calc_differences(MySkill, buffs) return this.calc_differences(buffs, MySkill)
} }
const oriDamage = this.calc_skill(skill) const oriDamage = this.calc_skill(skill)
this.cache = Object.create(null)
const result: { del: B, add: B, damage: damage, difference: number }[][] = [] const result: { del: B, add: B, damage: damage, difference: number }[][] = []
for (const i_del in buffs) { for (const i_del in buffs) {
result[i_del] = [] result[i_del] = []
const data_del = buffs[i_del] const buff_del = buffs[i_del]
const { type: type_del, name: name_del = type_del, value: value_del } = data_del const { name: name_del = buff_del.type, value: value_del } = buff_del
logger.debug(logger.blue(`差异计算:${name_del}`)) logger.debug(logger.blue(`差异计算:${name_del}`))
// @ts-ignore
this.buffM.buffs.push({ this.buffM.buffs.push({
...buff_del,
name: logger.green(`差异计算:${name_del}`), name: logger.green(`差异计算:${name_del}`),
type: type_del,
value: ({ calc }) => -calc.calc_value(value_del) // 转为负值 value: ({ calc }) => -calc.calc_value(value_del) // 转为负值
}) })
for (const i_add in buffs) { for (const i_add in buffs) {
const data_add = buffs[i_add] const buff_add = buffs[i_add]
data_add.name ??= data_add.type buff_add.name ??= buff_add.type
const { type: type_add, name: name_add = type_add, value: value_add } = data_add
const data = result[i_del][i_add] = { const data = result[i_del][i_add] = {
add: data_add, add: buff_add,
del: data_del, del: buff_del,
damage: oriDamage, damage: oriDamage,
difference: 0 difference: 0
} }
const { name: name_add = buff_add.type } = buff_add
if (name_del === name_add) continue if (name_del === name_add) continue
logger.debug(logger.yellow(`差异计算:${name_del}->${name_add}`)) logger.debug(logger.yellow(`差异计算:${name_del}->${name_add}`))
this.cache = Object.create(null)
// @ts-ignore
this.buffM.buffs.push({ this.buffM.buffs.push({
name: logger.green(`差异计算:${name_del}->${name_add}`), ...buff_add,
type: type_add, name: logger.green(`差异计算:${name_del}->${name_add}`)
value: value_add
}) })
const newDamage = this.calc_skill(skill) const newDamage = this.calc_skill(skill)
this.buffM.buffs.pop() this.buffM.buffs.pop()
this.cache = Object.create(null)
data.damage = newDamage data.damage = newDamage
data.difference = newDamage.result.expectDMG - oriDamage.result.expectDMG data.difference = newDamage.result.expectDMG - oriDamage.result.expectDMG
logger.debug(logger.magenta(`差异计算:${name_del}->${name_add} 伤害变化:${data.difference}`)) logger.debug(logger.magenta(`差异计算:${name_del}->${name_add} 伤害变化:${data.difference}`))
@ -641,7 +719,7 @@ export class Calculator {
/** 穿透值 */ /** 穿透值 */
get_Pen(skill: skill, usefulBuffs: buff[]) { get_Pen(skill: skill, usefulBuffs: buff[]) {
let Pen = this.get('穿透值', this.initial_properties.Pen, skill, usefulBuffs) let Pen = this.get('穿透值', this.initial_properties.Pen, skill, usefulBuffs)
Pen = Math.max(0, Math.min(Pen, 1000)) Pen = Math.min(Pen, 1000)
Pen && logger.debug(`穿透值:${Pen}`) Pen && logger.debug(`穿透值:${Pen}`)
return Pen return Pen
} }
@ -649,7 +727,7 @@ export class Calculator {
/** 穿透率 */ /** 穿透率 */
get_PenRatio(skill: skill, usefulBuffs: buff[]) { get_PenRatio(skill: skill, usefulBuffs: buff[]) {
let PenRatio = this.get('穿透率', this.initial_properties.PenRatio, skill, usefulBuffs) let PenRatio = this.get('穿透率', this.initial_properties.PenRatio, skill, usefulBuffs)
PenRatio = Math.max(0, Math.min(PenRatio, 2)) PenRatio = Math.min(PenRatio, 2)
PenRatio && logger.debug(`穿透率:${PenRatio}`) PenRatio && logger.debug(`穿透率:${PenRatio}`)
return PenRatio return PenRatio
} }

View file

@ -12,6 +12,6 @@ export default function (avatar) {
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"冰属性伤害提高": 1 "冰属性伤害加成": 1
}] }]
} }

View file

@ -13,7 +13,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"电属性伤害提高": 1 "电属性伤害加成": 1
}, },
"猫又": { "猫又": {
"生命值百分比": 0, "生命值百分比": 0,
@ -27,7 +27,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"物理属性伤害提高": 1 "物理属性伤害加成": 1
}, },
"妮可": { "妮可": {
"生命值百分比": 0, "生命值百分比": 0,
@ -41,7 +41,7 @@
"能量回复": 1, "能量回复": 1,
"异常精通": 1, "异常精通": 1,
"异常掌控": 1, "异常掌控": 1,
"以太属性伤害提高": 1 "以太属性伤害加成": 1
}, },
"「11号」": { "「11号」": {
"生命值百分比": 0, "生命值百分比": 0,
@ -55,7 +55,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"火属性伤害提高": 1 "火属性伤害加成": 1
}, },
"可琳": { "可琳": {
"生命值百分比": 0, "生命值百分比": 0,
@ -69,7 +69,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"物理属性伤害提高": 1 "物理属性伤害加成": 1
}, },
"凯撒": { "凯撒": {
"生命值百分比": 0, "生命值百分比": 0,
@ -83,7 +83,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"物理属性伤害提高": 1 "物理属性伤害加成": 1
}, },
"比利": { "比利": {
"生命值百分比": 0, "生命值百分比": 0,
@ -97,7 +97,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"物理属性伤害提高": 1 "物理属性伤害加成": 1
}, },
"雅": { "雅": {
"生命值百分比": 0, "生命值百分比": 0,
@ -111,7 +111,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0.5, "异常精通": 0.5,
"异常掌控": 0.5, "异常掌控": 0.5,
"冰属性伤害提高": 1 "冰属性伤害加成": 1
}, },
"珂蕾妲": { "珂蕾妲": {
"生命值百分比": 0, "生命值百分比": 0,
@ -125,7 +125,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"火属性伤害提高": 1 "火属性伤害加成": 1
}, },
"安东": { "安东": {
"生命值百分比": 0, "生命值百分比": 0,
@ -139,7 +139,7 @@
"能量回复": 1, "能量回复": 1,
"异常精通": 1, "异常精通": 1,
"异常掌控": 1, "异常掌控": 1,
"电属性伤害提高": 1 "电属性伤害加成": 1
}, },
"本": { "本": {
"生命值百分比": 0, "生命值百分比": 0,
@ -153,7 +153,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"火属性伤害提高": 1 "火属性伤害加成": 1
}, },
"苍角": { "苍角": {
"生命值百分比": 0, "生命值百分比": 0,
@ -167,7 +167,7 @@
"能量回复": 1, "能量回复": 1,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"冰属性伤害提高": 1 "冰属性伤害加成": 1
}, },
"莱卡恩": { "莱卡恩": {
"生命值百分比": 0, "生命值百分比": 0,
@ -181,7 +181,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"冰属性伤害提高": 1 "冰属性伤害加成": 1
}, },
"露西": { "露西": {
"生命值百分比": 0, "生命值百分比": 0,
@ -195,7 +195,7 @@
"能量回复": 1, "能量回复": 1,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"火属性伤害提高": 1 "火属性伤害加成": 1
}, },
"莱特": { "莱特": {
"生命值百分比": 0, "生命值百分比": 0,
@ -209,7 +209,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"火属性伤害提高": 1 "火属性伤害加成": 1
}, },
"柏妮思": { "柏妮思": {
"生命值百分比": 0, "生命值百分比": 0,
@ -223,7 +223,7 @@
"能量回复": 1, "能量回复": 1,
"异常精通": 1, "异常精通": 1,
"异常掌控": 1, "异常掌控": 1,
"火属性伤害提高": 1 "火属性伤害加成": 1
}, },
"格莉丝": { "格莉丝": {
"生命值百分比": 0, "生命值百分比": 0,
@ -237,7 +237,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 1, "异常精通": 1,
"异常掌控": 1, "异常掌控": 1,
"电属性伤害提高": 1 "电属性伤害加成": 1
}, },
"艾莲": { "艾莲": {
"生命值百分比": 0, "生命值百分比": 0,
@ -251,7 +251,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"冰属性伤害提高": 1 "冰属性伤害加成": 1
}, },
"悠真": { "悠真": {
"生命值百分比": 0, "生命值百分比": 0,
@ -265,7 +265,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"电属性伤害提高": 1 "电属性伤害加成": 1
}, },
"丽娜": { "丽娜": {
"生命值百分比": 0, "生命值百分比": 0,
@ -279,7 +279,7 @@
"能量回复": 1, "能量回复": 1,
"异常精通": 1, "异常精通": 1,
"异常掌控": 0.75, "异常掌控": 0.75,
"电属性伤害提高": 0.75 "电属性伤害加成": 0.75
}, },
"柳": { "柳": {
"生命值百分比": 0, "生命值百分比": 0,
@ -293,7 +293,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 1, "异常精通": 1,
"异常掌控": 1, "异常掌控": 1,
"电属性伤害提高": 0.75 "电属性伤害加成": 0.75
}, },
"朱鸢": { "朱鸢": {
"生命值百分比": 0, "生命值百分比": 0,
@ -307,7 +307,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"以太属性伤害提高": 1 "以太属性伤害加成": 1
}, },
"青衣": { "青衣": {
"生命值百分比": 0, "生命值百分比": 0,
@ -321,7 +321,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"电属性伤害提高": 1 "电属性伤害加成": 1
}, },
"简": { "简": {
"生命值百分比": 0, "生命值百分比": 0,
@ -335,7 +335,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 1, "异常精通": 1,
"异常掌控": 1, "异常掌控": 1,
"物理属性伤害提高": 1 "物理属性伤害加成": 1
}, },
"赛斯": { "赛斯": {
"生命值百分比": 0, "生命值百分比": 0,
@ -349,7 +349,7 @@
"能量回复": 1, "能量回复": 1,
"异常精通": 0.75, "异常精通": 0.75,
"异常掌控": 1, "异常掌控": 1,
"电属性伤害提高": 1 "电属性伤害加成": 1
}, },
"派派": { "派派": {
"生命值百分比": 0, "生命值百分比": 0,
@ -363,7 +363,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 1, "异常精通": 1,
"异常掌控": 1, "异常掌控": 1,
"物理属性伤害提高": 1 "物理属性伤害加成": 1
}, },
"耀嘉音": { "耀嘉音": {
"生命值百分比": 0, "生命值百分比": 0,
@ -377,7 +377,7 @@
"能量回复": 1, "能量回复": 1,
"异常精通": 0.25, "异常精通": 0.25,
"异常掌控": 0, "异常掌控": 0,
"以太属性伤害提高": 0.5 "以太属性伤害加成": 0.5
}, },
"伊芙琳": { "伊芙琳": {
"生命值百分比": 0, "生命值百分比": 0,
@ -391,7 +391,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"火属性伤害提高": 1 "火属性伤害加成": 1
}, },
"波可娜": { "波可娜": {
"生命值百分比": 0, "生命值百分比": 0,
@ -405,7 +405,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"物理属性伤害提高": 1 "物理属性伤害加成": 1
}, },
"零号·安比": { "零号·安比": {
"生命值百分比": 0, "生命值百分比": 0,
@ -419,7 +419,7 @@
"能量回复": 0, "能量回复": 0,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"电属性伤害提高": 1 "电属性伤害加成": 1
}, },
"「扳机」": { "「扳机」": {
"生命值百分比": 0, "生命值百分比": 0,
@ -433,7 +433,7 @@
"能量回复": 0.5, "能量回复": 0.5,
"异常精通": 0, "异常精通": 0,
"异常掌控": 0, "异常掌控": 0,
"电属性伤害提高": 1 "电属性伤害加成": 1
}, },
"薇薇安": { "薇薇安": {
"生命值百分比": 0, "生命值百分比": 0,
@ -447,6 +447,6 @@
"能量回复": 1, "能量回复": 1,
"异常精通": 1, "异常精通": 1,
"异常掌控": 1, "异常掌控": 1,
"以太属性伤害提高": 1 "以太属性伤害加成": 1
} }
} }

View file

@ -13,9 +13,9 @@
"30502": ["EnergyRegen", "能量回复", "回能", "回能"], "30502": ["EnergyRegen", "能量回复", "回能", "回能"],
"31203": ["AnomalyProficiency", "异常精通", "精通", "精通"], "31203": ["AnomalyProficiency", "异常精通", "精通", "精通"],
"31402": ["AnomalyMastery", "异常掌控", "掌控", "掌控"], "31402": ["AnomalyMastery", "异常掌控", "掌控", "掌控"],
"31503": ["PhysicalDMGBonus", "物理属性伤害提高", "物伤", "物伤"], "31503": ["PhysicalDMGBonus", "物理属性伤害加成", "物伤", "物伤"],
"31603": ["FireDMGBonus", "火属性伤害提高", "火伤", "火伤"], "31603": ["FireDMGBonus", "火属性伤害加成", "火伤", "火伤"],
"31703": ["IceDMGBonus", "冰属性伤害提高", "冰伤", "冰伤"], "31703": ["IceDMGBonus", "冰属性伤害加成", "冰伤", "冰伤"],
"31803": ["ElectricDMGBonus", "电属性伤害提高", "电伤", "电伤"], "31803": ["ElectricDMGBonus", "电属性伤害加成", "电伤", "电伤"],
"31903": ["EtherDMGBonus", "以太属性伤害提高", "以伤", "以太伤"] "31903": ["EtherDMGBonus", "以太属性伤害加成", "以伤", "以太伤"]
} }

View file

@ -453,6 +453,10 @@
padding: 0.5em 0.5em; padding: 0.5em 0.5em;
font-size: 0.9em; font-size: 0.9em;
border-right: 0.1em solid rgba(255, 255, 255, 0.3); border-right: 0.1em solid rgba(255, 255, 255, 0.3);
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
} }
.damage .data-list .td:last-child { .damage .data-list .td:last-child {
border-right: none; border-right: none;
@ -525,10 +529,7 @@
grid-template-columns: repeat(10, 1fr); grid-template-columns: repeat(10, 1fr);
} }
.damage .difference-list .difference-td { .damage .difference-list .difference-td {
display: flex;
flex-direction: column; flex-direction: column;
justify-content: center;
align-items: center;
} }
.damage .difference-list .difference-td span { .damage .difference-list .difference-td span {
font-size: 0.8em; font-size: 0.8em;

View file

@ -202,6 +202,7 @@
<div>注:一个技能可能分为多个出伤部分分别计算累加,此时该数据仅为一部分的乘区,下同</div> <div>注:一个技能可能分为多个出伤部分分别计算累加,此时该数据仅为一部分的乘区,下同</div>
</div> </div>
</div> </div>
{{if damage.usefulBuffs.length}}
<div class="title"> <div class="title">
<% include(sys.specialTitle, {en: 'BUFF' , cn: 'Buff统计' }) %> <% include(sys.specialTitle, {en: 'BUFF' , cn: 'Buff统计' }) %>
</div> </div>
@ -221,22 +222,23 @@
</div> </div>
{{/each}} {{/each}}
</div> </div>
{{if differences.length > 1}} {{/if}}
{{if sub_differences.length > 1}}
<div class="title"> <div class="title">
<% include(sys.specialTitle, {en: 'STAT' , cn: '词条差异计算' }) %> <% include(sys.specialTitle, {en: 'SUBSTAT' , cn: '词条差异计算' }) %>
</div> </div>
<div class="data-list difference-list"> <div class="data-list difference-list">
<div class="tr difference-tr d{{differences.length}}"> <div class="tr difference-tr d{{sub_differences[0].length}}">
<div class="td difference-td no-zzz-font">词条变化</div> <div class="td difference-td no-zzz-font">词条变化</div>
{{each differences[0] d}} {{each sub_differences[0] d}}
<div class="td difference-td no-zzz-font"> <div class="td difference-td no-zzz-font">
{{d.add.shortName}} {{d.add.shortName}}
<span>+{{d.add.valueBase}}</span> <span>+{{d.add.valueBase}}</span>
</div> </div>
{{/each}} {{/each}}
</div> </div>
{{each differences diff}} {{each sub_differences diff}}
<div class="tr difference-tr d{{differences.length}}"> <div class="tr difference-tr d{{sub_differences[0].length}}">
<div class="td difference-td no-zzz-font"> <div class="td difference-td no-zzz-font">
{{diff[0].del.shortName}} {{diff[0].del.shortName}}
<span>-{{diff[0].del.valueBase}}</span> <span>-{{diff[0].del.valueBase}}</span>
@ -247,8 +249,39 @@
</div> </div>
{{/each}} {{/each}}
<div class="tr difference-tr info-tr no-zzz-font"> <div class="tr difference-tr info-tr no-zzz-font">
<div>反映在上述buff作用下置换<span>单位词条</span>后的<span>{{skill.name}}</span>期望伤害变化</div> <div>反映在上述buff作用下置换<span>单位副词条</span>后的<span>{{skill.name}}</span>期望伤害变化</div>
<div><span>横轴</span>表示<span>增加</span>的单位词条,<span>纵轴</span>表示<span>减少</span>的单位词条,对应坐标即为<span>期望伤害变化</span></div> <div><span>横轴</span>表示<span>增加</span>的词条,<span>纵轴</span>表示<span>减少</span>的词条,对应坐标即为<span>期望伤害变化</span>,下同</div>
</div>
</div>
{{/if}}
{{if main_differences.length > 1}}
<div class="title">
<% include(sys.specialTitle, {en: 'MAINSTAT' , cn: '主词条差异计算' }) %>
</div>
<div class="data-list difference-list">
<div class="tr difference-tr d{{main_differences[0].length}}">
<div class="td difference-td no-zzz-font">词条变化</div>
{{each main_differences[0] d}}
<div class="td difference-td no-zzz-font">
{{d.add.shortName}}
<span>+{{d.add.valueBase}}</span>
</div>
{{/each}}
</div>
{{each main_differences diff}}
<div class="tr difference-tr d{{main_differences[0].length}}">
<div class="td difference-td no-zzz-font">
{{diff[0].del.shortName}}
<span>-{{diff[0].del.valueBase}}</span>
</div>
{{each diff d}}
<div class="td difference-td no-zzz-font {{d.difference > 0 ? 'positive' : d.difference < 0 ? 'negative' : 'zero'}}">{{d.difference > 0 ? '+' + d.difference.toFixed(0) : d.difference.toFixed(0)}}</div>
{{/each}}
</div>
{{/each}}
<div class="tr difference-tr info-tr no-zzz-font">
<div>反映在上述buff作用下置换<span>单位主词条</span>后的<span>{{skill.name}}</span>期望伤害变化</div>
<div>量化<span>不同主词条组合</span>对伤害的影响,但并非每个组合都可实现,仅供参考</div>
</div> </div>
</div> </div>
{{/if}} {{/if}}

View file

@ -423,6 +423,10 @@
padding: 0.5em 0.5em; padding: 0.5em 0.5em;
font-size: 0.9em; font-size: 0.9em;
border-right: 0.1em solid rgba(255, 255, 255, 0.3); border-right: 0.1em solid rgba(255, 255, 255, 0.3);
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
&:last-child { &:last-child {
border-right: none; border-right: none;
} }
@ -509,11 +513,8 @@
} }
.difference-td { .difference-td {
display: flex;
flex-direction: column; flex-direction: column;
justify-content: center;
align-items: center;
span { span {
font-size: 0.8em; font-size: 0.8em;
color: #bbb; color: #bbb;