UOEP

泛用型环境自适应干员强度评价体系设计文档

《明日方舟》是一款魔物主题的策略手游。在游戏中,玩家将管理一艘满载“魔物干员”的方舟,为调查来源神秘的矿石灾难而踏上旅途。在这个宽广而危机四伏的世界中,你或许会看到废土中的城市废墟,或许会看到仿若幻境的亚人国度,或许会遭遇无法解读的神秘,或许参与无比残酷的战争。在有关幻想与异种生命的世界中,体验史诗与想象,情感与牵绊!——鹰角网络

The Problem

当游戏中实装一个新干员时,玩家希望了解该干员的能力强度,以决定是否投资获取该干员。 游戏中使用稀有度表示干员的强度,然而,随着游戏运营时间的推移,干员数量也不断增长,同一稀有度的干员越来越多,并产生了一定幅度的强度膨胀,不再能简单使用稀有度来评价数百位干员的强度。面对玩家的困惑,本文提出一个干员强度评价体系,希望能够更有效地评价每位干员。

前人已经提出了多种强度评价方法,并利用这些方法产出了许多有价值的测评。然而,现有方法存在一些问题:

The Solution

本文提出的方案——泛用型环境自适应干员强度评价体系(以下简称UOEP)旨在解决上述问题,具有以下特性:

UOEP是一个可广泛用于明日方舟干员、随着游戏更新不断发展、涵盖各种环境和干员各项能力、一键自动计算干员强度的评价体系。

然而,目前的UOEP也存在一定的局限性:

干员能力评价指标

如上文所述,UOEP评价干员的各项能力,包括输出、增伤、承伤、保护、治疗、元素、回费、控制,其主要评价指标分别为:

UOEP使用Excel计算干员的伤害数据。在了解计算方法前,我们先学习一些基础知识,包括帧对齐、伤害类型、伤害乘区、友方增益。

伤害相关基础知识

帧对齐

明日方舟是一个每秒30帧的游戏,游戏中的任何操作均需要在对应的帧上完成。举例来说,史尔特尔的理论攻击间隔为1.25秒,但实际在游戏中并非如此。攻击间隔秒数1.25对应的帧数1.25*30=37.5并不是一个整数,由于操作被限制在30帧上,其必须被舍入为整数。游戏中采用的舍入方法为四舍五入,采用此规则,37.5将取整为38,因此史尔特尔的实际攻击间隔约为38/30≈1.2667秒,此操作被称为帧对齐。需要注意的是,明日方舟的部分代码存在会损失精度的浮点数运算,游戏过程中帧数会产生一定波动,与计算相差几帧,这一差距可能导致干员在技能期间的攻击次数多一次或少一次,实际伤害将与计算结果出现偏差。

帧对齐的计算方法如下所示,ROUND(value, 0)函数表示将value四舍五入取整:

ROUND(1.25*30,0)/30

伤害类型

不考虑治疗的情况下,当前版本游戏中我方伤害类型有物理、法术、元素、真实,敌方伤害类型有物理、法术、真实。每种伤害的结算方式不同,基本公式如下,其中MAX()函数表示取两数中更大的值:

物理和法术伤害需要结算敌方单位的双抗,且均有最低5%的保底伤害,元素伤害需要结算敌方单位的元素抗性,且没有保底伤害,真实伤害能够无视敌方的抗性。

伤害乘区

在游戏中,伤害的结算公式相比上述基本公式更加复杂,因为干员拥有提升攻击力、削弱敌方双抗等能力。经过补充的计算公式如下,其中MEDIAN(value, low, high)函数表示将value限制在最小值low和最大值high之间:

公式中存在一系列伤害乘区,其含义和相关例子在下表列出。

