mirror of
https://github.com/ZZZure/ZZZ-Plugin.git
synced 2025-12-16 13:17:32 +00:00
feature:%XX伤害
This commit is contained in:
parent
83ca22c3b8
commit
9b7e609f6a
35 changed files with 1849 additions and 114 deletions
|
|
@ -1,13 +1,27 @@
|
|||
import { getMapData } from '../../utils/file.js';
|
||||
import { elementEnum, anomalyEnum } from './BuffManager.js';
|
||||
import * as prop from '../../lib/convert/property.js';
|
||||
import { getMapData } from '../../utils/file.js';
|
||||
import { charData } from './avatar.js';
|
||||
import _ from 'lodash';
|
||||
const elementType2element = (elementType) => elementEnum[[0, 1, 2, 3, -1, 4][elementType - 200]];
|
||||
const baseValueData = {
|
||||
"生命值百分比": [0.03, '3.0%'],
|
||||
"生命值": [112, '112'],
|
||||
"攻击力百分比": [0.03, '3.0%'],
|
||||
"攻击力": [19, '19'],
|
||||
"防御力百分比": [0.048, '4.8%'],
|
||||
"防御力": [15, '15'],
|
||||
"暴击率": [0.024, '2.4%'],
|
||||
"暴击伤害": [0.048, '4.8%'],
|
||||
"穿透值": [9, '9'],
|
||||
"异常精通": [9, '9']
|
||||
};
|
||||
const AnomalyData = getMapData('AnomalyData');
|
||||
export class Calculator {
|
||||
buffM;
|
||||
avatar;
|
||||
skills = [];
|
||||
usefulBuffs = [];
|
||||
cache = Object.create(null);
|
||||
props = {};
|
||||
skill;
|
||||
|
|
@ -68,6 +82,7 @@ export class Calculator {
|
|||
logger.debug(`${logger.green(skill.type)}${skill.name}伤害计算:`);
|
||||
if (skill.dmg) {
|
||||
const dmg = skill.dmg(this);
|
||||
dmg.skill ||= skill;
|
||||
logger.debug('自定义计算最终伤害:', dmg.result);
|
||||
return dmg;
|
||||
}
|
||||
|
|
@ -114,15 +129,18 @@ export class Calculator {
|
|||
areas.AnomalyProficiencyArea ??= this.get_AnomalyProficiencyArea(skill, usefulBuffs);
|
||||
areas.AnomalyBoostArea ??= this.get_AnomalyBoostArea(skill, usefulBuffs);
|
||||
areas.LevelArea ??= this.get_LevelArea();
|
||||
props.异常暴击率 = this.get_AnomalyCRITRate(skill, usefulBuffs);
|
||||
props.异常暴击伤害 = this.get_AnomalyCRITDMG(skill, usefulBuffs);
|
||||
areas.CriticalArea ??= 1 + props.异常暴击率 * (props.异常暴击伤害 - 1);
|
||||
if (skill.type !== '紊乱') {
|
||||
props.异常暴击率 ??= this.get_AnomalyCRITRate(skill, usefulBuffs);
|
||||
props.异常暴击伤害 ??= this.get_AnomalyCRITDMG(skill, usefulBuffs);
|
||||
areas.CriticalArea ??= 1 + props.异常暴击率 * (props.异常暴击伤害 - 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
props.暴击率 = this.get_CRITRate(skill, usefulBuffs);
|
||||
props.暴击伤害 = this.get_CRITDMG(skill, usefulBuffs);
|
||||
props.暴击率 ??= this.get_CRITRate(skill, usefulBuffs);
|
||||
props.暴击伤害 ??= this.get_CRITDMG(skill, usefulBuffs);
|
||||
areas.CriticalArea ??= 1 + props.暴击率 * (props.暴击伤害 - 1);
|
||||
}
|
||||
areas.CriticalArea ??= 1;
|
||||
logger.debug(`暴击期望:${areas.CriticalArea}`);
|
||||
areas.BoostArea ??= this.get_BoostArea(skill, usefulBuffs);
|
||||
areas.VulnerabilityArea ??= this.get_VulnerabilityArea(skill, usefulBuffs);
|
||||
|
|
@ -138,7 +156,8 @@ export class Calculator {
|
|||
critDMG: BasicArea * 暴击伤害 * BoostArea * VulnerabilityArea * ResistanceArea * DefenceArea,
|
||||
expectDMG: BasicArea * CriticalArea * BoostArea * VulnerabilityArea * ResistanceArea * DefenceArea
|
||||
};
|
||||
const damage = { skill, props, areas, result };
|
||||
const damage = { skill, usefulBuffs: _.sortBy(this.usefulBuffs, ['type', 'value']).reverse(), props, areas, result };
|
||||
this.usefulBuffs = [];
|
||||
if (skill.after) {
|
||||
damage.add = (d) => {
|
||||
if (typeof d === 'string')
|
||||
|
|
@ -158,6 +177,7 @@ export class Calculator {
|
|||
damage.fnc(v => v * n);
|
||||
};
|
||||
skill.after({ avatar: this.avatar, calc: this, usefulBuffs, skill, damage });
|
||||
delete damage.add, delete damage.fnc, delete damage.x;
|
||||
}
|
||||
logger.debug('最终伤害:', result);
|
||||
if (!skill.banCache)
|
||||
|
|
@ -175,6 +195,86 @@ export class Calculator {
|
|||
}
|
||||
}).filter(v => v && v.result?.expectDMG && !v.skill?.isHide);
|
||||
}
|
||||
calc_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) {
|
||||
types = Object.entries(this.avatar.scoreWeight)
|
||||
.reduce((acc, [id, weight]) => {
|
||||
if (weight > 0) {
|
||||
const type = prop.idToName(id);
|
||||
if (type && baseValueData[type]) {
|
||||
acc.push({ type, weight });
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, [])
|
||||
.slice(0, 7)
|
||||
.sort((a, b) => b.weight - a.weight)
|
||||
.map(({ type }) => type);
|
||||
}
|
||||
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]);
|
||||
logger.debug(logger.red('词条变化值:'), base);
|
||||
const buffs = types.map(t => ({
|
||||
name: t,
|
||||
shortName: prop.nameToShortName3(t),
|
||||
type: t.replace('百分比', ''),
|
||||
value: base[t],
|
||||
valueBase: baseValueData[t][1]
|
||||
}));
|
||||
return this._calc_differences(skill, buffs);
|
||||
}
|
||||
_calc_differences(skill, buffs) {
|
||||
if (typeof skill === 'string') {
|
||||
const MySkill = this.skills.find(s => s.type === skill);
|
||||
if (!MySkill)
|
||||
return [];
|
||||
return this._calc_differences(MySkill, buffs);
|
||||
}
|
||||
const oriDamage = this.calc_skill(skill);
|
||||
const result = [];
|
||||
for (const i_del in buffs) {
|
||||
result[i_del] = [];
|
||||
const data_del = buffs[i_del];
|
||||
const { type: type_del, name: name_del = type_del, value: value_del } = data_del;
|
||||
logger.debug(logger.blue(`差异计算:${name_del}`));
|
||||
this.buffM.buffs.push({
|
||||
name: logger.green(`差异计算:${name_del}`),
|
||||
type: type_del,
|
||||
value: ({ calc }) => -calc.calc_value(value_del)
|
||||
});
|
||||
for (const i_add in buffs) {
|
||||
const data_add = buffs[i_add];
|
||||
data_add.name ??= data_add.type;
|
||||
const { type: type_add, name: name_add = type_add, value: value_add } = data_add;
|
||||
const data = result[i_del][i_add] = {
|
||||
add: data_add,
|
||||
del: data_del,
|
||||
damage: oriDamage,
|
||||
difference: 0
|
||||
};
|
||||
if (name_del === name_add)
|
||||
continue;
|
||||
logger.debug(logger.yellow(`差异计算:${name_del}->${name_add}`));
|
||||
this.cache = Object.create(null);
|
||||
this.buffM.buffs.push({
|
||||
name: logger.green(`差异计算:${name_del}->${name_add}`),
|
||||
type: type_add,
|
||||
value: value_add
|
||||
});
|
||||
const newDamage = this.calc_skill(skill);
|
||||
this.buffM.buffs.pop();
|
||||
data.damage = newDamage;
|
||||
data.difference = newDamage.result.expectDMG - oriDamage.result.expectDMG;
|
||||
logger.debug(logger.magenta(`差异计算:${name_del}->${name_add} 伤害变化:${data.difference}`));
|
||||
}
|
||||
this.buffM.buffs.pop();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
default(param, value) {
|
||||
if (typeof param === 'object') {
|
||||
this.defaultSkill = param;
|
||||
|
|
@ -271,14 +371,16 @@ export class Calculator {
|
|||
}, this).reduce((previousValue, buff) => {
|
||||
const { value } = buff;
|
||||
let add = 0;
|
||||
if (isRatio && typeof value === 'number' && value < 1) {
|
||||
if (isRatio && typeof value === 'number' && Math.abs(value) < 1) {
|
||||
add = value * initial;
|
||||
}
|
||||
else {
|
||||
add = this.calc_value(value, buff);
|
||||
if (add < 1 && isRatio && (typeof value === 'string' || Array.isArray(value)))
|
||||
if (Math.abs(add) < 1 && isRatio && (typeof value === 'string' || Array.isArray(value)))
|
||||
add *= initial;
|
||||
}
|
||||
if (!this.usefulBuffs.find(b => b.name === buff.name && b.type === buff.type && add === buff.value))
|
||||
this.usefulBuffs.push({ ...buff, value: add });
|
||||
logger.debug(`\tBuff:${buff.name}对${buff.range || '全类型'}增加${add}${buff.element || ''}${type}`);
|
||||
return previousValue + add;
|
||||
}, initial);
|
||||
|
|
@ -317,7 +419,8 @@ export class Calculator {
|
|||
return VulnerabilityArea;
|
||||
}
|
||||
get_ResistanceArea(skill, usefulBuffs) {
|
||||
const ResistanceArea = this.get('无视抗性', 1 + this.enemy.resistance, skill, usefulBuffs);
|
||||
let ResistanceArea = this.get('无视抗性', 1 + this.enemy.resistance, skill, usefulBuffs);
|
||||
ResistanceArea = Math.min(2, ResistanceArea);
|
||||
logger.debug(`抗性区:${ResistanceArea}`);
|
||||
return ResistanceArea;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import type { BuffManager, anomaly, buff, buffType, element } from './BuffManager.ts'
|
||||
import type { ZZZAvatarInfo } from '../avatar.js'
|
||||
import { getMapData } from '../../utils/file.js'
|
||||
import { elementEnum, anomalyEnum } from './BuffManager.js'
|
||||
import * as prop from '../../lib/convert/property.js'
|
||||
import { getMapData } from '../../utils/file.js'
|
||||
import { charData } from './avatar.js'
|
||||
import _ from 'lodash'
|
||||
|
||||
|
|
@ -29,6 +30,8 @@ export interface skill {
|
|||
* 当为数组类型时(多类型共存),满足数组内其一类型即可,判断规则同上
|
||||
*/
|
||||
redirect?: string | string[] | anomaly[] | "追加攻击"[]
|
||||
/** 是否为主要技能。`true`时%XX伤害 默认计算该技能 */
|
||||
isMain?: boolean
|
||||
/** 角色面板伤害统计中是否隐藏显示 */
|
||||
isHide?: boolean
|
||||
/** 禁用伤害计算cache */
|
||||
|
|
@ -41,14 +44,19 @@ export interface skill {
|
|||
}) => boolean)
|
||||
/** 自定义计算逻辑 */
|
||||
dmg?: (calc: Calculator) => damage
|
||||
/** 伤害计算前调用,可自由定义各属性等 */
|
||||
/**
|
||||
* 伤害计算前调用,可自由定义各属性等
|
||||
* 此操作只作用于当前技能
|
||||
*/
|
||||
before?: ({ avatar, calc, usefulBuffs, skill, props, areas }: {
|
||||
avatar: ZZZAvatarInfo
|
||||
calc: Calculator
|
||||
usefulBuffs: buff[]
|
||||
/** 技能自身 */
|
||||
skill: skill
|
||||
/** 属性数据。设置后不会更改 */
|
||||
props: damage['props']
|
||||
/** 乘区数据。设置后不会更改 */
|
||||
areas: damage['areas']
|
||||
}) => void
|
||||
/** 伤害计算后调用,可对结果进行修改等 */
|
||||
|
|
@ -65,6 +73,8 @@ export interface skill {
|
|||
export interface damage {
|
||||
/** 技能类型 */
|
||||
skill: skill
|
||||
/** 有益Buffs */
|
||||
usefulBuffs: buff[]
|
||||
/** 技能属性 */
|
||||
props?: skill['props']
|
||||
/** 各乘区数据 */
|
||||
|
|
@ -102,6 +112,21 @@ export interface damage {
|
|||
|
||||
const elementType2element = (elementType: number) => elementEnum[[0, 1, 2, 3, -1, 4][elementType - 200]] as element
|
||||
|
||||
const baseValueData = {
|
||||
"生命值百分比": [0.03, '3.0%'],
|
||||
"生命值": [112, '112'],
|
||||
"攻击力百分比": [0.03, '3.0%'],
|
||||
"攻击力": [19, '19'],
|
||||
"防御力百分比": [0.048, '4.8%'],
|
||||
"防御力": [15, '15'],
|
||||
"暴击率": [0.024, '2.4%'],
|
||||
"暴击伤害": [0.048, '4.8%'],
|
||||
"穿透值": [9, '9'],
|
||||
"异常精通": [9, '9']
|
||||
} as const
|
||||
|
||||
type statKeys = keyof typeof baseValueData
|
||||
|
||||
const AnomalyData = getMapData('AnomalyData') as {
|
||||
name: string,
|
||||
element: element,
|
||||
|
|
@ -129,6 +154,7 @@ export class Calculator {
|
|||
readonly buffM: BuffManager
|
||||
readonly avatar: ZZZAvatarInfo
|
||||
readonly skills: skill[] = []
|
||||
private usefulBuffs: buff[] = []
|
||||
private cache: { [type: string]: damage } = Object.create(null)
|
||||
private props: Exclude<damage['props'], undefined> = {}
|
||||
/** 当前正在计算的技能 */
|
||||
|
|
@ -206,6 +232,7 @@ export class Calculator {
|
|||
logger.debug(`${logger.green(skill.type)}${skill.name}伤害计算:`)
|
||||
if (skill.dmg) {
|
||||
const dmg = skill.dmg(this)
|
||||
dmg.skill ||= skill
|
||||
logger.debug('自定义计算最终伤害:', dmg.result)
|
||||
return dmg
|
||||
}
|
||||
|
|
@ -248,14 +275,17 @@ export class Calculator {
|
|||
areas.AnomalyProficiencyArea ??= this.get_AnomalyProficiencyArea(skill, usefulBuffs)
|
||||
areas.AnomalyBoostArea ??= this.get_AnomalyBoostArea(skill, usefulBuffs)
|
||||
areas.LevelArea ??= this.get_LevelArea()
|
||||
props.异常暴击率 = this.get_AnomalyCRITRate(skill, usefulBuffs)
|
||||
props.异常暴击伤害 = this.get_AnomalyCRITDMG(skill, usefulBuffs)
|
||||
areas.CriticalArea ??= 1 + props.异常暴击率! * (props.异常暴击伤害! - 1)
|
||||
if (skill.type !== '紊乱') { // 紊乱暂无异常暴击区
|
||||
props.异常暴击率 ??= this.get_AnomalyCRITRate(skill, usefulBuffs)
|
||||
props.异常暴击伤害 ??= this.get_AnomalyCRITDMG(skill, usefulBuffs)
|
||||
areas.CriticalArea ??= 1 + props.异常暴击率! * (props.异常暴击伤害! - 1)
|
||||
}
|
||||
} else {
|
||||
props.暴击率 = this.get_CRITRate(skill, usefulBuffs)
|
||||
props.暴击伤害 = this.get_CRITDMG(skill, usefulBuffs)
|
||||
props.暴击率 ??= this.get_CRITRate(skill, usefulBuffs)
|
||||
props.暴击伤害 ??= this.get_CRITDMG(skill, usefulBuffs)
|
||||
areas.CriticalArea ??= 1 + props.暴击率! * (props.暴击伤害! - 1)
|
||||
}
|
||||
areas.CriticalArea ??= 1
|
||||
logger.debug(`暴击期望:${areas.CriticalArea}`)
|
||||
areas.BoostArea ??= this.get_BoostArea(skill, usefulBuffs)
|
||||
areas.VulnerabilityArea ??= this.get_VulnerabilityArea(skill, usefulBuffs)
|
||||
|
|
@ -274,7 +304,8 @@ export class Calculator {
|
|||
critDMG: BasicArea * 暴击伤害! * BoostArea * VulnerabilityArea * ResistanceArea * DefenceArea,
|
||||
expectDMG: BasicArea * CriticalArea * BoostArea * VulnerabilityArea * ResistanceArea * DefenceArea
|
||||
}
|
||||
const damage: damage = { skill, props, areas, result }
|
||||
const damage: damage = { skill, usefulBuffs: _.sortBy(this.usefulBuffs, ['type', 'value']).reverse(), props, areas, result }
|
||||
this.usefulBuffs = []
|
||||
if (skill.after) {
|
||||
damage.add = (d) => {
|
||||
if (typeof d === 'string') d = this.calc_skill(d)
|
||||
|
|
@ -292,6 +323,7 @@ export class Calculator {
|
|||
damage.fnc!(v => v * n)
|
||||
}
|
||||
skill.after({ avatar: this.avatar, calc: this, usefulBuffs, skill, damage })
|
||||
delete damage.add, delete damage.fnc, delete damage.x
|
||||
}
|
||||
logger.debug('最终伤害:', result)
|
||||
if (!skill.banCache) this.cache[skill.type] = damage
|
||||
|
|
@ -310,6 +342,113 @@ export class Calculator {
|
|||
}).filter(v => v && v.result?.expectDMG && !v.skill?.isHide) as damage[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算词条伤害差异
|
||||
* @param types 需进行比较的词条数组
|
||||
*/
|
||||
calc_differences(skill?: skill, types?: statKeys[]) {
|
||||
if (!skill) {
|
||||
skill = this.skills.find((skill) => skill.isMain) // 主技能
|
||||
|| this.calc().sort((a, b) => b.result.expectDMG - a.result.expectDMG)[0]?.skill // 伤害最高技能
|
||||
}
|
||||
// 未指定types时,筛选评分权重大于0的词条进行差异计算
|
||||
if (!types || !types.length) {
|
||||
types = Object.entries(this.avatar.scoreWeight)
|
||||
.reduce((acc: { type: statKeys, weight: number }[], [id, weight]) => {
|
||||
if (weight > 0) {
|
||||
const type = prop.idToName(id) as statKeys
|
||||
if (type && baseValueData[type]) {
|
||||
acc.push({ type, weight })
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
.slice(0, 7) // 默认最多7个
|
||||
.sort((a, b) => b.weight - a.weight) // 按权重从大到小排序
|
||||
.map(({ type }) => type)
|
||||
}
|
||||
const base: { [type: string]: number } = {}
|
||||
types.forEach(type => base[type] = type.includes('百分比') ? this.avatar.base_properties[
|
||||
type.includes('攻击力') ? 'ATK' : type.includes('生命值') ? 'HP' : 'DEF'
|
||||
] * baseValueData[type][0] : baseValueData[type][0])
|
||||
logger.debug(logger.red('词条变化值:'), base)
|
||||
const buffs = types.map(t => ({
|
||||
name: t,
|
||||
shortName: prop.nameToShortName3(t),
|
||||
type: t.replace('百分比', '') as buff['type'],
|
||||
value: base[t],
|
||||
valueBase: baseValueData[t][1]
|
||||
}))
|
||||
return this._calc_differences(skill, buffs)
|
||||
}
|
||||
|
||||
/* 计算已注册技能差异 */
|
||||
_calc_differences<B extends { name: skill['type'], type: buff['type'], value: buff['value'] }>(
|
||||
skill: string,
|
||||
buffs: B[]
|
||||
): { add: B, del: B, damage: damage, difference: number }[][]
|
||||
/* 计算技能差异 */
|
||||
_calc_differences<B extends { name: string, type: buff['type'], value: buff['value'] }>(
|
||||
skill: skill,
|
||||
buffs: B[]
|
||||
): { add: B, del: B, damage: damage, difference: number }[][]
|
||||
/**
|
||||
* 以buff形式两两组合进行差异计算
|
||||
* @param buffs 需要进行组合差异计算的buffs
|
||||
* @returns 差异计算结果。`buffs.length维`结果数组
|
||||
*/
|
||||
_calc_differences<B extends { name: string, type: buff['type'], value: buff['value'] }>(
|
||||
skill: skill['type'] | skill,
|
||||
buffs: B[]
|
||||
): { add: B, del: B, damage: damage, difference: number }[][] {
|
||||
if (typeof skill === 'string') {
|
||||
const MySkill = this.skills.find(s => s.type === skill)
|
||||
if (!MySkill) return []
|
||||
return this._calc_differences(MySkill, buffs)
|
||||
}
|
||||
const oriDamage = this.calc_skill(skill)
|
||||
const result: { del: B, add: B, damage: damage, difference: number }[][] = []
|
||||
for (const i_del in buffs) {
|
||||
result[i_del] = []
|
||||
const data_del = buffs[i_del]
|
||||
const { type: type_del, name: name_del = type_del, value: value_del } = data_del
|
||||
logger.debug(logger.blue(`差异计算:${name_del}`))
|
||||
// @ts-ignore
|
||||
this.buffM.buffs.push({
|
||||
name: logger.green(`差异计算:${name_del}`),
|
||||
type: type_del,
|
||||
value: ({ calc }) => -calc.calc_value(value_del) // 转为负值
|
||||
})
|
||||
for (const i_add in buffs) {
|
||||
const data_add = buffs[i_add]
|
||||
data_add.name ??= data_add.type
|
||||
const { type: type_add, name: name_add = type_add, value: value_add } = data_add
|
||||
const data = result[i_del][i_add] = {
|
||||
add: data_add,
|
||||
del: data_del,
|
||||
damage: oriDamage,
|
||||
difference: 0
|
||||
}
|
||||
if (name_del === name_add) continue
|
||||
logger.debug(logger.yellow(`差异计算:${name_del}->${name_add}`))
|
||||
this.cache = Object.create(null)
|
||||
// @ts-ignore
|
||||
this.buffM.buffs.push({
|
||||
name: logger.green(`差异计算:${name_del}->${name_add}`),
|
||||
type: type_add,
|
||||
value: value_add
|
||||
})
|
||||
const newDamage = this.calc_skill(skill)
|
||||
this.buffM.buffs.pop()
|
||||
data.damage = newDamage
|
||||
data.difference = newDamage.result.expectDMG - oriDamage.result.expectDMG
|
||||
logger.debug(logger.magenta(`差异计算:${name_del}->${name_add} 伤害变化:${data.difference}`))
|
||||
}
|
||||
this.buffM.buffs.pop()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置后续新增buff参数的默认值
|
||||
* @param obj 直接覆盖默认值
|
||||
|
|
@ -414,7 +553,7 @@ export class Calculator {
|
|||
|
||||
/**
|
||||
* 获取局内属性原始值
|
||||
* @param isRatio 是否支持buff.value为数值/字符串/数组类型且<1时按初始数值百分比提高处理
|
||||
* @param isRatio 是否支持buff.value为数值/字符串/数组类型且<1时按 **`初始数值`** 百分比提高处理
|
||||
*/
|
||||
get(type: buff['type'], initial: number, skill: skill, usefulBuffs: buff[] = this.buffM.buffs, isRatio = false): number {
|
||||
return this.props[type] ??= this.buffM._filter(usefulBuffs, {
|
||||
|
|
@ -425,13 +564,15 @@ export class Calculator {
|
|||
}, this).reduce((previousValue, buff) => {
|
||||
const { value } = buff
|
||||
let add = 0
|
||||
if (isRatio && typeof value === 'number' && value < 1) { // 值小于1时,认为是百分比
|
||||
if (isRatio && typeof value === 'number' && Math.abs(value) < 1) { // 绝对值小于1时,认为是百分比
|
||||
add = value * initial
|
||||
} else {
|
||||
add = this.calc_value(value, buff)
|
||||
if (add < 1 && isRatio && (typeof value === 'string' || Array.isArray(value)))
|
||||
if (Math.abs(add) < 1 && isRatio && (typeof value === 'string' || Array.isArray(value)))
|
||||
add *= initial
|
||||
}
|
||||
if (!this.usefulBuffs.find(b => b.name === buff.name && b.type === buff.type && add === buff.value))
|
||||
this.usefulBuffs.push({ ...buff, value: add })
|
||||
logger.debug(`\tBuff:${buff.name}对${buff.range || '全类型'}增加${add}${buff.element || ''}${type}`)
|
||||
return previousValue + add
|
||||
}, initial)
|
||||
|
|
@ -484,7 +625,8 @@ export class Calculator {
|
|||
|
||||
/** 抗性区 */
|
||||
get_ResistanceArea(skill: skill, usefulBuffs: buff[]) {
|
||||
const ResistanceArea = this.get('无视抗性', 1 + this.enemy.resistance, skill, usefulBuffs)
|
||||
let ResistanceArea = this.get('无视抗性', 1 + this.enemy.resistance, skill, usefulBuffs)
|
||||
ResistanceArea = Math.min(2, ResistanceArea)
|
||||
logger.debug(`抗性区:${ResistanceArea}`)
|
||||
return ResistanceArea
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,10 +104,10 @@ async function importFile(type, name, isWatch = false) {
|
|||
}
|
||||
}
|
||||
await init();
|
||||
export function avatar_ability(avatar) {
|
||||
export function avatar_calc(avatar) {
|
||||
const m = calcFnc.character[avatar.id];
|
||||
if (!m)
|
||||
return [];
|
||||
return;
|
||||
const buffM = new BuffManager(avatar);
|
||||
const calc = new Calculator(buffM);
|
||||
logger.debug('initial_properties', avatar.initial_properties);
|
||||
|
|
@ -120,7 +120,7 @@ export function avatar_ability(avatar) {
|
|||
if (m.calc)
|
||||
m.calc(buffM, calc, avatar);
|
||||
logger.debug(`Buff*${buffM.buffs.length}:`, buffM.buffs);
|
||||
return calc.calc();
|
||||
return calc;
|
||||
}
|
||||
export function weapon_buff(weapon, buffM) {
|
||||
const name = weapon?.name;
|
||||
|
|
|
|||
|
|
@ -137,10 +137,10 @@ async function importFile(type: 'weapon' | 'set', name: string, isWatch = false)
|
|||
|
||||
await init()
|
||||
|
||||
/** 角色计算 */
|
||||
export function avatar_ability(avatar: ZZZAvatarInfo) {
|
||||
/** 角色计算实例 */
|
||||
export function avatar_calc(avatar: ZZZAvatarInfo) {
|
||||
const m = calcFnc.character[avatar.id]
|
||||
if (!m) return []
|
||||
if (!m) return
|
||||
const buffM = new BuffManager(avatar)
|
||||
const calc = new Calculator(buffM)
|
||||
logger.debug('initial_properties', avatar.initial_properties)
|
||||
|
|
@ -150,7 +150,7 @@ export function avatar_ability(avatar: ZZZAvatarInfo) {
|
|||
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()
|
||||
return calc
|
||||
}
|
||||
|
||||
/** 武器加成 */
|
||||
|
|
|
|||
|
|
@ -30,7 +30,11 @@ export const buffs = [
|
|||
/** @type {import('../../Calculator.ts').Calculator['skills']} */
|
||||
export const skills = [
|
||||
{ name: '灼烧', type: '灼烧' },
|
||||
{ name: '普攻:火力镇压四段', type: 'AQ4' },
|
||||
{
|
||||
name: '普攻:火力镇压四段',
|
||||
isMain: true,
|
||||
type: 'AQ4'
|
||||
},
|
||||
{ name: '闪避反击:逆火', type: 'CF' },
|
||||
{ name: '强化特殊技:盛燃烈火', type: 'EQ' },
|
||||
{ name: '连携技:昂扬烈焰', type: 'RL' },
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ export const skills = [
|
|||
name: '普攻:协奏狙杀·冥狱',
|
||||
type: 'AXQ',
|
||||
redirect: ['AXQ', '追加攻击'],
|
||||
isMain: true,
|
||||
after: ({ damage }) => damage.add('AXQ0')
|
||||
},
|
||||
{ name: '闪避反击:极魂罚', type: 'CF' },
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export const skills = [
|
|||
type: 'EQ',
|
||||
after: ({ damage }) => damage.add('EQ0')
|
||||
},
|
||||
{ name: '连携技:月辉丝·绊', type: 'RL' },
|
||||
{ name: '连携技:月辉丝·绊', isMain: true, type: 'RL' },
|
||||
{ name: '终结技:月辉丝·弦音', type: 'RZ' },
|
||||
{
|
||||
name: '6影月辉丝·弦',
|
||||
|
|
|
|||
|
|
@ -35,7 +35,12 @@ export const skills = [
|
|||
isHide: true,
|
||||
after: ({ damage }) => damage.x(2)
|
||||
},
|
||||
{ name: '强化特殊技:小心裙角', type: 'EQ', after: ({ damage }) => damage.add('EQ0') },
|
||||
{
|
||||
name: '强化特殊技:小心裙角',
|
||||
type: 'EQ',
|
||||
isMain: true,
|
||||
after: ({ damage }) => damage.add('EQ0')
|
||||
},
|
||||
{ name: '连携技:抱歉…', type: 'RL' },
|
||||
{ name: '终结技:非、非常抱歉!', type: 'RZ' }
|
||||
]
|
||||
|
|
@ -36,7 +36,7 @@ export const skills = [
|
|||
{ name: '感电每次', type: '感电' },
|
||||
{ name: '普攻:穿云五段', type: 'AP5' },
|
||||
{ name: '普攻:落羽', type: 'AX' },
|
||||
{ name: '冲刺攻击:飞弦·斩', type: 'CCQ3' },
|
||||
{ name: '冲刺攻击:飞弦·斩', isMain: true, type: 'CCQ3' },
|
||||
{ name: '强化特殊技:地网', type: 'EQ' },
|
||||
{ name: '连携技:会·离', type: 'RL' },
|
||||
{ name: '终结技:残心', type: 'RZ' }
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@
|
|||
// calc.new({
|
||||
// name: '蓄力攻击:三段蓄',
|
||||
// type: 'AX3',
|
||||
// isMain: true,
|
||||
// after: ({ avatar, damage }) => avatar.rank >= 6 && damage.add('AX2')
|
||||
// })
|
||||
// calc.new({ name: '强化特殊技:飞雪', type: 'EQ1' })
|
||||
|
|
@ -164,6 +165,7 @@ export const skills = [
|
|||
{
|
||||
name: '蓄力攻击:三段蓄',
|
||||
type: 'AX3',
|
||||
isMain: true,
|
||||
after: ({ avatar, damage }) => avatar.rank >= 6 && damage.add('AX2')
|
||||
},
|
||||
{ name: '强化特殊技:飞雪', type: 'EQ1' },
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ export const skills = [
|
|||
{
|
||||
name: '强化E极性紊乱',
|
||||
type: '紊乱',
|
||||
isMain: true,
|
||||
banCache: true,
|
||||
before: ({ calc, areas }) => {
|
||||
const skill = { type: '紊乱' }
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ export const skills = [
|
|||
{
|
||||
name: '强化特殊技:全弹连射',
|
||||
type: 'EQ',
|
||||
isMain: true,
|
||||
after: ({ damage }) => damage.add('EQ2')
|
||||
},
|
||||
{ name: '连携技:歼灭模式', type: 'RL' },
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export const buffs = [
|
|||
{
|
||||
name: '核心被动:燃油特调',
|
||||
type: '增伤',
|
||||
value: ({ calc }) => Math.min(30, Math.floor(calc.get_AnomalyProficiency() / 10)) * 0.01,
|
||||
value: ({ calc }) => Math.min(30, calc.get_AnomalyProficiency() / 10) * 0.01,
|
||||
isForever: true,
|
||||
range: ['TY', 'Y6Y']
|
||||
},
|
||||
|
|
@ -46,6 +46,7 @@ export const skills = [
|
|||
{
|
||||
name: '核心被动:余烬',
|
||||
type: 'TY',
|
||||
isMain: true,
|
||||
redirect: 'L'
|
||||
},
|
||||
// { name: '普攻:炽焰直调式五段', type: 'AP5' },
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export const buffs = [
|
|||
/** @type {import('../../Calculator.ts').Calculator['skills']} */
|
||||
export const skills = [
|
||||
{ name: '感电每次', type: '感电' },
|
||||
{ name: '紊乱', type: '紊乱' },
|
||||
{ name: '紊乱', isMain: true, type: '紊乱' },
|
||||
{ name: '闪避反击:违章处罚', type: 'CF' },
|
||||
{
|
||||
name: '强化特殊技:超规工程清障',
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ export const skills = [
|
|||
{
|
||||
name: '特殊技:噬爪·噩梦袭影',
|
||||
type: 'EPLP',
|
||||
isMain: true,
|
||||
redirect: ['EPLP', '追加攻击']
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export const buffs = [
|
|||
|
||||
/** @type {import('../../Calculator.ts').Calculator['skills']} */
|
||||
export const skills = [
|
||||
{ name: '强击', type: '强击' },
|
||||
{ name: '强击', isMain: true, type: '强击' },
|
||||
{ name: '普攻:准备发车四段', type: 'AP4' },
|
||||
{ name: '闪避反击:动力漂移', type: 'CF' },
|
||||
{ name: '强化特殊技:引擎转(每圈)', type: 'EQZ' },
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export const buffs = [
|
|||
/** @type {import('../../Calculator.ts').Calculator['skills']} */
|
||||
export const skills = [
|
||||
{ name: '强击', type: '强击' },
|
||||
{ name: '普攻:猫猫爪刺四段', type: 'AP4' },
|
||||
{ name: '普攻:猫猫爪刺四段', isMain: true, type: 'AP4' },
|
||||
{ name: '闪避反击:虚影双刺', type: 'CF' },
|
||||
{ name: '强化特殊技:超~凶奇袭!', type: 'EQ' },
|
||||
{ name: '连携技:刃爪挥击', type: 'RL' },
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export const buffs = [
|
|||
|
||||
/** @type {import('../../Calculator.ts').Calculator['skills']} */
|
||||
export const skills = [
|
||||
{ name: '强击', type: '强击' },
|
||||
{ name: '强击', isMain: true, type: '强击' },
|
||||
{ name: '紊乱', type: '紊乱' },
|
||||
{ name: '普攻:跳步刃舞六段(狂热)', type: 'AP6' },
|
||||
{ name: '普攻:萨霍夫跳0', type: 'AX0', isHide: true },
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export const skills = [
|
|||
},
|
||||
{ name: '普攻:间奏/终曲每[震音]', type: 'AQ', before },
|
||||
{ name: '特殊技:《风铃与旧约》', type: 'EP', before },
|
||||
{ name: '和弦追加[震音]', type: 'EQZ', before },
|
||||
{ name: '和弦追加[震音]', isMain: true, type: 'EQZ', before },
|
||||
{ name: '天赋追加[震音]', type: 'EZ', before },
|
||||
{
|
||||
name: '追加[音簇]*3',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ export const buffs = [
|
|||
value: 0.6,
|
||||
range: ['EQ']
|
||||
},
|
||||
|
||||
{
|
||||
name: '6影',
|
||||
type: '穿透率',
|
||||
|
|
@ -40,7 +39,11 @@ export const buffs = [
|
|||
/** @type {import('../../Calculator.ts').Calculator['skills']} */
|
||||
export const skills = [
|
||||
{ name: '碎冰', type: '碎冰' },
|
||||
{ name: '普攻:急冻修剪法三段', type: 'AQ3' },
|
||||
{
|
||||
name: '普攻:急冻修剪法三段',
|
||||
isMain: true,
|
||||
type: 'AQ3'
|
||||
},
|
||||
{ name: '闪避反击:暗礁', type: 'CF' },
|
||||
{ name: '冲刺攻击:寒潮', type: 'CCP' },
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const skills = [
|
|||
{ name: '蓄力普攻:五段一级', type: 'AX51' },
|
||||
{ name: '蓄力普攻:五段二级', type: 'AX52' },
|
||||
{ name: '闪避反击:保持清洁', type: 'CF' },
|
||||
{ name: '蓄力强化特殊技:狂猎时刻', type: 'EQX' },
|
||||
{ name: '蓄力强化特殊技:狂猎时刻', isMain: true, type: 'EQX' },
|
||||
{ name: '连携技:遵命', type: 'RL' },
|
||||
{ name: '终结技:不辱使命', type: 'RZ' }
|
||||
]
|
||||
|
|
@ -41,15 +41,18 @@ export const buffs = [
|
|||
element: ['Fire', 'Ice'],
|
||||
value: ({ calc }) => {
|
||||
const Impact = calc.get_Impact()
|
||||
const step = 0.0125 + Math.max(0, Math.floor((Impact - 170) / 10) * 25 / 10000)
|
||||
const step = 0.0125 + Math.max(0, (Impact - 170) / 10 * 25 / 10000)
|
||||
return Math.min(0.75, step * 20)
|
||||
},
|
||||
is: {
|
||||
team: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
/** @type {import('../../Calculator.ts').Calculator['skills']} */
|
||||
export const skills = [
|
||||
{ name: '普攻:强力终结一击', type: 'AQ5Q' },
|
||||
{ name: '普攻:强力终结一击', isMain: true, type: 'AQ5Q' },
|
||||
{ name: '闪避反击:烈闪', type: 'CF' },
|
||||
{ name: '快速支援:烈闪-守', type: 'LK' },
|
||||
{ name: '强化E:V式日轮升拳-全冲程', type: 'EQ1' },
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export const skills = [
|
|||
name: '特殊技:苍光',
|
||||
type: 'EPC',
|
||||
redirect: ['EPC', '追加攻击'],
|
||||
isMain: true,
|
||||
after: ({ damage }) => damage.add('EPC0')
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ export const skills = [
|
|||
},
|
||||
{ name: '闪避反击:獠牙折转!', type: 'CF' },
|
||||
{ name: '强化特殊技:全垒打短按', type: 'EQP' },
|
||||
{ name: '强化特殊技:全垒打长按', type: 'EQX' },
|
||||
{ name: '强化特殊技:全垒打长按', isMain: true, type: 'EQX' },
|
||||
{
|
||||
name: '连携技:大满贯!',
|
||||
type: 'RL',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue