植物大战僵尸吧 关注:529,509贴子:4,909,928

尝试研究了下传送带的机制

只看楼主收藏回复

初学反汇编,学艺不精,请务必持有怀疑精神。
在此向为pvz机制探索做出付出的前人、和在我的探索过程中提供指导的同学前辈表示感谢。


IP属地:江苏1楼2023-07-17 20:53回复
    2楼备用,勿回。


    IP属地:江苏2楼2023-07-17 20:54
    收起回复
      3楼也备用吧。


      IP属地:江苏3楼2023-07-17 20:54
      收起回复
        与传送带有关的函数主要如下:
        【41F380】初始设定传送带倒计时和卡片(还包括初始化一些与传送带无关的内容)。
        【422CD0】游戏过程中传送带倒计时和卡片的更新。
        【489C70】传送带上卡片位置更新(即卡片的移动)。
        【489A50】在传送带上创建新的卡片(主要是卡片坐标)。
        其中【422CD0】比较复杂,再稍微多说两句,其他的就不解释了:
        422CD0~422D1F判断倒计时是否归零,如果未归零则倒计时-1并直接终止,如果归零则继续向下;
        422D25~422E0B重设倒计时;
        422E10~4232A7根据关卡设定传送带可选的植物种类列表、和各植物的初始权重;
        4232AB~42340F第一次修改权重;
        423416~423453第二次修改权重(这里注意下第一、二次修改不是完全线性进行的,是列表中每个植物依次进行两次修改,前一个植物进行完再进行下一个植物,循环的指令位于423456~42345E);
        423464~42348E随机选择卡片并收尾。
        几个相关的地址,似乎指针表上没有:
        [[[6A9EC0]+768]+144]+34C:游戏时钟(不包括选卡停留的时间,与[[[6A9EC0]+768]+5568]相同,但仅用于传送带关卡)
        [[[6A9EC0]+768]+160]+5C:传送带倒计时
        [[[6A9EC0]+768]+160]+68:传送带上一次生成的卡片(并非传送带中最后一张卡片)
        中的植物种类
        应该还有,不过我就懒得找了……
        下文将与初始设定相对应的称为“过程”设定。


        IP属地:江苏4楼2023-07-17 20:55
        回复
          目录
          零、省流助手
          一、初始倒计时和初始卡片
          二、过程倒计时
          三、过程卡片
          四、传送带上卡片的移动
          五、创建新卡片的位置


          IP属地:江苏5楼2023-07-17 20:55
          回复
            零、省流助手
            以下是一些实际游戏中可以用到的规律:
            1. 传送带中卡片数量≤4时,下一张卡片来得最快,≤8时差别都不大,但≥9时来的最慢;
            2. 除睡莲、花盆、墓碑苔藓外,场地上的植物数量不影响传送带;
            3. 对于绝大部分卡片,传送带中同种卡片数量≤2时,得到该卡片的概率最大;对于所有卡片≥4时,概率极小;
            4. 获得花盆、睡莲的概率与 场地上+传送带中该种植物的数量和 有关,权重随数量和的增加而均匀减小,直至降到极小(不过正常游戏基本遇不到);
            5. 场地上+传送带中墓碑苔藓的数量和 达到墓碑数量后,不会再得到墓碑苔藓;
            6. 僵王关卡中,空花盆≥6时,得到投手的可能性最大;≤2时,得到投手的概率最小。


            IP属地:江苏6楼2023-07-17 20:56
            收起回复
              一、初始倒计时和初始卡片

              这张图包括三部分内容:初始倒计时、过程倒计时、初始卡片,下面一样样说。
              绝大部分关卡的初始倒计时都是200,但是有两种例外:
              1. 僵王系列(“系列”指包括冒险、迷你游戏等所有模式)和“你看,他们像柱子一样”,初始倒计时1000(估计是因为有好几张初始卡片);
              2. 坚果保龄球系列和“你能把它挖出来吗?”,初始倒计时1,也就是一进门就能收到礼。
              初始卡片除了众所周知的“你看,他们像柱子一样”,僵王系列和“隐形食脑者”同样有,不过隐形食脑者的初始倒计时仍然是200。
              初始倒计时和初始卡片在进入游戏时就已经设定完成。这里尤其要强调初始卡片,也就是游戏一开始固定会生成的卡片,它们是一下子就全部设定好的,而不是等到了某个时间点再生成。至于为什么实际游戏时是每过一段时间才会出现一张,那是因为初始设定时它们被抛在了不同的位置,因此进入可点击区域的时间也不同,详细的内容在第五节再讲。
              如果使用ShowMe,是可以看到传送带不可见区域的卡片的。
              同样是由于不可见区域的卡片,在这种情况下,我们能看到的卡片并不一定是全部的卡片。比如柱子关开局时已经是6张了,如果不及时清理掉,就有可能看上去是3张,倒计时重置时却重置成了1275(5~6张,3*425)之类的情况,遇到莫慌。


              IP属地:江苏7楼2023-07-17 20:58
              收起回复
                二、过程倒计时
                除了初始时设定的倒计时,游戏每次添加新的卡片后都需要重设倒计时,这个倒计时由两个数值相乘得到。
                一是有关卡自身决定的倍率(也就是表中的基数),绝大多数关卡的倍率都是1(不然也不会以这个为1倍了),例外情况如下:
                1. 僵王系列:0.875倍(说起来这里CE给取了近似值8.8,害我懵了半天)
                2. 保护传送门/你能把它挖出来吗?:1.5倍
                3. 隐形食脑者:2倍
                4. 你看,他们像柱子一样:3倍
                二是有传送带中已有的卡槽数决定,具体情况如下:
                0~4张:*400
                5~6张:*425
                7~8张:*500
                9~10张:*1000
                实际上,*400和*500的差距倒不大,哪怕是最大的3倍率也只差了(500-400)*3=3s,但是到了*1000差别就大了,延长到了两倍以上,因此游戏时最好卡片不要超过8张。
                注意这个设定位于添加新卡片之前,因此使用的是添加新卡片前的卡槽数。


                IP属地:江苏8楼2023-07-17 20:59
                回复
                  三、过程卡片
                  这应该是最大头的一个环节了……首先根据关卡会创建一个植物列表,列表中包括植物的种类和“初始权重”,然后初始权重再经过两次修改得到最终的权重,最后加权随机得到一种植物。具体数据如下,表中背景有颜色的单元格表示会进行第一次修改:
                  (表中顺序应该是按照内存中的顺序来的,从[esp+18]开始,植物种类和初始权重间隔排列)


                  IP属地:江苏9楼2023-07-17 20:59
                  回复
                    接下来是第一次修改,我又称之为特殊修改,因为它只对少数几种特殊的植物有效。共有4种情况。
                    1. 墓碑苔藓(4232F8~42331E):
                    如果场地上该植物数量+传送带中该植物数量(下文称“现有总数量”)≥墓碑数量(理论上讲其实不可能出现大于的情况),则权重改为0,不再参与第二次修改;反之则保留初始权重,正常参与第二次修改。
                    2. 睡莲/花盆(423323~423372):
                    首先会有一个“临界数量”,分别是:
                    睡莲:18(水路铺满)
                    花盆(非柱子关卡):35(相当于1~7列铺满)
                    花盆(柱子关卡):45(铺满)
                    很显然,实际游戏基本上是很难达到甚至接近的……
                    然后随着“现有总数量”从0逐渐接近“临界数量”,其权重也会均匀地从初始权重减小到1。
                    具体在内存中的公式是:int[(1 - 初始权重)* 现有总数量 / 临界数量 + 初始权重 + 0.5 ]。我还给列了个表:(其实我就是列完了表才发现这个公式就是平均减小的意思……)
                    3. 僵王系列关卡 投手植物(42337A~4233F9)
                    与场地上空花盆的数量有关。(注意是空的)
                    卷心菜/西瓜:空花盆0~2,改为2;空花盆3~5,改为3;空花盆>5,保留初始值10。
                    玉米:空花盆0~5,改为1;空花盆>5,保留初始值5。
                    4. 僵王系列关卡 花盆(4233FC~42340F)
                    如果此时僵王正在砸车(状态85),则花盆权重变为500。注意这一条位于第二条后面,会覆盖掉第2条的结果。
                    下文将进行过或跳过第一次修改后的权重称为中间权重。


                    IP属地:江苏10楼2023-07-17 21:01
                    收起回复
                      接下来是第二次修改,我又称之为普遍修改,因为它普遍适用于绝大多数情况,只有以下两种情况例外:
                      1. 墓碑苔藓在第一次修改中,现有总数量≥墓碑数量,权重设置为0,不再修改。(实际上有墓碑苔藓的只有2-10)
                      2. 若植物列表中的植物总数≤2,则跳过第二次修改。(实际上满足条件的只有1-5、坚果保龄球1、你能把它挖出来吗)
                      第二次修改的内容与传送带中该种植物的卡片数量有关,具体如下:
                      若卡片数≥4,则权重改为1。
                      若卡片数为3,则权重改为5。
                      若卡片数为0~2,则再进行判断:如果与上一次选择的植物相同,则改为中间权重/2;如果不同,则保留中间权重。
                      一般来说,都是卡片数越多权重越小的,如果中间权重≥10,那么中间权重/2≥5,这是一定符合的。因此大部分卡片最好不要储存>2张,当然如果你不想要那就存4张。
                      但如果中间权重=5,那么若卡片数为3,则最终权重为5;如果卡片数为0~2,则最终权重为5或2,卡片数增多反而理论上概率会增大。也就是说对于那些初始权重为5的植物,在传送带中保留3张卡片,能使新卡片最大可能地得到该植物。
                      不过这只是在理论上推测,实际游戏时如何就不清楚了。除了5,还有一些小于10的情况,此处也不多讨论了。
                      另外还有,如果卡槽已满(实际上传送带关卡也是有卡槽格数限制的,就是10张),倒计时是不会受影响的,并不会有暂停/重置之类的变化。倒计时归零后照样会选择卡片,只是到了489A50函数(在传送带上创建新的卡片)时会跳过,也就是说,即便卡槽已满,[[[6A9EC0]+768]+160]+68处的“传送带上一次生成的卡片”依然会不断变化。


                      IP属地:江苏12楼2023-07-17 21:03
                      收起回复
                        四、传送带上卡片的移动
                        传送带上的卡片每4cs向左移动1px。更准确地说,是当游戏时间(不包括选卡停留的时间)是4的整数倍时,卡片在传送带上的位置-1。


                        IP属地:江苏13楼2023-07-17 21:03
                        收起回复
                          五、创建新卡片的位置
                          传送带上的每一张卡片都有对应的“在传送带上的位置”,这个位置是相对位置,相对于该卡片所应该达到的最左侧的距离,比如下图中所有卡片的相对位置都是0:
                          此外在指针表中还有一个“卡牌X坐标”,那个是个固定的数值,其中第一张卡牌的X坐标是91,每向右一张卡牌+50,而不是传送带中卡片的实时位置。也就是说,传送带中卡片的横坐标= 卡槽序号 * 50 +41 + 在传送带上的位置。
                          这里为了图方便,我们就全部以第一张卡片的左边缘为基准,下文称之为绝对位置(其实也不是绝对的说)。
                          每张卡片的宽度是50px,卡片与卡片之间没有间隙。也就是说,第x张卡片的相对0位置=绝对50 *(x - 1)位置。
                          经手测,鼠标可以点击到的最右端的绝对位置是503,大概是下图这个样子:(靠音效可以辨认出是否点击到卡片)


                          IP属地:江苏14楼2023-07-17 21:05
                          回复
                            向传送带中添加新的卡片时,先将其相对位置设置为515 – 传送带中已有卡片数 * 51。此时若已有卡片数>0,则与前一张卡片的相对位置比较,若新卡片的相对位置<前一张的相对位置,则将新卡片的相对位置设置成前一张卡片的相对位置+40。下面详细分析。
                            前文有说,卡片与卡片之间是没有空隙的,但这里的*51,我估计是宝开最初设计时有1px的空隙,这样新卡片的绝对位置其实是固定的515:绝对x=相对(515 – 传送带中已有卡片数 * 51)+51 * 传送带中已有卡片数=515。
                            但是现在空隙没了,要确保卡片绝对位置仍然是515的话,51应该改为50,保留51的话实际上是多减掉了。而且已有的卡槽数越多,多减掉的就越多,实际上每张卡片生成的绝对位置如下:
                            出生的位置不同,达到503(也就是最早可被拾取)的时间也不同,不过即便是第一张和第十张也只差了9*4=36cs(每4cs移动1px没忘吧),这(至少以目前的技术发展)是完全可以忽略的。
                            接下来将两张卡片的相对位置进行比较,这其实就是判断两张卡片会不会重叠甚至倒序(只要有1px的重叠就叫重叠),只要不会那就没问题,就这么办;但如果会,则重新设置为前一张卡片的相对位置+40,这里“相对位置差=40”实际上就是两张卡片间距40。
                            那么什么情况下前后两张卡片会重合呢?游戏过程中,两张卡片生成的间隔至少是僵王关的350cs,则相邻生成两张卡片间隔350/4-1=77.5,向下取整得两张卡片的绝对位置间隔77px>50px,这已经是最小的间距了,但两张卡片仍不可能重合。
                            因此第二条规则其实就是为初始卡片准备的。


                            IP属地:江苏15楼2023-07-17 21:08
                            收起回复
                              (以下内容没有什么实用,只是卡片间距在我刚开始探究机制时给了我不小的困惑,我想验证一下。)
                              我们再算一些内容,有初始卡片的关卡
                              ,在不从传送带上取下植物的前提下,每两张卡片之间的间距(未考虑边界值导致的传送带可能多移动1px):
                              这都是不从传送带上取下植物的情况,如果要取下的话情况实在太多,我也就不讨论了。但实际游戏时其实,尤其是柱子关和僵王关,是几乎不会开局好半天都不种植物的。
                              僵王关倒不明显,基本上都差不多。但柱子关,如果仔细数的话会发现,明明初始卡片只有6张,但是第1~8张都间隔比较近,从第8张往后间隔才变得非常远。这就是因为第7张创建的时候,第6张卡片的位置还在509以外,于是第7张直接接在后面,第8张也是同理,接下来才比较正常。(其实也未必,但是第8和第9张的间隔太大,不容易察觉出问题)
                              最诡异的还是隐形关,初始卡片两张,第三张和第四张间距非常小,第四张和第五张又间距非常大。这也是因为初始倒计时200比较小(我甚至怀疑又是宝开忘了改了),第三张生成时第二张的位置还大于513,所以被向右调了很多,但是第四张又是正常生成的。(两张卡片的间距只有17px,这个是读内存验证过的。)
                              至于第四张和第五张间距非常大,这是正常的,隐形食脑者的传送带倒计时本就是*2倍的,第四张和第五张的间距正常就是800/4-1-50=149px。


                              IP属地:江苏16楼2023-07-17 21:09
                              回复