ShizuruNotes icon indicating copy to clipboard operation
ShizuruNotes copied to clipboard

关于6星妮侬UB充电量的疑惑

Open bbbbbbbbba opened this issue 5 years ago • 21 comments

根据目前静流笔记中的描述,6星妮侬的UB充电量应为[100 + 100 * 击杀的敌方数量],计算妮侬50点的TP上升后,充电量应为无击杀150,单杀300,双杀450等。然而在实测中,通过画面上出现的蓝色数字可以看到实际的充电量为无击杀150,单杀450,双杀750(这些数据中均未包括击杀敌人本应获得的TP,实际上UB双杀可以直接把妮侬的TP充满)。鉴于充电是PCR中比较重要的机制,希望大佬能研究一下此处充电量不一致的原因。

bbbbbbbbba avatar Oct 07 '20 10:10 bbbbbbbbba

根据攻略视频(https://www.youtube.com/watch?v=bNXm3rN9TIw),攻击力提升随击杀数量提高的数值同样是静流笔记中描述的两倍。另一方面,静流笔记对专武1技能的描述是准确的(实测单杀时蓝色数字为1500,双杀时为3000),所以有可能这个问题跟系数是加还是乘有关系?

bbbbbbbbba avatar Oct 07 '20 13:10 bbbbbbbbba

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.

HerDataSam avatar Oct 07 '20 14:10 HerDataSam

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.

bbbbbbbbba avatar Oct 07 '20 14:10 bbbbbbbbba

好像确实有问题,等明天上班摸鱼再仔细研究下(懒

MalitsPlus avatar Oct 08 '20 06:10 MalitsPlus

翻了半天没找到有什么问题...

而且ninon是目前唯一 action_type = 26action_value_1 = 2 的角色,想找其他角色做验证也没法。 目前能想出来的临时解决办法只能强行在 AdditiveAction 里计算值的时候手动乘个2来迎合游戏里的实际数值。

我会保持这个issue打开,看看有没有其他大佬能够解决。

MalitsPlus avatar Oct 10 '20 07:10 MalitsPlus

今天活动SP的bug让我又想起这个老问题,回头看了一下prefab之后,有了一个猜想(其实当时似乎也有过,只不过觉得太不靠谱了就没有提出来):是不是单纯因为这个技能中有两个动作都检查了击杀数量,导致每个击杀被计算了两次?当然有很多技能里都有两个动作检查同一个数值的情况,但可能因为击杀数量是需要“计数”的,所以比较特殊?

bbbbbbbbba avatar Nov 30 '22 10:11 bbbbbbbbba

无聊看了一下 其实就是他不是击杀数量,而是击杀数量+1 所以其实应该是[100 + 100 * (击杀的敌方数量 + 1)] image

krulci avatar Jan 12 '23 17:01 krulci

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 * 击杀的敌方数量] image image

krulci avatar Jan 12 '23 18:01 krulci

但是这样解释不了实际观察到的双杀蓝字TP量啊。

bbbbbbbbba avatar Jan 12 '23 18:01 bbbbbbbbba

但是这样解释不了实际观察到的双杀蓝字TP量啊。

你一开始写的不就是 150 450 750吗? 这有什么问题吗

krulci avatar Jan 12 '23 19:01 krulci

[100 + 100 * (击杀的敌方数量 + 1)]

计算50点TP上升的话,击杀的敌方数量 = 2时,应该是(100 + 100 * (2 + 1)) * 1.5 = 600

bbbbbbbbba avatar Jan 12 '23 19:01 bbbbbbbbba

等等,从代码上来看这并不是简单的“击杀的敌方数量+1”吧,而是在OnDefeatEnemy这个event上加了一个listener?

bbbbbbbbba avatar Jan 12 '23 19:01 bbbbbbbbba

因为是委托阿 应该这么理解才对,前面说的确实过于片面 只存在两种: 1)无击杀:[100 + 100 * 击杀的敌方数量] 2)有击杀:[100 + 100 * (击杀的敌方数量 + 1)] 但是他给OnDefeatEnemy这个Action委托类型赋值,意思是说 这个委托每次执行的时候,都会给击杀数+1 但是击杀到底怎么判定呢?那当然是从伤害来的 image 也就是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 单杀 image 双杀 image 三杀 image 四杀 image 五杀 image

krulci avatar Jan 12 '23 20:01 krulci

1)无击杀:[100 + 100 * 击杀的敌方数量] 2)有击杀:[100 + 100 * (击杀的敌方数量 + 1)]

啊这,那你非要把公式写成这样不是很奇怪,说穿了就是一个计数的逻辑而已,计数归计数,乘以100归乘以100,合在一起不就是[100 + 100 * (击杀的敌方数量 * 2)]嘛。

bbbbbbbbba avatar Jan 12 '23 20:01 bbbbbbbbba

而且你有没有想过“击杀的敌方数量”的初始值是哪里来的,为什么双杀的时候不是直接2→3→4,而是(0→)1→2→3→4?

bbbbbbbbba avatar Jan 12 '23 20:01 bbbbbbbbba

你结果上观察起来确实等价 但是他逻辑确实不是这样阿 image 然后第二个问题是这里 coroutineStartProcess会根据DJJKGCFKJNJ的数量Loop 其实意思就是根据双方角色Loop 然后执行ExecActionOnStartAndDetermineInstanceID +UnitActionController.ExecActionOnStart +execActionOnStart +GiveValueAction.ExecActionOnStart 五个角色时ExecActionOnStart一共执行了五次 之后每个角色才再执行SetDamage

krulci avatar Jan 12 '23 20:01 krulci

image 初始值是这里给的 所有都是0

krulci avatar Jan 12 '23 20:01 krulci

但是ExecActionOnStart不会直接增加DefeatEnemyCount对吧,只是设置委托,后面SetDamage才会执行对吧。

bbbbbbbbba avatar Jan 12 '23 20:01 bbbbbbbbba

归根结底目前看到的代码只有那个匿名的委托呼叫才会直接增加DefeatEnemyCount,那么这个委托到底被呼叫了几次呢。

bbbbbbbbba avatar Jan 12 '23 20:01 bbbbbbbbba

稍微调试了一下 这个要修要把描述改成 [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)

其中103001102103001105属于Elements.GiveValueAdditiveAction类 而Elements.GiveValueAdditiveAction继承Elements.GiveValueAction。 首先,前面说的Delegate.Combine(a, b)a = null(即从没被赋值之时),他返回的值就是b而已。 而当游戏在初始化扇子UB的时候,ExecActionOnStart会走两次,分别为了103001102103001105各执行一次。 并且每一次都会把Skill.ActionParameters的每一个AcitionParameter赋予b 但是由于扇子6星的UB103001102103001105各执行了一次ExecActionOnStart,因此每一个Action ID: 103001101~5Elements.ActionParameter.OnDefeatEnemy会被103001102103001105分别赋值一次 第一次被103001102Delegate.Combine(a, b)的结果是b 第二次被103001105Delegate.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

krulci avatar Jan 15 '23 13:01 krulci

这也说明为什么旋风击和旋风击+并不200 因为旋风击和旋风击+的四个Action ID中只有第三个是加法赋值

krulci avatar Jan 15 '23 14:01 krulci