GB/GBC汉化经验分享之十七--新的文本读取程序 心得研究

六级用户 RangerMarsh 17小时前 210

十七、新的文本读取程序


前面我们在查找文本指针的时候并没有关注文本的Bank号,如果后续还是在原来文本的位置修改,那可以不用管。但现在我们修改后的游戏中,码表会采用双字节,原来的位置肯定是放不下这些文本的,我们需要想办法把文本放到新的地方去,所以还需要看一下游戏里文本的Bank号是如何读取出来的。

前面在分析文本输出程序时,我们已经知道游戏是在0:34A1这里调用程序0:3786来实现文字输出,在这里设置断点

17-01.png

可以看到在调用这个程序时,Bank号已经是D,所以要往前去找Bank D是从哪里读出来的。

找到0:3CD0这里,从D86A读出的0D

17-02.png

接下来看什么时候往D86A写入0D,找到了程序3CB40D写入D86A

17-03.png

它根据D8B6D8B7保存的文本指针(第14节分析过),判断该文本属于哪一个Bank。所以如果我们把文本放到了其他的Bank,需要对D86A的值进行修改以保证读取的是正确的文本。

接下来我们就开始修改程序。这里尽量把程序拆分成一个一个子程序,这样后面汉化其他游戏时,只要单独去修改个别的程序就好。

修改后的游戏中,码表采用双字节,第一个字节表示Bank号信息,第二个字节表示在该Bank中的位置,新的字库放在Bank 11-17,对应的第一个字节编码分别是31-37。(注意一下因为我还想保留原来的日文输出程序,所以把判断的编码改成了40以下,也就是原来对应短语的那部分编码,反正也不需要输出短语了。)

新的文本会放在Bank 18-19,对应关系为原Bank D的文本放到Bank 18,原Bank E的文本放到 Bank 19Bank 10用于放新增加的程序。

首先把下面这两处做如下修改

0:3364

cp   a,21

 

0:378A

cp   a,21

 

原程序为与40作比较,若小于40就跳转到输出短语的程序。这里修改后,对于21-40之间编码就不会跳转,会继续向下运行到读取文本的程序。

与之对应的,原来Bank 0上原来用于存放短语的0:3F72-0:3FFF这一部分也不需要了,把这里的内容删除,后续可以在这里写新增加的程序。

将原来对浊音进行判断的程序做如下修改,当读到21-40之间的值时会跳到WriteCH这里去运行新的程序

0:37B0

cp   a,40

jp   c, WriteCH

 

注意在实际修改时,要把WriteCH换成该程序的地址(这里如下方所示,应该是3F72)。

当前的程序是在Bank 0上的,所以我们在Bank 0上找一个空的地方增加一段程序WriteCH。大部分时候Bank 0上可用的空间都非常少,这里我们也是删除了一部分不用的内容才腾出了一些空间。所以这里我们只放跳转的程序,当读取到对应的代码后就跳转到Bank 10中去执行大字文本读取输出的程序

0:3F72

WriteCH:

push af

push hl

ld   a,10

call 2A21

pop  hl

pop  af

call JudgeCode

push af

push hl

call 2A30

pop  hl

pop  af

jp   37BF

 

这里切换Bank利用了原来程序的0:2A21(切换到新Bank)和0:2A30(切换回原Bank)。注意切换到新的Bank要先指定Bank号,所以这里先给a赋值10。切换回原来的Bank则不需要,程序会把之前保存Bank号取回来。完成大字输出后,跳回到0:37BF,也就是之前我们分析出来的原程序写完小字的位置。

接下来我们就在Bank 10上来写新的程序JudgeCode

因为有一些参数需要暂时保存,我们在WRAM中找一块没有被使用的区域,用于保存这些参数,这里选择DA00开始的这一段。

