有关Rune Run最后的敲石头,就是完成A4的第二个任务,将有一个符文的奖励,在地狱难度下面完成这个任务,可以获得15#~25#中的某个符文。网上大多研究表明,这个到底会得到那个符文,完全是随机的。
然后从理论的角度,由于伪随机并不是真正的随机,因此完全有可能找到其规律,从而实现敲石头的时候,只出25#。
因此,我上网找了一下相关的资料,得到如下信息:
1、敲石头掉落的符文产生方法,是硬编码在d2game.dll中的。这个和别的物品掉落不一样,别的物品基本上都是由一个公共函数产生,几率由配置文件决定。
2、Diablo2 1.10和Diablo2 1.11的符文掉落上,算法有变动。因此,如果按照1.10敲符文的经验在1.11里敲符文,很可能不理想。这个是我反汇编d2game.dll得出的结论。
下面说的都是在Diablo2 1.11B版本文件上进行分析的。
1、首先要找到d2game.dll中,与敲石头任务奖励相关的代码。这个很容易,在d2game.dll里面搜索r25,就看到了,引用这个数字的地方,就是相关的代码;
2、在相关的代码片断,其任务奖励过程是:首先产生完美宝石,然后产生无瑕疵的宝石,最后产生符文。
其中,完美宝石和无瑕疵的宝石产生极其类似,都是产生一个0~6的随机数,然后对应到相应的宝石即可。
3、符文的产生较为复杂。首先判断游戏难度,决定掉落的符文范围是多少?在普通难度,掉落的是1#~11#,而在噩梦难度,掉落的是12#~22#,地狱难度掉落的是15#~25#。
然后调用一个随机数函数,用于产生最终掉落符文的序号。最后根据这个序号产生对应的符文。
而最为感兴趣的自然就是其中的随机数函数RuneRandom了。。其代码如下:
.text:6FC21040 RuneRandom proc near ; CODE XREF: sub_6FC336B0+187p
.text:6FC21040 ; sub_6FC41C20+CCp ...
.text:6FC21040 push esi
.text:6FC21041 mov esi, eax ; ESI=EAX=B
.text:6FC21043 test esi, esi
.text:6FC21045 jg short loc_6FC2104B
.text:6FC21047 xor eax, eax
.text:6FC21049 pop esi
.text:6FC2104A retn
.text:6FC2104B ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:6FC2104B
.text:6FC2104B loc_6FC2104B: ; CODE XREF: RuneRandom+5j
.text:6FC2104B mov eax, [ecx]
.text:6FC2104D push ebx
.text:6FC2104E push edi
.text:6FC2104F mov edx, 6AC690C5h ; 初始化随机数种子
.text:6FC21054 lea edi, [esi-1] ; lea edi,[A]
.text:6FC21057 mul edx
.text:6FC21059 xor ebx, ebx
.text:6FC2105B test edi, esi
.text:6FC2105D jz short loc_6FC21075
.text:6FC2105F mov edi, [ecx+4]
.text:6FC21062 add eax, edi
.text:6FC21064 adc edx, ebx
.text:6FC21066 mov [ecx+4], edx
.text:6FC21069 mov [ecx], eax
.text:6FC2106B xor edx, edx
.text:6FC2106D div esi ; ESI = A = 10
.text:6FC2106F pop edi
.text:6FC21070 pop ebx
.text:6FC21071 pop esi
.text:6FC21072 mov eax, edx
.text:6FC21074 retn
.text:6FC21075 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:6FC21075
.text:6FC21075 loc_6FC21075: ; CODE XREF: RuneRandom+1Dj
.text:6FC21075 mov esi, eax ; EDI=ESI
.text:6FC21077 mov eax, [ecx+4]
.text:6FC2107A add esi, eax
.text:6FC2107C mov eax, edi
.text:6FC2107E adc edx, ebx
.text:6FC21080 pop edi
.text:6FC21081 pop ebx
.text:6FC21082 mov [ecx], esi
.text:6FC21084 and eax, esi
.text:6FC21086 mov [ecx+4], edx
.text:6FC21089 pop esi
.text:6FC2108A retn
.text:6FC2108A RuneRandom endp
可以看出,它使用的是一种典型的伪随机数产生算法。
简单的说,就是用如下公式产生:
Rand_Number = (Rand_Seed * X + Y) mod Z
其中Rand_Seed固定是6AC690C5h, 而Z固定是10
因此,决定最终随机数的只有X和Y。
不幸的是,X和Y并不能简单的推算出来。。。
它的XY大概的产生过程是:
1、貌似系统初始的时候,有一个XY;
2、以后,每次使用随机数算法,将X更新为X*Rand_Seed + Y的低半部分;而Y更新为X*Rand_Seed + Y的高半部分。
最有可能的方法是,在游戏中,有地图工具,读取内存中的与随机数相关的XY,然后再推算出最终掉落的符文。
不过这个方法有个问题,貌似在打怪、开箱子等等,都会更新XY的值。。。。也许不能打怪或者做任何与随机函数有关的事情。 |