乘区 含义 举例 举例干员能力描述
A 攻击力直接加算 乌尔比安二天赋血脉的哺养 每次击倒一名敌人时攻击力提高30
B 攻击力直接乘算 Mon3tr一天赋自我修复 重构体周围友方单位的攻击力+15%
C 攻击力最终加算 浊心斯卡蒂二技能同葬无光之愿 获得相当于浊心斯卡蒂60%攻击力的鼓舞
D 攻击力最终乘算 娜仁图亚一技能旋刃 造成相当于攻击力190%的物理伤害
E 伤害加算 逻各斯二天赋剜魂具辞 使目标在5秒内受到的法术伤害提高150点
F 伤害最终乘算 塞雷娅三技能钙质化 附近所有敌军受到的法术伤害+55%
G 元素损伤最终乘算 塑心二天赋精神逆构 使攻击范围内敌人受到的凋亡损伤提高33%
X 敌方双抗加算 假日威龙陈三技能“假日风暴” 地面敌人经过时防御力-220
Y 敌方双抗乘算 缄默德克萨斯二技能阵雨连绵 使命中目标在10秒内法术抗性-30%
P 敌方双抗数值无视 史尔特尔一天赋熔火 无视攻击目标26法术抗性
Q 敌方双抗比例无视 提丰一天赋锐如兽牙 连续攻击时最高无视防御力的60%

友方增益

在上述多个伤害乘区中,并非所有加成效果都来自干员自身,而是来自其他友方单位。如Mon3tr一天赋自我修复提供的效果为重构体周围友方单位的攻击力+15%,可对多名友方干员生效,则这些友方干员的伤害公式中的攻击力直接乘算乘区均会出现Mon3tr提供的增益。

此外,并非所有加成效果均可直接叠加,部分增益效果具有同类属性取最高的性质,如浊心斯卡蒂鼓舞,当多名干员同时提供鼓舞时,只有一名干员的鼓舞增益会生效。目前具备该性质的增益效果包括:

伤害计算的复杂性

在基础知识中,我们已经了解伤害公式中存在的乘区,以及友方增益效果。应用已学习的知识,考虑娜仁图亚携带一技能旋刃造成相当于攻击力190%的物理伤害,由于其一天赋“我见,我得”累计可偷取敌人250点攻击力和200点防御力,且攻击间隔为1秒,理想情况下其DPS公式为:

MAX(
    (((攻击力)+250)*1.9)*0.05,
    (((攻击力)+250)*1.9)-MAX(((敌方防御力-200)),0)
)/1

为了计算吃拐率,UOEP需要将所有可能的友方增益都加入伤害公式中,使公式的复杂度迅速提高。加入所有增益的公式如下所示。注意到其中娜仁图亚偷取了敌方200点防御力,由于偷取具有同类属性取最高的性质,因此友方附加的敌方防御力加算_偷取增益效果需要和娜仁图亚自身提供的200MAX()运算。此外,友方可能附加攻击速度加成,使得娜仁图亚的攻击间隔小于1秒并变为非整数帧数,此时需要进行帧对齐。

MAX(
    (((攻击力+攻击力直接加算)*(1+攻击力直接乘算+攻击力直接乘算_狙击干员+MAX(攻击力直接乘算_精力充沛))+250+攻击力最终加算+MAX(攻击力最终加算_鼓舞))*1.9+伤害加算)*0.05,
    (((攻击力+攻击力直接加算)*(1+攻击力直接乘算+攻击力直接乘算_狙击干员+MAX(攻击力直接乘算_精力充沛))+250+攻击力最终加算+MAX(攻击力最终加算_鼓舞))*1.9+伤害加算)-MAX(((敌方防御力-(敌方防御力加算+MAX(敌方防御力加算_偷取,200)))*敌方防御力乘算),0)
)*(伤害最终乘算*MAX(伤害最终乘算_脆弱)*MAX(伤害最终乘算_物理脆弱))/(ROUND(1/((100+攻击速度直接加算+攻击速度直接加算_狙击干员+攻击速度直接加算_高台干员)/100)*30,0)/30)

加入增益后,公式的长度膨胀了4倍多,注意到这只是最简单的伤害公式,大多数干员的公式都比它复杂。这里我们至少遇到两个问题:

UOEP 公式语言