Bank 104000这里增加一段程序JudgeCode,这个程序的目的主要是通过判断当前读到的代码或者其它参数,来决定后续采用哪一种文本输出方式,可以看作是前面的程序WriteCH的补充,也为后面增加其它的文本输出方式留下冗余。

这里我们引入了两个控制符3839来解决原来文本长度不够放新的文本的问题。38是跳转到新的地址去读写(JumpOut),39是跳回原来的地址去读写(JumpIn)。如果都不是的话,就是正常的文本,则把当前读到的第一个代码(字库Bank号)保存在DA01,然后读出下一个代码,再调用正式的文本读写程序。

10:4000

JudgeCode:

cp a,38

jr z,JumpOut

cp a,39

jr z,JumpIn

ld (DA01),a

call ReadText

call WriteLarge

ret

 

下面这一段程序是用来实现文本跳转的。翻译文本时,把原来文本的前3个字节修改为“38+“双字节地址”,这里双字节地址对应新的Bank中文本的初始地址。当读到38跳转到这里时,先调用程序GetAddr把紧接在38后面的地址读出来放到hl,然后把切换前的Bank号(保存在C0C2)暂存在DA00,并计算出新的文本的Bank号(这里是加0B)保存在D86AC0C2,这样后面就切换到新的文本Bank去读文本。在新的文本的结尾增加3个字节,“39+“双字节地址”,这里双字节地址对应原来这一段文本结尾的控制代码地址。当读到39跳转到这里时,也是先调用程序GetAddr把紧接在39后面的地址读出来放到hl,然后从DA00取回原来的Bank号,放到D86AC0C2,使得再切换Bank时会回到原先的Bank。由于这两步操作实际上都没有写文本,所以要提前给b1,给e1,以抵消后面程序对be的操作

10:4400

JumpOut:

call GetAddr

ld a,(C0C2)

ld (DA00),a

add a,0B

jr JudgeEnd

JumpIn:

call GetAddr

ld a,(DA00)

JudgeEnd:

ld (D86A),a

ld (C0C2),a

inc b

dec e

ret

 

GetAddr这个程序是用来读取38或者39后面接的地址。调用程序ReadText读出这两个字节保存到hl

10:40A0

GetAddr:

call ReadText

push af

call ReadText

ld l,a

pop af

ld h,a

ret

 

ReadText这个程序是新增加的用来读取文本的程序,因为这里涉及到切换Bank的操作,最好放在Bank 0上,从C0C2读取需要切换的Bank号,调用0:2A21切换Bank,读出hl上的编码,给hl1,再切换回去

0:3F88

ReadText:

ld a,(C0C2)

push hl

call 2A21

pop hl

ldi a,(hl)

push af

push hl

call 2A30

pop hl

pop af

ret

 

这样我们就完成了新的文本读取的工作。

要注意到原先的主程序0:3786读出来的始终是Bank号(31-37)或者控制符(3839),这样原来的文本编码或控制符是不会进入我们的文本读写程序的。并且我们只在读取文本时跳转到新的Bank,对于控制符还是在原来的Bank上操作,也减少了出错的可能。

JudgeCode这个程序中还可以引入更多的判断语句,来实现不同的文本输出方式。比如对于道具武器的处理,以及命名界面小字的处理。

这种方式也有一个弊端,那就是每段文本的长度至少得有3个字节。对于少于3个字节的就要特殊处理。


上一篇:請問一下使用ClrMamePro來整理MAME的CHD疑問
下一篇:没了
最新回复 (2)
  • 三级用户 论坛大家弹 17小时前
    0 2
    不懂,但觉得牛逼,帮顶
  • 五级用户 shn 10小时前
    0 3
    感谢大佬分享。等我看懂了就去搞那个中文的合卡菜单
    • 老男人游戏网配套论坛
      4
        立即登录 立即注册
发新帖
本论坛禁止发布SWITCH和PS4相关资源,若有其他侵权内容,请致邮3360342659#qq.com(#替换成@)删除。