• 42462阅读
  • 82回复

[原创]DYRB房间的一些潜规则(新人学习一下吧) [复制链接]

上一主题 下一主题
离线xpkong
发帖
2048
金钱
10
91币
0
信誉
0
资产
0 IST
在线时间
350 小时
注册时间
2007-10-03
最后登录
2020-05-03
只看该作者 10楼 发表于: 2008-06-06 08:04:09
支持!
俗话说无规矩不成方圆
离线newangels
发帖
*
金钱
*
91币
*
信誉
0
资产
0 IST
在线时间
小时
注册时间
*
最后登录
*
只看该作者 11楼 发表于: 2008-06-06 08:42:50
学习了,我好像违反了好几条,原来高级别的人k82为了经验啊,我不知道啊,下次不82的房间了
离线hyggghyg
发帖
968
金钱
1185
91币
0
信誉
0
资产
0 IST
在线时间
367 小时
注册时间
2008-04-22
最后登录
2013-04-30
只看该作者 12楼 发表于: 2008-06-06 09:06:01
狠狠地顶一下
离线hqy
发帖
1850
金钱
187
91币
0
信誉
0
资产
0 IST
在线时间
260 小时
注册时间
2008-04-12
最后登录
2020-05-02
只看该作者 13楼 发表于: 2008-06-06 09:07:40
应该有对应的DYRB房间的厚黑学出版
离线cloudwzq
发帖
848
金钱
0
91币
0
信誉
0
资产
0 IST
在线时间
230 小时
注册时间
2008-04-09
最后登录
2008-09-30
只看该作者 14楼 发表于: 2008-06-06 09:09:05
问个经验获取问题:
记得带小号时,如果凑满8pp一起run5小队,好像每个角色升级反而升的快。
为什么kb的时候要人越少越好?
具体经验获取有没有简单公式呢?
离线hqy
发帖
1850
金钱
187
91币
0
信誉
0
资产
0 IST
在线时间
260 小时
注册时间
2008-04-12
最后登录
2020-05-02
只看该作者 15楼 发表于: 2008-06-06 09:13:32
  当你在非资料片模式下,在地狱难度最后杀Diablo的时候,如果是8个玩家结盟在Diablo的场景,有人就会要求等级最低的离队。
    这看似是一个奇怪的要求,但是如果没人离队,就是说如果是8pp杀Diablo的话,那么每个玩家只能获得1点经验,而不是预期的大量经验。
    同样的情形发生在资料片模式地狱难度杀Baal五小队的第二小队的时候,如果没人离队而且8个玩家都在场,那么每个玩家只能获得1点经验。BN上有一些老玩家习惯在杀第二小队的时候,等级最高的离队,杀完第二小队后,再重新组队。

    这个问题解决方法只有一个:杀Diablo或者第二小队的时候,最多保持7个玩家在场。

    如果你想深究这个原因,你回去查询IMPK的经验计算过程,“Experience计算的详细流程”http://impk.blizzard.cn/ShowTopic-546719-34.html
    你会发现其中并没有说明为何出现这种情况。因此我决定研究一下程序代码,以找到真正的原因。

    很容易,可以发现游戏中经验值的计算代码,而问题出在结盟时候经验分配的计算上,代码如下(1.11b的代码,1.10的算法一样)
