NP获取
NP获取机制、99%NP进位以及NP值显示的说明
NP获取机制
影响NP值 的方式有四种:直接增加、直接减少、攻击时的主动获取NP和被攻击时的被动获取NP。涉及到计算的是后两种。
计算方式如下:
主动NP获取 |
---|
1.从者卡牌基础NP获取率 |
× |
2.(色卡倍率 × 3.位置加成 × 4.色卡性能BUFF + 5.首位加成) |
× |
6.敌方补正 |
× |
7.NP获得量BUFF |
× |
8.暴击补正 |
× |
9.OVER KILL补正 |
被动NP获取 |
---|
10.从者被攻击基础NP值 |
× |
11.敌方补正 |
× |
12.NP获得量BUFF |
× |
13.受击NP获得量BUFF |
× |
9.OVER KILL补正 |
计算结果说明
在游戏内部,从者的 NP 值是 int 存储的, 10000 表示 100% NP。
显示时,直接向下取整:
int display = (int)(np / 100.0)
例如:
数值 | 显示 |
---|---|
9999 | 99% |
100 | 1% |
99 | 0% |
战斗过程中,每个单次攻击(例如一张蓝卡攻击)都会按照上面公式计算1次。
计算过程中,数值是用 float 存储的,得到计算结果后会直接向下取整,转换为 int。
每个单次攻击可能会分为若干 hit(即攻击动作时产生若干伤害数字),每次 hit 都会给调用 addNp() 函数给双方加上一个上述结果的 int 值。即单次攻击时,最终 NP 获取是 (int)上述计算结果 * hit数。
具体逻辑可以参考以下伪代码:
// 执行上述计算(但排除最后一步 overkill 补正),结果转换为 int
int attackNp = (int)actor.getAttackNp();
int defenseNp = (int)target.getDefenseNp();
// 举例,此处蓝卡有 3hit,这里是每个 hit 造成的伤害。遍历每个hit值。
int[] hits = {3238, 2329, 8827};
for(int i = 0; i < hits.count; i++) {
// 如果这次hit会导致被攻击者血量到达0,则从该 hit 开始都算是 overkill
bool isOverkill = target.resultDamage(hits[i]);
// 即最后一步 overkill 补正,注意这里结果仍然是 int 类型
if (isOverkill) {
attackNp *= 1.5;
defenseNp * 1.5;
}
actor.addNp(attackNp); // 攻击者NP增加
target.addNp(defenseNp); //被攻击者NP增加
}
举例:
贞德蓝卡 hit 数为 2,
贞德身上有 2 个 buff:蓝卡性能提升 20%,NP获得量提升 30%。
敌人身上有 1 个 buff:蓝卡耐性提升 10%。
三张蓝卡连携,第 3 张卡产生了暴击,且暴击的第二 hit 是 overkill。
则第 3 张卡 NP 获取计算:
贞德蓝卡的基础NP获取率×(蓝卡色卡倍率 ×第3位位置加成 ×色卡性能BUFF +首位加成)×敌方补正×NP获得量BUFF×暴击补正
76×[3.0 × 2.0 × (1.0 + 0.2 - 0.1) + 1.0 ] × 1.0 × (1 + 0.3) ×2.0 =1501.76
即每 hit 都会获得 1501 NP(15.01%),
蓝卡 2 hits,且第二 hit 达成了 overkill,则该蓝卡总 NP 获取为 1501 + 1501 × 1.5 = 3752(37.52%),
显示出来就是 37% NP。
关于 99% NP 进位到 100% 的说明
战斗时对于从者的 NP 的变动(例如攻击时每hit增加NP、使用技能减少NP),
都会调用到 addNp(int npAdd) 这个函数,
而这个函数内有个特殊判断(C#代码):
if (0 < npAdd && (float)this.lineMaxNp * 0.99f <= (float)this.np && this.np < this.lineMaxNp) { this.np = this.lineMaxNp; }
从代码本意上看,盐川想要的效果是:
如果 np 增加后,其值处于 [9900,9999](即99%NP范围内),则自动向上进位至 10000(100%)。但是中间这句判断是有问题的:
(float)this.lineMaxNp * 0.99f <= (float)this.np
C# 运算时,float 会自动转为 double 进行对比,左侧数字由于浮点数精度问题,会变为 9900.00009536743,如果右侧是 9900.0 ,则会对比失败,这就会导致 99% NP 的状态。
修复问题的办法是把 C# 代码改为整形判断:
this.lineMaxNp * 99 / 100 <= this.np
对于 Unity 程序,Android 是用 mono 虚拟机跑的 C# dll,而 iOS 则是用 il2cpp 编译为原生的 C++ 代码。编译后 C++ 代码反而是正确的:
(!(((float)((float)((float)(((float)((float)lineMaxNp)))*(float)(0.99f)))) <= ((float)(((float)((float)np))))))
所以,实现的结果是:只有iOS在NP增加为99%时进位100%,安卓在正好为99.00%时不会进位,仍显示99%。
日服1.40.0(2018.6.13)将float类型全部改为double,修复了这一问题,iOS和Android表现一致,NP增加时都会从99%进位100%。
if (0 < npAdd && (double)this.lineMaxNp * 0.99 <= (double)this.np && this.np < this.lineMaxNp) {
this.np = this.lineMaxNp;
}
关于 NP 显示的问题
在显示时,NP 处理逻辑如下(C#)
public static int npGauge(int now) {
int lineCount = 3;
int max = 3 * 10000;
return (int)Math.Floor((float)now / (float)max * 100f * (float)lineCount);
}
这段代码在 C# 下运行是没有问题的,即在 Android 平台上,NP显示是正确的。
但是,当编译为 iOS 项目时,Unity 会把 C# 转换为 C++ 代码:
int npGauge(int now) { float npGauge = now / 30000.f;
npGauge *= 100.0f;
npGauge *= 3; return (int)floor(npGauge);
}
这就会存在精度丢失的问题,导致某些数值会出现错误,例如 10700 会返回 106.999992。
即在 iOS 上会出现如下显示错误:
实际值 | 显示值 |
---|---|
29% | 28% |
49% | 48% |
58% | 57% |
98% | 97% |
107% | 106% |
116% | 115% |
125% | 124% |
159% | 158% |
177% | 176% |
193% | 192% |
196% | 195% |
211% | 210% |
214% | 213% |
229% | 228% |
232% | 231% |
250% | 249% |
253% | 252% |
修复办法是全程改用 long 计算,先乘,后除,避免丢失精度。
计算公式说明
1.从者卡牌基础NP获取率
每个从者的的每张卡,都有一个基础 NP 值,
例如白贞德A卡0.76%,B卡0.76%,Q卡0.76%,EX卡0.76%,宝具卡0.76%。
对于大部分从者来说,不同卡牌的基础 NP 是相同的。
2.色卡倍率
蓝卡:3.0,红卡:0.0,绿卡:1.0,EX卡:1.0。
宝具卡也按上述颜色取值。
3.位置加成
第1位1.0,第2位1.5,第3位2.0。
如果这张卡是宝具卡、EX卡,则不算位置加成,取值 1.0。
4.色卡性能BUFF
该模块计算方式为 1.0 + 攻击者色卡性能BUFF - 防御者色卡耐性BUFF
如果该模块最终结果小于 0.0,则修改为 0.0。
攻击者色卡性能BUFF包括:
图标 | 效果 |
---|---|
![]() | Quick 指令卡NP获得提升/性能提升 |
![]() | Arts 指令卡NP获得提升/性能提升 |
![]() | Buster 指令卡NP获得提升/性能提升 |
![]() | Quick 指令卡NP获得下降/性能下降 |
![]() | Arts 指令卡NP获得提升/性能下降 |
![]() | Buster 指令卡NP获得下降/性能下降 |
攻击者色卡性能BUFF计算方式为:
float rate = 1.0 + (upBuff1 + upBuff2 + ...) - (downBuff1 + downBuff2 + ...);
if (rate > 5.0) rate = 5.0; // 上限
if (rate < 0.001) rate = 0.001; // 下限
防御者色卡耐性BUFF包括:
图标 | 效果 |
---|---|
![]() | Quick 指令卡耐性提升 |
![]() | Arts 指令卡耐性提升 |
![]() | Buster 指令卡耐性提升 |
![]() | Quick 指令卡耐性下降 |
![]() | Arts 指令卡耐性下降 |
![]() | Buster 指令卡耐性下降 |
防御者色卡耐性BUFF计算方式为:
float rate = 1.0 + (upBuff1 + upBuff2 + ...) - (downBuff1 + downBuff2 + ...);
if (rate > 5.0) rate = 5.0; // 上限
举例:
蓝卡攻击,我方有 Arts卡性能提升50%,Arts卡NP获得下降30% 2个Buff,
对方有 Arts卡耐性下降20% Buff,
则计算结果是 1.0 + (1.0 + 0.5 - 0.3) - (1.0 - 0.2) = 1.4
5.首位加成
如果这次攻击的第一张卡是蓝色,则取值 1.0。否则取值 0.0。
宝具卡不参与该运算(即此处取值 0.0),但可以当做"首蓝"给其他普通卡和EX卡提供加成。
6.敌方补正
敌方从者身上带有的一个值 (downTdRate),通常在 0.8~1.2 之间。
通常来说,Rider、Caster 大于1.0、Assassin、Berserker 小于1.0。
该值仅当进入战斗后才会由服务端下发,其值并不确定。
注意,攻击和被击时的敌方补正是分开的两个数字,但通常数值相等。
7.NP获得量BUFF
该模块计算方式为 1.0 + 攻击者NP获得量提升BUFF - 攻击者NP获得量下降BUFF
float rate = 1.0 + (upBuff1 + upBuff2 + ...) - (downBuff1 + downBuff2 + ...);
if (rate > 5.0) rate = 5.0; // 下限
if (rate < 0.001) rate = 0.001; // 下限
图标 | 效果 |
---|---|
![]() | NP获得量提升 |
![]() | NP获得量下降 |
8.暴击补正
如果该卡暴击判定成功,则此处取值 2.0。
如果该卡没有暴击、或者该卡是宝具卡,则取值 1.0。
9.OVER KILL补正
如果该 hit 是 over kill,则此处取值 1.5,否则取值 1.0。
10.从者被攻击基础NP值
每个从者都有一个固定的被攻击基础NP值,例如贞德为 300。
11.敌方补正
敌方从者身上带有的一个值 (downTdRate),通常在 0.8~1.2 之间。
通常来说,Rider、Caster 大于1.0、Assassin、Berserker 小于1.0。
该值仅当进入战斗后才会由服务端下发,其值并不确定。
注意,攻击和被击时的敌方补正是分开的两个数字,但通常数值相等。
12.NP获得量BUFF
该模块计算方式为 1.0 + 被攻击者NP获得量提升BUFF - 被攻击者NP获得量下降BUFF
float rate = 1.0 + (upBuff1 + upBuff2 + ...) - (downBuff1 + downBuff2 + ...);
if (rate > 5.0) rate = 5.0; // 下限
if (rate < 0.001) rate = 0.001; // 下限
图标 | 效果 |
---|---|
![]() | NP获得量提升 |
![]() | NP获得量下降 |
13.受击NP获得量BUFF
该模块计算方式为 1.0 + 被攻击者受击时NP获得量提升 - 被攻击者受击时NP获得量下降
float rate = 1.0 + (upBuff1 + upBuff2 + ...) - (downBuff1 + downBuff2 + ...);
if (rate > 5.0) rate = 5.0; // 下限
if (rate < 0.001) rate = 0.001; // 下限
图标 | 效果 |
---|---|
![]() | 受到攻击时NP获得量提升 |
![]() | 受到攻击时NP获得量下降 |
例如茶茶的技能黄金律(凶)所带来的效果受到攻击时NP获得量提升20%~50%