为了应对上述问题,本文提出了UOEP公式语言(UOEP Formula Language, UOEP-FL)。UOEP-FL是一个领域专用语言,是Excel公式语言的严格子集。UOEP-FL定义了用于编写伤害公式的基本语法块,编译器将会读取用户使用基本语法块编写的公式,并将所有增益注入公式中,输出带增益的公式。用户只需维护不含任何友方增益效果的公式,无需维护编译生成的增益公式,有效提高了公式的可维护性。换句话说,在上一节中,由第一个公式转换到第二个公式的过程将由机器自动完成,用户只需要编写第一个公式,而无需操心第二个。

以下是一个使用UOEP-FL编写的伤害公式实例,该公式计算逻各斯携带Δ模组时一技能殁亡的周期DPS:

=(
    N("法术伤害")+
    (
        (((BaseAttackRE03D)*(1+1))+150)*(MEDIAN(100-((EnemyResistanceMajor-10)),5,100)/100)+
        0.6*(1/(EnemyCountMinor+1))*(((BaseAttackRE03D)*(1+1))*0.6+150)*(MEDIAN(100-((EnemyResistanceMajor-10)),5,100)/100)
    )/(ROUND(1.6*30,0)/30)+
    N("元素伤害")+
    (
        (800)*(MEDIAN(100-EnemyElementalResistanceMajor,0,100)/100)*15+
        0.6*(1/(EnemyCountMinor+1))*(((BaseAttackRE03D)*(1+1))*0.6)*(MEDIAN(100-EnemyElementalResistanceMajor,0,100)/100)*ROUND(15/(ROUND(1.6*30,0)/30)+0.5,0)
    )/(
        N("凋亡损伤爆发期间时间")+
        15+
        N("凋亡损伤累积至爆发所需时间")+
        ROUNDUP(EnemyMaxElementMajor/(
            (((N("@InjuryDark")+BaseAttackRE03D)*(1+1))+150)*(MEDIAN(100-((EnemyResistanceMajor-10)),5,100)/100)*0.08*(MEDIAN(100-EnemyInjuryResistanceMajor,0,100)/100)+
            0.6*(1/(EnemyCountMinor+1))*(((N("@InjuryDark")+BaseAttackRE03D)*(1+1))*0.6+150)*(MEDIAN(100-((EnemyResistanceMajor-10)),5,100)/100)*0.08*(MEDIAN(100-EnemyInjuryResistanceMajor,0,100)/100)
        ),0)*(ROUND(1.6*30,0)/30)
    )
)

编译器生成的增益公式如下:

