口袋改版资源吧 关注:249,292贴子:1,573,726
  • 10回复贴,共1

浅谈火红叶绿汉化中的培育屋BUG

取消只看楼主收藏回复

前言
本文章简单阐述下关于火红叶绿汉化(或以火红叶绿为基础的改版汉化)中出现的培育屋bug的产生原因及解决方法。适合对游戏机制有兴趣及有意向进行改版汉化的朋友们进行阅读。


IP属地:福建1楼2023-09-10 03:44回复
    BUG介绍
    培育屋汉化bug,指的是当GBA火红叶绿游戏里存入两只宝可梦后,在确认取出时,发生的卡死问题。该bug仅发生在存入两只宝可梦的情况下,且仅在汉化版中存在,日文、英文等原版中并不存在该问题。

    这是一个由来已久的bug,早在d商汉化时期,以及口袋群星SP汉化组的2012年精灵宝可梦版汉化时期均有发生。口袋群星SP的汉化版中,后续的更新版里已经修复了该问题,在发布页的更新内容中可以看到这点。

    在如今,会再次遇到这个bug,往往是玩家游玩d商版、早期未更新的12版汉化时会出现。同时在改版圈,改版汉化者引入国外的改版作品进行汉化时,也常常会遇到这种问题。部分早期汉化的改版作品未进行这个bug的修复,玩家游玩时也会遇到这个情况。


    IP属地:福建2楼2023-09-10 03:45
    回复
      2026-01-01 05:17:28
      广告
      不感兴趣
      开通SVIP免广告
      口袋群星SP的解决方式
      在改版作者的汉化中,往往发现这个bug会在汉化了"Yes\nNo"和"Go back to the\nprevious menu."这两段文字后出现。前者用于“是\n否”选项框的文字,后者则是PC电脑选择道具寄存系统时的提示文字“返回至\n上一级菜单”。
      可以看看口袋群星SP汉化组是如何解决这个问题的:


      可以看到口袋群星SP的做法是保留了第二句的原句,将第二句的汉化文本修改指针移动到了其他空位处。
      除了口袋群星SP的方法外,保留第二句在原位汉化,但是在句子前添加一个空格,又或是在“是\n否”的汉化文本中插入一个空格,同样可以解决这个bug。那么这个bug的本质原因,究竟是什么呢?还请接着往下看。


      IP属地:福建3楼2023-09-10 03:46
      回复
        BUG的本质原因
        在这里我们综合借助no&gba的debug功能,以及pret的反编译工程进行探索。
        首先既然是已知读取到“返回至\n上一级菜单。”时会出现问题,那么便可以对该地址进行断点,一旦有程序读取这条文本所在的地址时便暂停程序。从上面截图可以看到地址是0x08416080,那么我们需要设置该地址被读取时即停止的断点代码格式为:“[08416080]?”
        按下ctrl+b键唤出断点窗口,输入这串代码。

        设置好断点后,在培育屋内进行对话,当触发断点条件时,程序会停止在对应指令上。在这里可以看到是停在了0x081E5F9E的函数位置上。

        在pokefirered反编译生成的map文件中,我们可以查找到这个地址的函数是strcpy。

        但是很可惜这个函数是封装在库里的函数,并没有c语言样式的函数代码。那么我们接着回到no&gba里观察这个函数。


        IP属地:福建4楼2023-09-10 03:47
        回复
          断点上一位的指令ldrb r0,[r2],意味着将地址为寄存器r2里的值,将该地址的1字节的值,存入到寄存器r0里,可以看到r0里存入的值为0xC1,对应的便是"Go back to the\nprevious menu."的第一个字母“G”的编码。

          而接下来的指令strb r0,[r3],意味着将寄存器r0的低位1字节的值存入寄存器r3的值所代表的地址,即0x03007D6D。Trace运行一下指令,就可以在数据窗口内观察到该地址的确被写入了0xC1。

          观察0x03007D6D周围的数值,可以发现前面的数值其实就是"Go back to the\nprevious menu."这句文本前面的其他文本内容,从0x03007D4C开始写入。


          在反编译项目里可以看的更清楚,写入的是这些文本


          IP属地:福建5楼2023-09-10 03:49
          回复
            继续运行程序,我们可以发现这个函数会进行一个判断,即读入的文本编码是否为0x00,也即空格所代表的编码,只有当读到0x00时,程序才会停止读入,否则会一直读取文本的内容。

            那么到这里问题已经开始逐渐明了了,"Go back to the\nprevious menu."文本的第三个字符便是空格,也即0x00,可以终止程序的运行,而汉化后的文本由于中文语法习惯不常用空格,导致程序一直读取不到0x00的值,造成内存溢出,文本编码不断载入占用了其他内存的数据。
            这也符合上述提到的几种解决方案都是在其中保留了0x00的编码,使得读入的编码没有造成内存溢出。


            IP属地:福建6楼2023-09-10 03:49
            回复
              接着我们看一看究竟是哪一个程序调用了这个strcpy函数,在记录返回的程序地址的r14寄存器的位置上,可以看到是0x08046961,在反编译文件里查找,可以看到是函数DaycarePrintMonLvl所在的范围内。

              那就让我们来看一看这个函数到底写了些什么。

              可以看到strcpy((char *)lvlText, (const char *)gText_Lv);这句,意思是将文本gText_Lv的值拷贝到变量u8 lvlText[12]的位置上。而这个gText_Lv,正是上面观察到的被载入内存的第一个文本。


              IP属地:福建7楼2023-09-10 03:51
              回复
                这个函数的作用,便是在取回宝可梦时,显示宝可梦的等级Lv符号。而这个窗口,仅在存入两只宝可梦的时候才会显示。只有1只宝可梦时,并不会出现这个窗口,而是直接归还宝可梦。这也应证了前面提到的bug的触发条件必须是已经存入了两只宝可梦后才会出现。


                IP属地:福建8楼2023-09-10 03:51
                回复
                  2026-01-01 05:11:28
                  广告
                  不感兴趣
                  开通SVIP免广告
                  在反编译函数里,还有一个细节,提到当版本不为1.0时,调用的是StringCopy(lvlText, gText_Lv);函数,而不是strcpy。我们可以看一下StringCopy函数的内容。

                  可以发现StringCopy同样也是拷贝文本编码,但区别在于停止的识别符是0xFF,而0xFF正是宝可梦3代游戏里,文本结束的标识符。而strcpy,还记得上面对指令的观察得到的结论吗,停止的识别符是0x00。这就是两个函数的最大区别。


                  IP属地:福建9楼2023-09-10 03:51
                  回复
                    至此,BUG产生的本质原因已经彻底明晰,问题在于strcpy函数的缺陷。程序为了显示两个宝可梦的信息窗口,本应只拷贝gText_Lv文本以显示lv符号,但却由于strcpy函数只有识别到0x00时停止,以至于将后面的文本也一同载入进了内存中,直到遇到了“Go ”里面的空格0x00才停了下来。而汉化版汉化之后0x00需要在非常后面才存在,致使strcpy读取数据超出原定大小造成内存溢出,从而引发卡死。


                    IP属地:福建10楼2023-09-10 03:51
                    回复
                      BUG的解决方法
                      在上述内容中,我们可以看到其实GF本身已经给出了一种解决办法,将strcpy函数替换为StringCopy函数。在火叶的v1.1版里已经更新为了这个函数。
                      而对于以火叶v1.0为基础的汉化,亦或改版汉化,可以采用如下方式进行修复。
                      通过观察gText_Lv到gText_GoBackToThePreviousMenu之间的文本,可以发现gUnknown_841623D[] = _("YES\nNO");这句文本最适合插入0x00的编码。
                      “Yes\nNo”对应的编码为 “D3 D9 E7 FE C8 E3 FF”总计7个字节
                      而汉字为双字节,翻译为“是\n否”时,正好空出1个字节的富余,对应编码为“0C 0C FE 03 F4 FF”总计6个字节。
                      那么多出来的那一个字节,就可以用来放置0x00,即“0C 0C FE 03 F4 FF”+“00”。
                      当然,也同样可以把空格塞入到文本内部中,如添加到“是”或“否”的后面,
                      “是 \n否”(“0C 0C 00 FE 03 F4 FF”)、“是\n否 ”(“0C 0C FE 03 F4 00 FF”)。
                      以上便是对于火红叶绿汉化中的培育屋BUG解析的全部内容,希望能对大家有所帮助。


                      IP属地:福建11楼2023-09-10 03:52
                      回复