ShizuruNotes
ShizuruNotes copied to clipboard
关于6星妮侬UB充电量的疑惑
根据目前静流笔记中的描述,6星妮侬的UB充电量应为[100 + 100 * 击杀的敌方数量],计算妮侬50点的TP上升后,充电量应为无击杀150,单杀300,双杀450等。然而在实测中,通过画面上出现的蓝色数字可以看到实际的充电量为无击杀150,单杀450,双杀750(这些数据中均未包括击杀敌人本应获得的TP,实际上UB双杀可以直接把妮侬的TP充满)。鉴于充电是PCR中比较重要的机制,希望大佬能研究一下此处充电量不一致的原因。
根据攻略视频(https://www.youtube.com/watch?v=bNXm3rN9TIw),攻击力提升随击杀数量提高的数值同样是静流笔记中描述的两倍。另一方面,静流笔记对专武1技能的描述是准确的(实测单杀时蓝色数字为1500,双杀时为3000),所以有可能这个问题跟系数是加还是乘有关系?
Interesting.
The current calculation of 静流笔记 reflected the pretty old version of the client code well.
Maybe there was an update about this algorithm in the GiveValueAdditiveAction class.
And, this UB action is the first skill action that uses DefeatEnemyCount as far as I know.
Well, both Ninon's main skill 1 (and 1+) and Mitsuki's UB use this value, but Ninon's UB+ is the first skill action that uses this value additively (instead of multiplicatively). Ninon's main skill 1+ does act correctly on the current version.
好像确实有问题,等明天上班摸鱼再仔细研究下(懒
翻了半天没找到有什么问题...
而且ninon是目前唯一 action_type = 26 且 action_value_1 = 2 的角色,想找其他角色做验证也没法。
目前能想出来的临时解决办法只能强行在 AdditiveAction 里计算值的时候手动乘个2来迎合游戏里的实际数值。
我会保持这个issue打开,看看有没有其他大佬能够解决。
今天活动SP的bug让我又想起这个老问题,回头看了一下prefab之后,有了一个猜想(其实当时似乎也有过,只不过觉得太不靠谱了就没有提出来):是不是单纯因为这个技能中有两个动作都检查了击杀数量,导致每个击杀被计算了两次?当然有很多技能里都有两个动作检查同一个数值的情况,但可能因为击杀数量是需要“计数”的,所以比较特殊?
无聊看了一下
其实就是他不是击杀数量,而是击杀数量+1
所以其实应该是[100 + 100 * (击杀的敌方数量 + 1)]

ILSpy把一些便于阅读的判断优化掉了 看dnSpy的话可以看到,if的条件是
GiveValueAction.eAdditiveValueType eAdditiveValueType = (GiveValueAction.eAdditiveValueType)base.Value[eValueNumber.VALUE_1];
if (eAdditiveValueType != GiveValueAction.eAdditiveValueType.DEFEAT_NUMBER)
这个eAdditiveValueType.DEFEAT_NUMBER其实就是2,也就ILSpy的case 2
所以当eAdditiveValueType 为2的时候才会走是前面说的[100 + 100 * (击杀的敌方数量 + 1)]的逻辑,也就是说无击杀其实是[100 + 100 * 击杀的敌方数量]

但是这样解释不了实际观察到的双杀蓝字TP量啊。
但是这样解释不了实际观察到的双杀蓝字TP量啊。
你一开始写的不就是 150 450 750吗? 这有什么问题吗
[100 + 100 * (击杀的敌方数量 + 1)]
计算50点TP上升的话,击杀的敌方数量 = 2时,应该是(100 + 100 * (2 + 1)) * 1.5 = 600
等等,从代码上来看这并不是简单的“击杀的敌方数量+1”吧,而是在OnDefeatEnemy这个event上加了一个listener?
因为是委托阿
应该这么理解才对,前面说的确实过于片面
只存在两种:
1)无击杀:[100 + 100 * 击杀的敌方数量]
2)有击杀:[100 + 100 * (击杀的敌方数量 + 1)]
但是他给OnDefeatEnemy这个Action委托类型赋值,意思是说
这个委托每次执行的时候,都会给击杀数+1
但是击杀到底怎么判定呢?那当然是从伤害来的
也就是ExecActionOnStart这个方法定义了这个委托
而SetDamage这个方法把OnDefeatEnemy传给SetDamageImpl这个方法
SetDamageImpl去呼叫这个委托
你就当成这个UB打五个角色那就会出现五次伤害数字
打四个角色就会有四次伤害数字,以次类推
然后每个伤害数字(判断伤害是SetDamage和SetDamageImpl)决定的
会根据伤害决定是否有击杀,那有击杀就是+1
也就是说:
击杀1个就是(SetDamageImpl呼叫次数: 1) * (1次Combine委托(2)呼叫) = 2
击杀2个就是(SetDamageImpl呼叫次数: 2) * (1次Combine委托(2)呼叫) = 4
击杀3个就是(SetDamageImpl呼叫次数: 3) * (1次Combine委托(2)呼叫) = 6
击杀4个就是(SetDamageImpl呼叫次数: 4) * (1次Combine委托(2)呼叫) = 8
击杀5个就是(SetDamageImpl呼叫次数: 5) * (1次Combine委托(2)呼叫) = 10
下面是直接Hook 6.9.0版本客户端的Skill.set_DefeatEnemyCount
单杀
双杀
三杀
四杀
五杀

