雨果伤害计算等

This commit is contained in:
UCPr 2025-08-12 02:47:00 +08:00
parent 14af1a20e1
commit 151f87093a
20 changed files with 340 additions and 53 deletions

View file

@ -67,14 +67,14 @@ export interface buff {
}) => number)
/**
* Buff增益技能类型****
* - **redirect****range**
* - **redirect****range****redirect**
* - **redirect****range**
* - **redirect****range****type****redirect**
* - 使**include****exclude**
*/
range?: string[] | anomaly[] | "追加攻击"[]
/**
* Buff增益技能类型****
* - **range**
* - **range**
* - **range****include**buff对**exclude**
* - **range****include**buff生效
* - **redirect****range****include****include****redirect**
@ -82,7 +82,7 @@ export interface buff {
include?: string[]
/**
* Buff增益技能类型****
* - **include**
* - **include**
* - **range****include**
*/
exclude?: string[]
@ -205,15 +205,15 @@ export class BuffManager {
const buffRange = buff.range
const skillRange = param.range?.filter(r => typeof r === 'string')
if (!skillRange?.length) return true // 对任意类型生效
// buff作用范围向后覆盖
// 存在重定向时range须全匹配redirect向后覆盖
// buff作用范围向后覆盖生效
// 存在重定向时range与type全匹配时生效redirect向后覆盖生效
else if (param.redirect) {
if (skillRange.some(ST => buffRange.some(BT => BT === ST))) return true
const redirect = Array.isArray(param.redirect) ? param.redirect : [param.redirect]
if (buffRange.some(BT => redirect.some(RT => RT.startsWith(BT)))) return true
return false
}
// 不存在重定向时range向后覆盖
// 不存在重定向时range向后覆盖生效
return skillRange.some(ST => buffRange.some(BT => ST.startsWith(BT)))
}
// 00
@ -276,8 +276,8 @@ export class BuffManager {
/**
* **** buff
* - range数组的筛选
* - range须全匹配redirect向后覆盖
* - range向后覆盖
* - range向后覆盖生效
* - range与type全匹配时生效redirect向后覆盖生效
*/
filter(obj: Partial<Pick<buff, filterable>> & { element: element, redirect?: skill['redirect'] }, calc?: Calculator): buff[]
/**

View file

@ -114,12 +114,29 @@ export class Calculator {
const areas = {};
if (skill.before)
skill.before({ avatar: this.avatar, calc: this, usefulBuffs, skill, props, areas });
logger.debug(`有效buff*${usefulBuffs.length}/${this.buffM.buffs.length}`);
const isAnomaly = typeof anomalyEnum[skill.type.slice(0, 2)] === 'number';
if (!areas.BasicArea) {
let Multiplier = props.倍率;
if (!Multiplier) {
if (skill.fixedMultiplier) {
Multiplier = skill.fixedMultiplier;
if (skill.multiplier) {
switch (typeof skill.multiplier) {
case 'number':
Multiplier = skill.multiplier;
break;
case 'string':
Multiplier = this.get_SkillMultiplier(skill.multiplier);
break;
case 'object':
Multiplier = skill.multiplier[this.get_SkillLevel(skill.type[0]) - 1];
break;
case 'function':
Multiplier = skill.multiplier({ avatar: this.avatar, buffM: this.buffM, calc: this });
break;
default:
Multiplier = this.get_SkillMultiplier(skill.type);
logger.warn('无效的技能倍率:', skill);
}
}
else if (isAnomaly) {
Multiplier = (skill.type.startsWith('紊乱') ?
@ -127,10 +144,7 @@ export class Calculator {
this.get_AnomalyMultiplier(skill, usefulBuffs, skill.name.includes('每') ? 1 : 0)) || 0;
}
else {
if (skill.skillMultiplier)
Multiplier = skill.skillMultiplier[this.get_SkillLevel(skill.type[0]) - 1];
else
Multiplier = this.get_SkillMultiplier(skill.type);
Multiplier = this.get_SkillMultiplier(skill.type);
}
const ExtraMultiplier = this.get_ExtraMultiplier(skill, usefulBuffs);
Multiplier += ExtraMultiplier;

View file

@ -14,23 +14,37 @@ export interface skill {
type: string
/** 属性类型,不指定时,默认取角色属性 */
element: element
/** 技能倍率数组于character/角色名/data.json中自动获取该json中不存在相应数据时可填写该值以填写值为准 */
skillMultiplier?: number[]
/** 指定常数倍率(可吃倍率增益) */
fixedMultiplier?: number
/**
*
* @default number[] character//data.json中自动获取
* @number
*
* @string
* type`calc.get_SkillMultiplier(skill.multiplier)`
* @array
* - **`技能等级-1`**
* - character//data.json中自动获取
* @function
*
*/
multiplier?: number | string | number[] | (({ avatar, buffM, calc }: {
avatar: ZZZAvatarInfo
buffM: BuffManager
calc: Calculator
}) => number)
/** 指定局内固定属性 */
props?: { [key in buffType]?: number }
/**
*
*
* X"()Y()使Y的类型
* - range须全匹配redirect向后覆盖
* - range向后覆盖
* - range向后覆盖生效
* - range与type全匹配时生效redirect向后覆盖生效
*
*
*/
redirect?: string | string[] | anomaly[] | "追加攻击"[]
/** 是否为主要技能。`true`时%XX伤害 默认计算该技能 */
/** 是否为主要技能。`true`时%XX伤害 默认计算该技能且会作为角色伤害排名依据 */
isMain?: boolean
/** 角色面板伤害统计中是否隐藏显示 */
isHide?: boolean
@ -269,12 +283,29 @@ export class Calculator {
}, this)
const areas = {} as damage['areas']
if (skill.before) skill.before({ avatar: this.avatar, calc: this, usefulBuffs, skill, props, areas })
logger.debug(`有效buff*${usefulBuffs.length}/${this.buffM.buffs.length}`)
const isAnomaly = typeof anomalyEnum[skill.type.slice(0, 2) as anomaly] === 'number'
if (!areas.BasicArea) {
let Multiplier = props.
if (!Multiplier) {
if (skill.fixedMultiplier) {
Multiplier = skill.fixedMultiplier
if (skill.multiplier) { // 显式指定
switch (typeof skill.multiplier) {
case 'number':
Multiplier = skill.multiplier
break
case 'string':
Multiplier = this.get_SkillMultiplier(skill.multiplier)
break
case 'object':
Multiplier = skill.multiplier[this.get_SkillLevel(skill.type[0]) - 1]
break
case 'function':
Multiplier = skill.multiplier({ avatar: this.avatar, buffM: this.buffM, calc: this })
break
default:
Multiplier = this.get_SkillMultiplier(skill.type)
logger.warn('无效的技能倍率:', skill)
}
} else if (isAnomaly) {
Multiplier = (
skill.type.startsWith('紊乱') ?
@ -282,8 +313,7 @@ export class Calculator {
this.get_AnomalyMultiplier(skill, usefulBuffs, skill.name.includes('每') ? 1 : 0)
) || 0
} else {
if (skill.skillMultiplier) Multiplier = skill.skillMultiplier[this.get_SkillLevel(skill.type[0]) - 1]
else Multiplier = this.get_SkillMultiplier(skill.type)
Multiplier = this.get_SkillMultiplier(skill.type)
}
const ExtraMultiplier = this.get_ExtraMultiplier(skill, usefulBuffs)
Multiplier += ExtraMultiplier

View file

@ -100,7 +100,7 @@
/**
* Buff增益技能类型生效范围参考技能类型命名标准
* - 当技能参数不存在redirect时range作用范围向后覆盖
* - 当技能参数存在redirect时range须全匹配redirect向后覆盖
* - 当技能参数存在redirect时range与type全匹配时生效redirect向后覆盖生效
*/
range?: string[]
/** Buff增益属性类型无则对全部属性生效 */
@ -118,7 +118,7 @@
- **value**Buff增益值。具体解释如上述
- **range**Buff增益技能类型范围。该参数用于鉴别不同buff的[生效范围](#技能类型命名对buff作用的影响)(比如只对普攻生效),[填写方法](#技能类型命名标准)会在技能属性中详细说明
- **range**Buff增益技能类型范围匹配技能type。该参数用于鉴别不同buff的[生效范围](#技能类型命名对buff作用的影响)(比如只对普攻生效),[填写方法](#技能类型命名标准)会在技能属性中详细说明
- **element**Buff增益属性类型可为字符串或字符串数组。该参数用于鉴别不同buff的生效属性比如只对冰属性伤害生效。查看[属性类型](./BuffManager.ts#L5)
@ -329,7 +329,7 @@ buff作用范围将以技能类型命名为依据向后覆盖。以上述[艾莲
- 属性异常中**强击**和**碎冰**没有持续时间的概念,总倍率不受持续时间的影响也无法结算紊乱。因此对于作用于**异常持续时间**的buff其buff.range应填写异常对应的**状态异常****畏缩**和**霜寒**),灼烧等既是伤害异常也是状态异常则无需区分
- 对于`“X"(造成的伤害)被视为“Y”(伤害)`此类特殊技能,需要指定技能**重定向参数**同时上述buff覆盖规则会发生变化具体请参考[源码内描述](./Calculator.ts#L23)
- 对于`“X"(造成的伤害)被视为“Y”(伤害)`此类特殊技能,需要指定技能**重定向参数**同时上述buff覆盖规则会发生变化具体请参考[源码内描述](./Calculator.ts#L46)
> 需要注意的是:即使出现`“X"(造成的伤害)被视为“Y”(伤害)`,对**Y**类型的增益**X**不一定能吃到,视具体情况变化
@ -347,7 +347,7 @@ buff作用范围将以技能类型命名为依据向后覆盖。以上述[艾莲
角色每个技能各等级对应的倍率建议在[米游社官网图鉴](https://baike.mihoyo.com/zzz/wiki/channel/map/2/43)中查询。不建议使用第三方图鉴工具如B站的绝区零wiki其技能倍率可能存在错误
技能倍率大部分情况下为**等差数列**,少数情况下增量**存在变化**,请注意甄别。对于等差数列的技能倍率,我写了一个简易的生成函数,你可复制粘贴直接使用:
技能倍率大部分情况下为**等差数列**,少数情况下增量**存在变化**,请注意甄别。对于等差数列的技能倍率,下面是一个简易的生成函数,可复制粘贴直接使用:
<details>
<summary>点击展开</summary>
@ -428,7 +428,7 @@ counter(145.7, 159, 16)
通过在角色伤害计算文件中导出**calc**函数调用函数参数中calc的[defEnemy](./Calculator.ts)方法,你可以对此三个参数进行自定义
敌方基础属性可查看[此表](https://img.nga.178.com/attachments/mon_202407/16/axvkQq44x-2xpiZyT3cSwm-1hf.png)
敌方基础属性可查看[此表](https://docs.qq.com/sheet/DUHBodnJVQ1pKcFl4?tab=llkjkv)(最新)或[此图](https://img.nga.178.com/attachments/mon_202407/16/axvkQq44x-2xpiZyT3cSwm-1hf.png)
例如将敌人的1级基础防御力设置为36如提尔锋
@ -476,11 +476,11 @@ export function calc(buffM, calc, avatar) {
- [x] 伤害计算自定义支持
- [x] 伤害计算说明文档
- [x] 全角色伤害计算
- [ ] 组队伤害计算
- [ ] 词条收益分析
- [x] 词条收益分析
- [ ] 失衡值累积计算
- [ ] ~~异常积蓄值计算~~
- [ ] ~~治疗量计算~~
- [ ] ~~组队伤害计算~~
## 鸣谢

View file

@ -48,7 +48,7 @@ export const skills = [
name: '6影破甲凶弹',
type: 'Y6',
check: 6,
fixedMultiplier: 12,
multiplier: 12,
before: ({ usefulBuffs }) => usefulBuffs.push({
name: '6影',
type: '增伤',

View file

@ -59,7 +59,7 @@ export const skills = [
name: '6影月辉丝·弦',
type: 'Y6',
redirect: 'RL',
fixedMultiplier: 3.75,
check: ({ avatar }) => avatar.rank >= 6
multiplier: 3.75,
check: 6
}
]

View file

@ -20,7 +20,7 @@ export const skills = [
{
name: '2影格挡反击额外伤害',
type: 'Y2',
check: ({ avatar }) => avatar.rank >= 2,
check: 2,
isHide: true,
before: ({ areas, calc }) => {
areas.BasicArea = 3 * calc.get_DEF()

View file

@ -34,9 +34,9 @@ export const skills = [
{
name: '6影以太鹿弹',
type: 'EQ2',
fixedMultiplier: 2.2 * 4,
multiplier: 2.2 * 4,
isHide: true,
check: ({ avatar }) => avatar.rank >= 6
check: 6
},
{
name: '强化特殊技:全弹连射',

View file

@ -71,13 +71,13 @@ export const skills = [
{
name: '6影强化E双份额外余烬秒伤',
type: 'Y6Y',
fixedMultiplier: 1.2,
check: ({ avatar }) => avatar.rank >= 6
multiplier: 1.2,
check: 6
},
{
name: '6影强化E双份额外灼烧',
type: 'Y6灼烧',
check: ({ avatar }) => avatar.rank >= 6,
check: 6,
dmg: (calc) => {
const dmg = calc.calc_skill({
name: '灼烧每段',

View file

@ -17,8 +17,8 @@ export const skills = [
name: '6影额外伤害',
type: 'Y6',
isHide: true,
fixedMultiplier: 3.6,
check: ({ avatar }) => avatar.rank >= 6
multiplier: 3.6,
check: 6
},
{ name: '强化特殊技沸腾熔炉0', type: 'EQP0', isHide: true },
{

View file

@ -91,7 +91,7 @@ export const skills = [
{
name: '6影强击暴击额外攻击',
type: 'Y6',
check: ({ avatar }) => avatar.rank >= 6,
check: 6,
before: ({ calc, areas }) => {
const AnomalyProficiency = calc.get_AnomalyProficiency()
areas.BasicArea = AnomalyProficiency * 16

View file

@ -47,7 +47,7 @@ export const skills = [
name: '6影追加蓄力普攻三段',
type: 'AP3',
banCache: true,
check: ({ avatar }) => avatar.rank >= 6,
check: 6,
before: ({ usefulBuffs }) => usefulBuffs.push({
name: '6影',
type: '暴击率',

View file

@ -61,7 +61,7 @@ export const skills = [
{
name: '6影[火焰冲击]',
type: 'Y6',
check: ({ avatar }) => avatar.rank >= 6,
check: 6,
before: ({ calc, props }) => {
const Impact = calc.get_Impact()
props.倍率 = 2.5 + Math.min(5, Math.max(0, Math.floor(Impact - 170) * 5 / 100))

View file

@ -86,7 +86,7 @@ export const skills = [
{
name: '薇薇安的预言',
type: 'TW',
fixedMultiplier: 0.55
multiplier: 0.55
},
{ name: '闪避反击:羽刃反振', type: 'CF' },
{ name: '强化特殊技:堇花悼亡', type: 'EQ' },

View file

@ -20,8 +20,8 @@ export const skills = [
name: '6影额外伤害',
type: 'Y6',
isHide: true,
check: ({ avatar }) => avatar.rank >= 6,
fixedMultiplier: 5,
check: 6,
multiplier: 5,
props: {
暴击率: 1
}

View file

@ -0,0 +1,176 @@
/** @type {import('../../BuffManager.ts').BuffManager['buffs']} */
export const buffs = [
{
name: '1影',
type: '暴击率',
value: 0.12,
range: ['EQJ', 'RZJ']
},
{
name: '1影',
type: '暴击伤害',
value: 0.3,
range: ['EQJ', 'RZJ']
},
{
name: '2影',
type: '无视防御',
value: 0.15,
range: ['EQJ', 'RZJ']
},
{
name: '4影',
type: '无视抗性',
value: 0.12,
element: 'Ice'
},
{
name: '6影',
type: '增伤',
value: 0.6,
range: ['EQJ', 'RZJ']
},
{
name: '6影',
type: '倍率',
value: 10,
include: ['EQP']
},
{
name: '核心被动:终末裁决',
type: '攻击力',
value: 'TA2', // 按2名击破位计算
},
{
name: '核心被动:终末裁决',
type: '暴击率',
value: 0.12
},
{
name: '核心被动:终末裁决',
type: '暴击伤害',
value: 0.25
},
{
name: '核心被动:终末裁决',
type: '倍率',
value: ({ calc }) => calc.get_SkillMultiplier('TJ0'),
include: ['EQJ', 'RZJ']
},
{
name: '核心被动:终末裁决',
type: '倍率',
value: ({ calc }) => calc.get_SkillMultiplier('TJ1') * 5, // 5/12
include: ['EQJ', 'RZJ']
},
{
name: '核心被动:终末裁决',
type: '倍率',
value: ({ calc }) => calc.get_SkillMultiplier('TJ2') * 7, // 7/12
include: ['EQJ', 'RZJ']
},
{
name: '额外能力:终焉序曲',
type: '增伤',
value: 0.15, // 取非普通敌人
range: ['RL']
},
{
name: '额外能力:终焉序曲',
type: '增伤',
value: 0.4,
range: ['EQJ', 'RZJ']
}
]
/** @type {import('../../Calculator.ts').Calculator['skills']} */
export const skills = [
{ name: '碎冰', type: '碎冰' },
{
name: '普攻:暗渊四重奏四段·斩击',
type: 'AP4Z',
isHide: true
},
{
name: '普攻:暗渊四重奏四段',
type: 'AP4P',
after: ({ damage }) => damage.add('AP4Z')
},
{
name: '普攻:暗渊四重奏四段(蓄力)',
type: 'AP4X',
after: ({ damage }) => damage.add('AP4Z')
},
{
name: '普攻:暗渊协奏曲·斩击',
type: 'AQZ',
isHide: true
},
{
name: '普攻:暗渊协奏曲',
type: 'AQP',
after: ({ damage }) => damage.add('AQZ')
},
{
name: '普攻:暗渊协奏曲(蓄力)',
type: 'AQX',
after: ({ damage }) => damage.add('AQZ')
},
{
name: '闪避反击:诡影·斩',
type: 'CFP'
},
{
name: '闪避反击:诡影·斩(蓄力)',
type: 'CFX',
after: ({ damage }) => damage.add('CFP')
},
// 决算计算参考https://www.miyoushe.com/zzz/article/64534320
{
name: '强E魂狩·惩戒0', // 基础
type: 'EQ0',
isHide: true,
multiplier: ({ calc }) => calc.get_SkillMultiplier('EQP') * 0.05
},
{
name: '强E魂狩·惩戒',
type: 'EQP',
multiplier: ({ calc }) => calc.get_SkillMultiplier('EQP') * 0.95,
after: ({ damage }) => damage.add('EQ0')
},
{
name: '强E魂狩·惩戒[决算](12s失衡)', // 终结一击
type: 'EQJ',
isMain: true,
multiplier: ({ calc }) => calc.get_SkillMultiplier('EQP') * 0.95,
after: ({ damage }) => damage.add('EQ0')
},
{ name: '连携技:命运戏法', type: 'RL' },
{ name: '终结技:渎神者', type: 'RZP' },
{
name: '终结技:渎神者[决算](12s失衡)', // 基础
type: 'RZ0',
isHide: true,
multiplier: ({ calc }) => calc.get_SkillMultiplier('RZP') * (11 / 15)
},
{
name: '终结技:渎神者[决算](12s失衡)', // 终结一击
type: 'RZJ',
multiplier: ({ calc }) => calc.get_SkillMultiplier('RZP') * (4 / 15)
},
{
name: '[决算](固定倍率伤害)',
type: 'EQJP0', // 按强化特殊技伤害计算
multiplier: 'TJ0'
},
{
name: '[决算](5秒内每秒失衡伤害)',
type: 'EQJP1',
multiplier: 'TJ1'
},
{
name: '[决算](5秒外每秒失衡伤害)',
type: 'EQJP2',
multiplier: 'TJ2'
}
]

View file

@ -0,0 +1,54 @@
{
"skill": {
"AP4Z": [
1.491,1.627,1.763,1.899,2.035,2.171,2.307,2.443,2.579,2.715,2.851,2.987,3.123,3.259,3.395,3.531
],
"AP4P": [
0.586,0.64,0.694,0.748,0.802,0.856,0.91,0.964,1.018,1.072,1.126,1.18,1.234,1.288,1.342,1.396
],
"AP4X": [
1.18,1.288,1.396,1.504,1.612,1.72,1.828,1.936,2.044,2.152,2.26,2.368,2.476,2.584,2.692,2.8
],
"AQZ": [
1.434,1.565,1.696,1.827,1.958,2.089,2.22,2.351,2.482,2.613,2.744,2.875,3.006,3.137,3.268,3.399
],
"AQP": [
0.867,0.946,1.025,1.104,1.183,1.262,1.341,1.42,1.499,1.578,1.657,1.736,1.815,1.894,1.973,2.052
],
"AQX": [
1.706,1.862,2.018,2.174,2.33,2.486,2.642,2.798,2.954,3.11,3.266,3.422,3.578,3.734,3.89,4.046
],
"CFP": [
2.459,2.683,2.907,3.131,3.355,3.579,3.803,4.027,4.251,4.475,4.699,4.923,5.147,5.371,5.595,5.819
],
"CFX": [
2.121,2.314,2.507,2.7,2.893,3.086,3.279,3.472,3.665,3.858,4.051,4.244,4.437,4.63,4.823,5.016
],
"EQP": [
3.732,4.072,4.412,4.752,5.092,5.432,5.772,6.112,6.452,6.792,7.132,7.472,7.812,8.152,8.492,8.832
],
"RL": [
7.011,7.649,8.287,8.925,9.563,10.201,10.839,11.477,12.115,12.753,13.391,14.029,14.667,15.305,15.943,16.581
],
"RZP": [
15.271,16.66,18.049,19.438,20.827,22.216,23.605,24.994,26.383,27.772,29.161,30.55,31.939,33.328,34.717,36.106
],
"TJ0": [
5,5.83,6.67,7.5,8.33,9.17,10
],
"TJ1": [
1.4,1.63,1.87,2.1,2.33,2.57,2.8
],
"TJ2": [
0.50,0.58,0.67,0.75,0.83,0.92,1
]
},
"buff": {
"TA1": [
27,50,80,120,180,270,300
],
"TA2": [
75,150,240,360,540,810,900
]
}
}

View file

@ -63,7 +63,7 @@ export const skills = [
name: '6影电磁涡流',
type: 'Y6',
check: 6,
fixedMultiplier: 10,
multiplier: 10,
redirect: '追加攻击'
}
]

View file

@ -52,8 +52,8 @@ export const skills = [
{
name: '6影小猪空中落地爆炸',
type: 'Y6',
check: ({ avatar }) => avatar.rank >= 6,
fixedMultiplier: 3,
check: 6,
multiplier: 3,
props: {
穿透值: 0,
穿透率: 0

View file

@ -0,0 +1,13 @@
/** @type {import('../BuffManager.ts').BuffManager['buffs']} */
export const buffs = [
{
type: '暴击伤害',
value: [0.45, 0.5175, 0.585, 0.6525, 0.72]
},
{
type: '无视防御',
value: [0.25, 0.2875, 0.325, 0.3625, 0.4],
element: 'Ice',
range: ['EQ', 'RL', 'RZ'] // 仅持续3s认为只作用于技能自身
}
]