.text:6FC9E04D loc_6FC9E04D:                          ; CODE XREF: PersonExpGain2+50j
.text:6FC9E04D                mov    esi, [esp+70h]  ; 引入结盟因素,基础经验值=0x0039FD64
.text:6FC9E051                lea    eax, [ecx-1]    ; 同一区域内在exp分配范围内结盟玩家数
.text:6FC9E054                imul    eax, esi        ; 0x0195EDBC=exp*(player-1)
.text:6FC9E057                imul    eax, 59h        ; 0x8D1FA65C=exp*(player-1)*89
.text:6FC9E05A                cdq                    ; EDX=FFFFFFFF EAX=8D1FA65C
.text:6FC9E05B                and    edx, 0FFh      ; EDX=FF  EAX=8D1FA65C
.text:6FC9E061                add    eax, edx        ; EAX=8D1FA75B=8D1FA65C+FF
.text:6FC9E063                sar    eax, 8          ; EAX=EAX/256=FF8D1FA7
.text:6FC9E066                add    eax, esi        ; EAX=FFC71D0B=FF8D1FA7+0039FD64
.text:6FC9E068                mov    [esp+5Ch+arg_8], eax
.text:6FC9E06C                xor    esi, esi
.text:6FC9E06E                test    ecx, ecx        ; 游戏内玩家数=8
.text:6FC9E070                fild    [esp+5Ch+arg_8] ; FFC71D0B
.text:6FC9E074                pushf
.text:6FC9E075                cmp    dword_6FD39F7C, 0
.text:6FC9E07C                jnz    short loc_6FC9E084
.text:6FC9E07E                fidiv  dword ptr [esp+5Ch] ; 除以0x277==同一场景内所有玩家级别之和
.text:6FC9E082                jmp    short loc_6FC9E08D
.text:6FC9E084 ; ---------------------------------------------------------------------------
.text:6FC9E084
.text:6FC9E084 loc_6FC9E084:                          ; CODE XREF: PersonExpGain2+ACj
.text:6FC9E084                push    dword ptr [esp+5Ch]
.text:6FC9E088                call    unknown_libname_13 ; Microsoft VisualC 2-8/net runtime
.text:6FC9E08D
.text:6FC9E08D loc_6FC9E08D:                          ; CODE XREF: PersonExpGain2+B2j
.text:6FC9E08D                popf
.text:6FC9E08E                fstp    dword ptr [esp+70h] ; C5B8A225
.text:6FC9E092                jle    short loc_6FC9E0CB
.text:6FC9E094
.text:6FC9E094 loc_6FC9E094:                          ; CODE XREF: PersonExpGain2+F9j
.text:6FC9E094                mov    edi, [esp+esi*4+34h] ; 4B=玩家级别
.text:6FC9E098                mov    ebx, [esp+esi*4+14h] ;
.text:6FC9E09C                mov    [esp+5Ch+arg_8], edi
.text:6FC9E0A0                fild    [esp+5Ch+arg_8] ; 4B
.text:6FC9E0A4                fmul    dword ptr [esp+70h]
.text:6FC9E0A8                call    __ftol2
.text:6FC9E0AD                mov    ecx, [esp+6Ch]  ; exp=5A
.text:6FC9E0B1                push    ecx
.text:6FC9E0B2                push    ebp            ; ptGame
.text:6FC9E0B3                call    PersonExpGain
.text:6FC9E0B8                push    eax
.text:6FC9E0B9                push    edi
.text:6FC9E0BA                push    ebp
.text:6FC9E0BB                mov    eax, ebx
.text:6FC9E0BD                call    sub_6FC9DDB0
.text:6FC9E0C2                mov    eax, [esp+54h]
.text:6FC9E0C6                inc    esi
.text:6FC9E0C7                cmp    esi, eax
.text:6FC9E0C9                jl      short loc_6FC9E094

    关键的代码段是从6FC9E04D到6FC9E092这一段。代码边上的注释,其游戏场景就是:非资料片,地狱难度,8pp在场KD。

    首先,地狱难度的Diablo的基础经验值是exp1=0x0039FD64,计算算法如下:

1.exp1=0x0039FD64
2.exp2=exp1*(8-1)=0x0195EDBC
3.exp3=exp2*89=0x8D1FA65C
4.将32位的exp3符号扩展成64位的值。由于exp3的最高位为1,所以扩展后EDX=0xFFFFFFFF。注意,EDX:EAX已经变成负数了....
5.EDX&0xFF,就是限制EDX不能太大,由于是负数,所以EDX=0x000000FF
6.exp4=exp3+EDX,很奇怪,为什么要加上高半部分呢?!
7.exp5=exp4/256=FF8D1FA7,注意这里用的是算数移位,由于最高位是1,所以补入1
8.使用fild指令,将exp5装入浮点寄存器。注意fild指令认为这是一个32位的有符号数,所以到了浮点寄存器里面,变成负数浮点数了
9.exp6=exp5/同一场景内所有玩家级别之和

下面开始循环了
10.exp7=exp6*当前玩家的等级
11.将exp7放入eax,调用PersonExpGain函数,进一步修正玩家最终获得的经验
12.对获得经验的每个玩家,重复10、11步