1)无击杀:[100 + 100 * 击杀的敌方数量] 2)有击杀:[100 + 100 * (击杀的敌方数量 + 1)]
啊这,那你非要把公式写成这样不是很奇怪,说穿了就是一个计数的逻辑而已,计数归计数,乘以100归乘以100,合在一起不就是[100 + 100 * (击杀的敌方数量 * 2)]嘛。
而且你有没有想过“击杀的敌方数量”的初始值是哪里来的,为什么双杀的时候不是直接2→3→4,而是(0→)1→2→3→4?
你结果上观察起来确实等价
但是他逻辑确实不是这样阿
然后第二个问题是这里
coroutineStartProcess会根据DJJKGCFKJNJ的数量Loop
其实意思就是根据双方角色Loop
然后执行ExecActionOnStartAndDetermineInstanceID
+UnitActionController.ExecActionOnStart
+execActionOnStart
+GiveValueAction.ExecActionOnStart
五个角色时ExecActionOnStart一共执行了五次
之后每个角色才再执行SetDamage
初始值是这里给的
所有都是0
但是ExecActionOnStart不会直接增加DefeatEnemyCount对吧,只是设置委托,后面SetDamage才会执行对吧。
归根结底目前看到的代码只有那个匿名的委托呼叫才会直接增加DefeatEnemyCount,那么这个委托到底被呼叫了几次呢。
稍微调试了一下
这个要修要把描述改成
[100 + 100 * 击杀的敌方数量 * 该技能中继承Elements.GiveValueAction类的Action数量]
可能顺便给每一个Action都加上Action Type的标注
主要理由在于6星扇子的UB有五个Action ID分别是:
103001101('Action Type': ATTACK)
103001102('Action Type': GIVE_VALUE_AS_ADDITIVE)
103001103('Action Type': BUFF_DEBUFF)
103001104('Action Type': GIVE_VALUE_AS_ADDITIVE)
103001105('Action Type': CHARGE_ENERGY)
其中103001102和103001105属于Elements.GiveValueAdditiveAction类
而Elements.GiveValueAdditiveAction继承Elements.GiveValueAction。
首先,前面说的Delegate.Combine(a, b)当a = null(即从没被赋值之时),他返回的值就是b而已。
而当游戏在初始化扇子UB的时候,ExecActionOnStart会走两次,分别为了103001102和103001105各执行一次。
并且每一次都会把Skill.ActionParameters的每一个AcitionParameter赋予b
但是由于扇子6星的UB的103001102和103001105各执行了一次ExecActionOnStart,因此每一个Action ID: 103001101~5的Elements.ActionParameter.OnDefeatEnemy会被103001102和103001105分别赋值一次
第一次被103001102给Delegate.Combine(a, b)的结果是b
第二次被103001105给Delegate.Combine(a, b)的结果就将会是b+b
如果我们输出Elements.UnitCtrl.SetDamage的_onDefeat.GetInvocationList().Length参数的时候,我们会得到2
因此当SetDamageImpl呼叫OnDefeatEnemy这个委托的时候,他会呼叫两次。
总的来说OnDefeatEnemy这个委托的呼叫次数在于该技能中有几个Action继承了Elements.GiveValueAction类的数量,这个数量会决定DefeatEnemyCount会被赋值几次
下面是SetDamage的一些输出:
long Elements.UnitCtrl::SetDamage(Elements.DamageData _damageData, bool _byAttack, int _actionId, Elements.ActionParameter+OnDamageHitDelegate _onDamageHit, bool _hasEffect, Elements.Skill _skill, bool _energyAdd, Action _onDefeat, bool _noMotion, float _damageWeight, float _damageWeightSum, System.Func<int, float, int> _upperLimitFunc, float _energyChargeMultiple, System.Collections.Generic.Dictionary<Elements.eStateIconType, System.Collections.Generic.List<Elements.UnitCtrl>> _usedChargeEnergyByReceiveDamage)
- __instance: UNIT_114401(Clone) (Elements.UnitCtrl)
- Parameter 2 '_actionId': 103001101
- Parameter 3 '_onDamageHit': null
- Parameter 7 '_onDefeat Invocation Counts': 2
- Return value: 15140
下面是ExecActionOnStart的一些输出:
0--------------------
virtual void Elements.GiveValueAction::ExecActionOnStart(Elements.Skill _skill, Elements.UnitCtrl _source, Elements.UnitActionController _sourceActionController)
- __instance: Elements.GiveValueAdditiveAction
- '_skill.ActionParameters.Count': 5
- '_skill.SkillId': 1030011
- '_skill.ActionParameters[0]': 103001101
- 'test': True
- '_skill.ActionParameters[1]': 103001102
- 'test': True
- '_skill.ActionParameters[2]': 103001103
- 'test': True
- '_skill.ActionParameters[3]': 103001104
- 'test': True
- '_skill.ActionParameters[4]': 103001105
- 'test': True
1--------------------
virtual void Elements.GiveValueAction::ExecActionOnStart(Elements.Skill _skill, Elements.UnitCtrl _source, Elements.UnitActionController _sourceActionController)
- __instance: Elements.GiveValueAdditiveAction
- '_skill.ActionParameters.Count': 5
- '_skill.SkillId': 1030011
- '_skill.ActionParameters[0]': 103001101
- 'test': True
- '_skill.ActionParameters[1]': 103001102
- 'test': True
- '_skill.ActionParameters[2]': 103001103
- 'test': True
- '_skill.ActionParameters[3]': 103001104
- 'test': True
- '_skill.ActionParameters[4]': 103001105
- 'test': True
2--------------------
virtual void Elements.GiveValueAction::ExecActionOnStart(Elements.Skill _skill, Elements.UnitCtrl _source, Elements.UnitActionController _sourceActionController)
- __instance: Elements.GiveValueMultipleAction
- '_skill.ActionParameters.Count': 4
- '_skill.SkillId': 1030012
- '_skill.ActionParameters[0]': 103001201
- 'test': True
- '_skill.ActionParameters[1]': 103001202
- 'test': True
- '_skill.ActionParameters[2]': 103001203
- 'test': True
- '_skill.ActionParameters[3]': 103001204
- 'test': True
这也说明为什么旋风击和旋风击+并不200 因为旋风击和旋风击+的四个Action ID中只有第三个是加法赋值