=IF(OR(ISNUMBER(SEARCH("RE03",BuffSourceIds))),0,(
    N("法术伤害")+
    (
        (((BaseAttackRE03D+BuffDamageAttackFirstValue)*(1+1+(N("@MonoEnergizedAttack")+MAX(BuffDamageMonoEnergizedAttackFirstRatio))+BuffDamageAttackFirstRatio+BuffDamageAttackFirstRatioCaster)+(N("@MonoEncouragedAttack")+MAX(BuffDamageMonoEncouragedAttackFinalValue))+BuffDamageAttackFinalValue)+150+BuffDamageMagicalGainValue)*(MEDIAN(100-((EnemyResistanceMajor-(10+(N("@MonoEnemyFrozenResistance")+MAX(BuffDamageMonoEnemyFrozenResistanceLossValue))+BuffDamageEnemyResistanceLossValue))*BuffDamageEnemyResistanceLossFinalRatio),5,100)/100)*(1*(N("@MonoEnemyVulnerable")+MAX(BuffDamageMonoEnemyVulnerableFinalRatio))*(N("@MonoEnemyVulnerableMagical")+MAX(BuffDamageMonoEnemyVulnerableMagicalFinalRatio))*BuffDamageMagicalFinalRatio)+
        0.6*(1/(EnemyCountMinor+1))*(((BaseAttackRE03D+BuffDamageAttackFirstValue)*(1+1+(N("@MonoEnergizedAttack")+MAX(BuffDamageMonoEnergizedAttackFirstRatio))+BuffDamageAttackFirstRatio+BuffDamageAttackFirstRatioCaster)+(N("@MonoEncouragedAttack")+MAX(BuffDamageMonoEncouragedAttackFinalValue))+BuffDamageAttackFinalValue)*0.6+150+BuffDamageMagicalGainValue)*(MEDIAN(100-((EnemyResistanceMajor-(10+(N("@MonoEnemyFrozenResistance")+MAX(BuffDamageMonoEnemyFrozenResistanceLossValue))+BuffDamageEnemyResistanceLossValue))*BuffDamageEnemyResistanceLossFinalRatio),5,100)/100)*(1*(N("@MonoEnemyVulnerable")+MAX(BuffDamageMonoEnemyVulnerableFinalRatio))*(N("@MonoEnemyVulnerableMagical")+MAX(BuffDamageMonoEnemyVulnerableMagicalFinalRatio))*BuffDamageMagicalFinalRatio)
    )/(ROUND(1.6/((100+BuffDamageAttackSpeedFirstValue+BuffDamageAttackSpeedFirstValueRanged)/100)*30,0)/30)+
    N("元素伤害")+
    (
        (800)*(MEDIAN(100-EnemyElementalResistanceMajor,0,100)/100)*(1*(N("@MonoEnemyVulnerableElemental")+MAX(BuffDamageMonoEnemyVulnerableElementalFinalRatio,BuffDamageMonoEnemyVulnerableElementalFinalRatioDark))*BuffDamageElementalFinalRatio)*15+
        0.6*(1/(EnemyCountMinor+1))*(((BaseAttackRE03D+BuffDamageAttackFirstValue)*(1+1+(N("@MonoEnergizedAttack")+MAX(BuffDamageMonoEnergizedAttackFirstRatio))+BuffDamageAttackFirstRatio+BuffDamageAttackFirstRatioCaster)+(N("@MonoEncouragedAttack")+MAX(BuffDamageMonoEncouragedAttackFinalValue))+BuffDamageAttackFinalValue)*0.6+BuffDamageElementalGainValue)*(MEDIAN(100-EnemyElementalResistanceMajor,0,100)/100)*(1*(N("@MonoEnemyVulnerableElemental")+MAX(BuffDamageMonoEnemyVulnerableElementalFinalRatio,BuffDamageMonoEnemyVulnerableElementalFinalRatioDark))*BuffDamageElementalFinalRatio)*ROUND(15/(ROUND(1.6/((100+BuffDamageAttackSpeedFirstValue+BuffDamageAttackSpeedFirstValueRanged)/100)*30,0)/30)+0.5,0)
    )/(
        N("凋亡损伤爆发期间时间")+
        15+
        N("凋亡损伤累积至爆发所需时间")+
        ROUNDUP(EnemyMaxElementMajor/(
            (((N("@InjuryDark")+BaseAttackRE03D+BuffDamageAttackFirstValue)*(1+1+(N("@MonoEnergizedAttack")+MAX(BuffDamageMonoEnergizedAttackFirstRatio))+BuffDamageAttackFirstRatio+BuffDamageAttackFirstRatioCaster)+(N("@MonoEncouragedAttack")+MAX(BuffDamageMonoEncouragedAttackFinalValue))+BuffDamageAttackFinalValue)+150+BuffDamageMagicalGainValue)*(MEDIAN(100-((EnemyResistanceMajor-(10+(N("@MonoEnemyFrozenResistance")+MAX(BuffDamageMonoEnemyFrozenResistanceLossValue))+BuffDamageEnemyResistanceLossValue))*BuffDamageEnemyResistanceLossFinalRatio),5,100)/100)*(1*(N("@MonoEnemyVulnerable")+MAX(BuffDamageMonoEnemyVulnerableFinalRatio))*(N("@MonoEnemyVulnerableMagical")+MAX(BuffDamageMonoEnemyVulnerableMagicalFinalRatio))*BuffDamageMagicalFinalRatio)*0.08*(MEDIAN(100-EnemyInjuryResistanceMajor,0,100)/100)*(1*BuffDamageInjuryFinalRatio*BuffDamageInjuryDarkFinalRatio)+
            0.6*(1/(EnemyCountMinor+1))*(((N("@InjuryDark")+BaseAttackRE03D+BuffDamageAttackFirstValue)*(1+1+(N("@MonoEnergizedAttack")+MAX(BuffDamageMonoEnergizedAttackFirstRatio))+BuffDamageAttackFirstRatio+BuffDamageAttackFirstRatioCaster)+(N("@MonoEncouragedAttack")+MAX(BuffDamageMonoEncouragedAttackFinalValue))+BuffDamageAttackFinalValue)*0.6+150+BuffDamageMagicalGainValue)*(MEDIAN(100-((EnemyResistanceMajor-(10+(N("@MonoEnemyFrozenResistance")+MAX(BuffDamageMonoEnemyFrozenResistanceLossValue))+BuffDamageEnemyResistanceLossValue))*BuffDamageEnemyResistanceLossFinalRatio),5,100)/100)*(1*(N("@MonoEnemyVulnerable")+MAX(BuffDamageMonoEnemyVulnerableFinalRatio))*(N("@MonoEnemyVulnerableMagical")+MAX(BuffDamageMonoEnemyVulnerableMagicalFinalRatio))*BuffDamageMagicalFinalRatio)*0.08*(MEDIAN(100-EnemyInjuryResistanceMajor,0,100)/100)*(1*BuffDamageInjuryFinalRatio*BuffDamageInjuryDarkFinalRatio)
        ),0)*(ROUND(1.6/((100+BuffDamageAttackSpeedFirstValue+BuffDamageAttackSpeedFirstValueRanged)/100)*30,0)/30)
    )
))