PersonExpGain函数执行经验修正,具体算法就如IMPK的资料所示,值得注意的是,一开始有一个判断
.text:6FC9B3E0                push    esi
.text:6FC9B3E1                mov    esi, eax        ; 经验总数
.text:6FC9B3E3                cmp    esi, 7FFFFFh
.text:6FC9B3E9                jle    short loc_6FC9B3FE
.text:6FC9B3EB                mov    esi, 7FFFFFh
.text:6FC9B3F0
.text:6FC9B3F0 loc_6FC9B3F0:                          ; CODE XREF: PersonExpGain+20j
.text:6FC9B3F0                test    ebx, ebx        ; ebx=ptPlayer
.text:6FC9B3F2                jz      short loc_6FC9B40B
.text:6FC9B3F4                cmp    dword ptr [ebx], 0
.text:6FC9B3F7                jnz    short loc_6FC9B40B
.text:6FC9B3F9                mov    eax, [ebx+4]    ; ptPlayer->Type PAL=3
.text:6FC9B3FC                jmp    short loc_6FC9B40D
.text:6FC9B3FE ; ---------------------------------------------------------------------------
.text:6FC9B3FE
.text:6FC9B3FE loc_6FC9B3FE:                          ; CODE XREF: PersonExpGain+9j
.text:6FC9B3FE                test    esi, esi
.text:6FC9B400                jg      short loc_6FC9B3F0 ; 经验小于等于0,则强制为1
.text:6FC9B402                mov    eax, 1
.text:6FC9B407                pop    esi
.text:6FC9B408                retn    8

    Blizzard的程序员有先见之明,一开始拿获得的经验值与0x7FFFFF比较,取较小者。但是此时的EAX是负数,所以在
6FC9B3E9                jle    short loc_6FC9B3FE
处的比较会成功,转到
6FC9B3FE                test    esi, esi
然而这个test会失败,跳过了所有后续复杂的经验值修正,所以最后获得的经验值就是1,然后直接返回。

    从上面的代码可以看出,暴雪的程序员应当试图在按照IMPK给出的公式来进行编程,但是由于没有注意到数值的有效位数,导致很容易就溢出变成负数,从而导致8pp KD奇怪的经验值获得。


    如果是7pp KD,那么计算如下:
1.exp1=0x0039FD64
2.exp2=exp1*(7-1)=0x015BF058
3.exp3=exp2*89=0x78F68E98
4.将32位的exp3符号扩展成64位的值。由于exp3的最高位为0,所以扩展后EDX=0x00000000。注意,EDX:EAX还是正数....
5.EDX&0xFF,就是限制EDX不能太大,由于是正数,所以EDX=0x00000000
6.exp4=exp3+EDX=0x78F68E98
7.exp5=exp4/256=0x0078F68E,注意这里用的是算数移位,由于最高位是0,所以补入0
8.使用fild指令,将exp5装入浮点寄存器。注意fild指令认为这是一个32位的有符号数,所以到了浮点寄存器里面,还是正数浮点数了
9.exp6=exp5/同一场景内所有玩家级别之和

下面开始循环了
10.exp7=exp6*当前玩家的等级
11.将exp7放入eax,调用PersonExpGain函数,进一步修正玩家最终获得的经验
12.对获得经验的每个玩家,重复10、11步



    可见,7PP KD,可以获得正常的经验值。
离线sf036920
发帖
34
金钱
0
91币
0
信誉
0
资产
0 IST
在线时间
19 小时
注册时间
2008-06-04
最后登录
2011-07-26
只看该作者 16楼 发表于: 2008-06-06 09:21:48
好帖子应当置顶
离线biantaiyang
发帖
561
金钱
1398
91币
0
信誉
0
资产
0 IST
在线时间
91 小时
注册时间
2008-05-08
最后登录
2024-02-05
只看该作者 17楼 发表于: 2008-06-06 09:58:42
有时的确是无意冒犯呀,受教!
发帖
780
金钱
0
91币
0
信誉
0
资产
0 IST
在线时间
84 小时
注册时间
2008-04-25
最后登录
2009-06-22
只看该作者 18楼 发表于: 2008-06-06 14:25:19
写的不错!
离线gudu119
发帖
240
金钱
0
91币
0
信誉
0
资产
0 IST
在线时间
50 小时
注册时间
2008-04-23
最后登录
2008-07-08
只看该作者 19楼 发表于: 2008-06-06 15:31:34
好好学习,天天向上