下面介绍UOEP-FL的基本语法块。

注解

N("@...")
(N("@...")+...)

注解是公式中的重要部分,可以告知编译器该部分的值属于哪个增益。例如,在上一节中,娜仁图亚一天赋“我见,我得”累计可偷取敌人200点防御力,由于偷取同类属性取最高,且友方增益效果也可以偷取,我们需要告诉编译器200偷取得到的,以便编译器注入友方增益时,对其取MAX():通过注解可以编写(N("@MonoEnemyStolenDefense")+200),编译器会将其转换为MAX(200,BuffDamageMonoEnemyStolenDefenseLossValue

目前支持的注解及其含义如下。

同类属性取最高相关注解

注解 含义
@MonoEncouragedAttack 伤害-鼓舞-攻击力数值提升(最终加算)
@MonoEnergizedAttack 伤害-精力充沛-攻击力比例提升(直接乘算)
@MonoEnemyStolenDefense 伤害-偷取-敌方防御力数值降低(最终加算)
@MonoEnemyFrozenResistance 伤害-冻结-敌方法术抗性降低(直接加算)
@MonoEnemyVulnerable 伤害-脆弱-敌方受到的物理法术真实伤害比例提升(最终乘算)
@MonoEnemyVulnerablePhysical 伤害-物理脆弱-敌方受到的物理伤害比例提升(最终乘算)
@MonoEnemyVulnerableMagical 伤害-法术脆弱-敌方受到的法术伤害比例提升(最终乘算)
@MonoEnemyVulnerableElemental 伤害-元素脆弱-敌方受到的元素伤害比例提升(最终乘算)
@MonoSkillPointAutomatic 伤害-技力光环-技力自然回复速度提升(直接加算)
@MonoEncouragedHealth 保护-鼓舞-生命上限数值提升(最终加算)
@MonoEncouragedDefense 保护-鼓舞-防御力数值提升(最终加算)
@MonoShelter 保护-庇护-受到的物理和法术伤害比例降低(最终乘算)
@MonoEnemyStolenAttack 保护-偷取-敌方攻击力数值降低(最终加算)
@MonoEnemyWeakenedAttack 保护-虚弱-敌方攻击力比例降低(最终乘算)
@MonoEnemyStolenAttackSpeed 保护-偷取-敌方攻击速度数值降低(最终加算)
@MonoEnemyColdAttackSpeed 保护-寒冷-敌方攻击速度数值降低(直接加算)

伤害相关注解

注解 含义
@True 真实伤害
@InjurySanity 神经损伤
@InjuryFire 灼燃损伤
@InjuryDark 凋亡损伤
@AttackSpeed 攻击速度
@SkillAutomatic 自然回复技能回转时长
@SkillOffensive 攻击回复技能回转时长
@SkillOffensiveAttackCount 攻击回复技能回转期间普通攻击次数

保护相关注解

注解 含义
@EnemyAttackSpeedLoss 敌方攻击速度数值降低(直接加算)
@DamageLoss 受到的伤害比例降低(最终乘算)
@Evasion 闪避和减命中(最终乘算)
@CrystalBarrier 琉璃璧效果(
@ProjectileRemoval 弹道消除效果(
@BlockCount 强制修改该单位的阻挡数(玛恩纳
@PositionMelee 强制将该单位设为地面单位(Mon3tr
@PositionRanged 强制将该单位设为高台单位

输出

伤害

伤害基本语法块包括物理、法术、元素、真实伤害,以及元素损伤。可以在各个伤害乘区(即代码中的...)处加入具体数值,其中使用的变量名及其含义如下。

伤害基本语法块及相关变量:

变量名 含义
BaseAttackGG01 ID为GG01的干员(推进之王)的基础攻击力
BaseDefenseMajor 主目标的防御力
BaseResistanceMajor 主目标的法术抗性
EnemyElementalResistanceMajor 主目标的元素抗性
EnemyInjuryResistanceMajor 主目标的损伤抵抗

攻击速度

结合帧对齐的知识,我们可以得出攻击间隔的基本语法块,其中理论攻击间隔可以进行加算和乘算,攻击速度可以在默认值100的基础上进行增减。然而,在复杂情况下,攻击间隔是可变的,例如伊内丝二技能暗夜无明忍冬三技能隐狐之艺期间的攻击速度不断改变,这种情况下不能再使用定长的攻击间隔语法块,需要改用手动攻击速度语法块,编译器也会正确注入相关的增益。

技能回转

在计算技能的周期DPS时,我们需要考虑技能的回转时长。由于技力光环增益的存在,技能的回转可以被缩短,需要使用注解让编译器注入对应的友方技力增益。其中,在没有增益时,自然回复技能的回转时长等于消耗的技力数,攻击回复技能的时长等于消耗的技力数×攻击间隔。计算强力击类攻回技能的周期DPS时,需要提供技能回转期间的普攻次数,该次数会受到攻击间隔和友方增益的影响,因此需要为编译器提供攻击间隔(此处使用0*攻击间隔在告知编译器的情况下不影响公式计算结果),编译器会将包含攻击间隔的增益片段注入公式。

复数干员

在部分情况下,我们需要在一个公式中同时计算多名友方单位的输出,召唤类干员如死芒的所有技能均包含本体和召唤物的输出,元素干员组合如塑心+妮芙的输出由两名干员同时在场组成。UOEP-FL支持公式中出现任意数量的干员,且编译器会自动分析公式中的片段属于哪位干员提供的伤害,并注入对应类别的增益,如塑心+妮芙组合中塑心的部分会注入辅助职业的增益,妮芙的部分会注入术师职业的增益。

然而,并非在所有情况下都能如此顺利。部分公式的基本语法块默认写法并未指出该部分属于哪位干员,这种情况下需要人工在该语法块中指出。例如,对于如下计算死芒普攻DPS的公式,同时包含了本体和召唤物的伤害:

=(
    (
        (((BaseAttackDB01)))*(MEDIAN(100-EnemyResistanceMajor,5,100)/100)
    )/(ROUND(1.6*30,0)/30)+
    (
        (((BaseSummonAttackDB01)*(1+1)))*(MEDIAN(100-EnemyResistanceMajor,5,100)/100)
    )/(ROUND(1.8*30,0)/30)
)

编译器将报错ValueError: Expect a subject in (ROUND(1.6*30,0)/30),提示找不到攻击间隔(ROUND(1.6*30,0)/30)的主人。这时需要用户手动在其末尾用0*BaseAttackDB01告知编译器该攻击间隔的从属单位为死芒本体,如下所示,即可正确通过编译。

=(
    (
        (((BaseAttackDB01)))*(MEDIAN(100-EnemyResistanceMajor,5,100)/100)
    )/(ROUND(1.6*30,0)/30+0*BaseAttackDB01)+
    (
        (((BaseSummonAttackDB01)*(1+1)))*(MEDIAN(100-EnemyResistanceMajor,5,100)/100)
    )/(ROUND(1.8*30,0)/30+0*BaseSummonAttackDB01)
)

承伤

与输出公式计算DPS不同,承伤公式计算的是我方单位受到的DPH。提供一个承伤公式的模板,所有承伤公式均可使用该模板编写。使用的变量名及其含义在下方列出。

=MAX(IFS(
    EnemyDamageType=LiteralPhysical,MAX(
        (EnemyDamagePerHit)*0.05,
        (EnemyDamagePerHit)-((BaseDefenseGG01))
    ),
    EnemyDamageType=LiteralMagical,(EnemyDamagePerHit)*(MEDIAN(100-((BaseResistanceGG01)),5,100)/100),
    EnemyDamageType=LiteralTrue,(EnemyDamagePerHit)
),0)*(N("@ProjectileRemoval")+IF(EnemyRanged,0.8,1))+0*((BaseHealthGG01))+0*(N("@EnemyAttackSpeedLoss")+0)+0*(N("@CrystalBarrier")+200)+0*(N("@BlockCount")+3)+N("@PositionMelee")+N("@PositionRanged")
变量名 含义
EnemyDamageType 敌方伤害类型
EnemyDamagePerHit 敌方每击伤害
EnemyRanged 敌方可远程攻击
BaseDefenseGG01 ID为GG01的干员(推进之王)的基础防御力
BaseResistanceGG01 ID为GG01的干员(推进之王)的基础法术抗性
BaseHealthGG01 ID为GG01的干员(推进之王)的基础生命值
LiteralPhysical 物理伤害字面量
LiteralMagical 法术伤害字面量
LiteralTrue 真实伤害字面量

弹道消除:可以使用@ProjectileRemoval表示敌方远程弹道消除效果,该增益目前由三技能灶里乾坤提供,为可选项。

(N("@ProjectileRemoval")+IF(EnemyRanged,0.8,1))

敌方攻击速度数值降低:可以使用@EnemyAttackSpeedLoss表示减攻速效果,后跟直接加算值,为可选项。

0*(N("@EnemyAttackSpeedLoss")+0)

强制修改阻挡数和位置:可以使用@BlockCount表示阻挡数,@PositionMelee表示修改为地面单位,@PositionRanged表示修改为高台单位,均为可选项。

0*(N("@BlockCount")+3)
N("@PositionMelee")
N("@PositionRanged")

琉璃璧:可以使用@CrystalBarrier表示琉璃璧效果,后跟吸收伤害的最大值,该增益目前由一天赋计出万全提供,为可选项。

0*(N("@CrystalBarrier")+200)

编译器使用方法

需要Python 3.10或以上版本。在Windows环境下,建议使用Windows Terminal,键入以下命令可看到帮助说明。

PS C:\> python3 arknights_formula_helper.py --help
usage: arknights_formula_helper.py [-h] [--from {damage,endurance}] [--to {buff,decay,enemy}]
                                   [--minify {auto,off,max}] [--file] [--dry-run]

Effortlessly tailor your Arknights formulas to various battlefields with all possible buffs

options:
  -h, --help            show this help message and exit
  --from {damage,endurance}
                        formula source type
  --to {buff,decay,enemy}
                        formula target type
  --minify {auto,off,max}
                        whether to minify the generated formula
  --file                read input from `input.txt` and write output to `output.txt`
  --dry-run             do not write the disk
参数 说明
--help 显示帮助
--from damage 输入输出公式(默认值)
--from endurance 输入承伤公式
--to buff 输出增益公式(默认值)
--to decay 输出增益衰减公式,用于输出衰减 承伤衰减
--to enemy 输出增益实战公式,用于输出实战 承伤实战
--minify auto 按需压缩公式,仅在公式长度超过阈值时压缩
--minify off 不压缩公式
--minify max 最大程度压缩公式
--file 从文件读写,而非从控制台读写
--dry-run 空跑,不将结果写入磁盘

交互式使用样例如下,输入公式后,按Ctrl + Z结束输入,编译器将输出增益后的公式。不输入公式的情况下,按Ctrl + Z可退出,也可输入:quit退出。输入:clear可以清屏。

PS C:\> python3 arknights_formula_helper.py
Formula >
============================================================
=(
    (
        (((BaseAttackDB01)))*(MEDIAN(100-EnemyResistanceMajor,5,100)/100)
    )/(ROUND(1.6*30,0)/30+0*BaseAttackDB01)+
    (
        (((BaseSummonAttackDB01)*(1+1)))*(MEDIAN(100-EnemyResistanceMajor,5,100)/100)
    )/(ROUND(1.8*30,0)/30+0*BaseSummonAttackDB01)
)
^Z
------------------------------------------------------------
=IF(OR(BuffDamageApplyToSingleAllyOnly,BuffDamageApplyToNonSummonAllyOnly,ISNUMBER(SEARCH("DB01",BuffSourceIds))),0,(
    (
        (((BaseAttackDB01+BuffDamageAttackFirstValue)*(1+(N("@MonoEnergizedAttack")+MAX(BuffDamageMonoEnergizedAttackFirstRatio))+BuffDamageAttackFirstRatio+BuffDamageAttackFirstRatioCaster)+(N("@MonoEncouragedAttack")+MAX(BuffDamageMonoEncouragedAttackFinalValue))+BuffDamageAttackFinalValue)+BuffDamageMagicalGainValue)*(MEDIAN(100-MAX(((EnemyResistanceMajor-(0+(N("@MonoEnemyFrozenResistance")+MAX(BuffDamageMonoEnemyFrozenResistanceLossValue))+BuffDamageEnemyResistanceLossValue))*BuffDamageEnemyResistanceLossFinalRatio),0),5,100)/100)*(1*(N("@MonoEnemyVulnerable")+MAX(BuffDamageMonoEnemyVulnerableFinalRatio))*(N("@MonoEnemyVulnerableMagical")+MAX(BuffDamageMonoEnemyVulnerableMagicalFinalRatio))*BuffDamageMagicalFinalRatio)
    )/(ROUND(1.6/((100+BuffDamageAttackSpeedFirstValue+BuffDamageAttackSpeedFirstValueRanged)/100)*30,0)/30+0*BaseAttackDB01)+
    (
        (((BaseSummonAttackDB01+BuffDamageAttackFirstValue)*(1+1+(N("@MonoEnergizedAttack")+MAX(BuffDamageMonoEnergizedAttackFirstRatio,BuffDamageMonoEnergizedAttackFirstRatioMelee))+BuffDamageAttackFirstRatio+BuffDamageAttackFirstRatioMelee)+(N("@MonoEncouragedAttack")+MAX(BuffDamageMonoEncouragedAttackFinalValue))+BuffDamageAttackFinalValue)+BuffDamageMagicalGainValue)*(MEDIAN(100-MAX(((EnemyResistanceMajor-(0+(N("@MonoEnemyFrozenResistance")+MAX(BuffDamageMonoEnemyFrozenResistanceLossValue))+BuffDamageEnemyResistanceLossValue))*BuffDamageEnemyResistanceLossFinalRatio),0),5,100)/100)*(1*(N("@MonoEnemyVulnerable")+MAX(BuffDamageMonoEnemyVulnerableFinalRatio))*(N("@MonoEnemyVulnerableMagical")+MAX(BuffDamageMonoEnemyVulnerableMagicalFinalRatio))*BuffDamageMagicalFinalRatio)
    )/(ROUND(1.8/((100+BuffDamageAttackSpeedFirstValue+BuffDamageAttackSpeedFirstValueMelee)/100)*30,0)/30+0*BaseSummonAttackDB01)
))
============================================================

数据使用方法

查看数据使用方法

受到时间和工作量限制,文档必有许多不详之处,将在未来版本中改进,希望您能谅解。