Posts by Mezaransu

    我找到字库是从00018000开始,但是我怎么找他在ROM记录的指针地址?

    他的[菜单]内容和[对话]内容应该是分开,所以我想修改菜单的字库地址到其他地方,

    怎么用BGB操作?还是说CT就可以?

    CT只能用来借助查看字库跟制作字库。

    要修改字库开始地址就必须给TILE打断点找出相关的写显程序

    然后分析。就知道了。

    会Z80汇编的话,就很简单。

    所以想汉化GBC就从学习Z80汇编开始。

    先打开TILE看看是静态菜单还是动态菜单字库。

    动态的话 一般都是找文本 替换字库 修改文本

    静态的话 可以改掉整个字库 再慢慢对着TILE修改MAP。


    实际上有很多功能我自己都没用过,也不知道是怎样的。

    所以放置了很多没翻译的,并且我英文也不怎样基本是靠百度查词典。

    因为平时自己经常用这模拟器做调试,所以就做了个汉化。

    bgb1.5.6 CHS.zip

    836-2017-09-20-094019-png

    最后,当程序将要运行01AA:RET时候,观察栈对应的位置。就是指向目标地址。

    837-2017-09-20-094239-png

    到这里,证明已经可以成功远程到BANK20:6540地址上的位置了。而且栈的位置也刚好在CFFB上,也就是01AB上面。

    那么只要当程序运行到RET指令,就会返回到01AB的程序上。继续执行一系列后续操作。返回到原位置上。

    838-2017-09-20-094736-png

    然后写下压入弹出栈操作指令观察,是否会破坏返回必要用到的重要信息。

    运行之后发现,在压入栈之后,只会覆盖掉一些没用的临时数据,事实证明,远程程序是成功了。

    839-2017-09-20-095113-png

    那么现在就继续运行到RET看是否能回到01AB的位置上。

    842-2017-09-20-095405-png

    然后现在,只需要把存放在栈里面的BANK号取出来,然后就可以成功切换回原来的地址上了。

    方法还是那样把栈+一个偏移的位置载入到寄存器上,然后读取出来,切换BANK,最终栈的寄存器数值调整到需要弹出返回到原地址的目标上即可。

    843-2017-09-20-095944-png

    成功回到原地址上,远程调用完成。

    844-2017-09-20-100325-png

    首先,在了解GBC设计之后,在普通的卡带芯片下,HOMEBANK固定地址0000-3FFF,不可切换,

    且大部分游戏都比较缺少空白的HOMEBANK位置,因此,大部分时候,就需要用到一种方法,就是远程调用。

    也就是说在当前BANK的位置上远程调用其他BANK的内容,然后回到原程序的对应位置上。譬如说在BANK 10:5230的位置上调用BANK:20:6540的程序。

    远程调用程序的原理,实际上就是在调用这个远程程序的时候读取位置上的某些信息(目标的地址已经BANK号),然后把当前位置已经BANK号堆放在栈里面,

    等调用完之后返回的时候,写回当前BANK的位置上。但是在运行远程调用程序的前后,A BC DE HL的数值不能改变。

    首先,在HOMEBANK的某一处地方写下远程调用的程序。

    822-2017-09-20-083640-png

    然后,在调用这个程序的时候,后面写上必要的信息。

    825-2017-09-20-085214-png

    这里的CALL 0180后面三个字节的信息,就是需要远程目标的位置。并不是程序。

    首先,CALL的原理就是将当前位置PC+3压入栈,然后当运行到RET之后,就返回到弹出栈的位置上。

    那么现在开始分析远程调用的程序。

    826-2017-09-20-085254-jpg

    首先CALL之后会压入5233的位置到栈。

    然后再给栈偏移一个数值,将必要的数据(原BANK号,已经位置信息),保存在栈的中间,

    因为这里的压入弹出栈的数据都只作一个临时存放,所以就要放到重要信息后面。

    827-2017-09-20-090425-jpg

    那么,现在就开始整理一系列的数据。

    首先就是要把原地址5233再+3,因为刚才在CALL远程程序的时候有三个字节不是程序的,所以返回的时候就需要跳过这三个字节。

    828-2017-09-20-090942-jpg

    那么首先将栈偏移一个数值载入到HL寄存器,读取数值+3之后写回去。

    顺便要把这个数值5233载入到寄存器里面。因为还要读取这个地址后面的远程目标信息。

    830-2017-09-20-091508-jpg

    5233成功转变成5236。

    然后载入栈+一个偏移的数值,让HL寄存器定位回到刚才隔空的位置上。

    然后读取5236上的目标地址数值写入到栈空白位置上。

    为什么要写到栈?因为当运行到RET之后,原理就是程序恢复到弹出这个栈的数值地址上。

    831-2017-09-20-092433-jpg

    目标地址6540成功写到栈位置上。

    接下来就要,写入一个对应的数值,让调用完毕之后返回到HOMEBANK一个程序地址上,让这个程序切换回原来BANK号已经地址。

    832-2017-09-20-092804-png

    833-2017-09-20-092838-png

    将01AB程序的地址,写到栈。

    然后再将当前BANK号写入到栈。

    834-2017-09-20-093121-png

    由于每个游戏设计都不同,有些游戏是用一个地址来保存当前BANK号,一般是存放在HRAM的某个地址上。

    有些就是在每个BANK的第一个字节上记录着BANK号。这个展示的就是这种每个BANK记录着BANK号信息的。

    那么最后一步就是切换目标BANK了。相继弹出恢复刚才压入的三个寄存器上的数值。

    关于GB/GBC的机能限制比较多,常常会出现TILE不够等情况,

    所以在熟悉汇编之后的情况下可以考虑把8*8改成12*12的汉字大小,但是12*12在程序处理上会相对复杂很多,

    因为其中需要把汉字拆分以及合并来处理。

    虽然说汉化这个坑越踩越深,但是能汉化到自己喜欢的游戏也是一件好事。

    至少我把怪兽胶囊做了,也算是完成了我毕生的一个愿望。

    同时也希望大家可以多学习汇编能够汉化出自己心目中的游戏。

    这个教程也就写给大家,可以简单理解并熟悉汉化改大字的一些步骤,以及单色字库的写入方式。

    记得当初我做单色字库写到TILE的时候捣鼓几个小时都不知道是什么原因。

    在毫无头绪的情况下,希望这教程可以帮得到你。

    感谢观看,有错请指出,谢谢。

    在这里,可以逐步运行刚才所写一连串的程序,可以找到,主要分配出9957的程序。

    816-2017-09-10-164430-jpg

    那么可以得知,主要影响这个指针的就是FF88跟FF89了。但是FF88跟FF89在这里都是一个临时存放点,

    需要找到主要的位置才行。

    817-2017-09-10-165046-jpg

    继续查找

    819-2017-09-10-165328-jpg

    然后可以找到,这里就是给指针增加一位的程序。

    820-2017-09-10-165637-jpg

    改完之后在重新试验一下。

    821-2017-09-10-170258-jpg

    教程到这里就完成了。

    813-2017-09-10-161715-jpg

    当写第二个字的TILE的时候,写在了第一个字的第二个8*8上,这时候就需要把原本指针递增一位的,递增到4位。

    上面程序中FF89就是读取指针的开始计算出DE位置。那么只需要把FF89打上断点进行查找。

    814-2017-09-10-162119-jpg首先第二个指针CB是根据CAA0来写入的,那么继续查找CAA0。发现第二个指针就是出现在这里写入的。

    当程序运行到7F0F的时候,INC A,指针加一,写入到CAA0。

    815-2017-09-10-162728-jpg

    把指针改成加4之后,写第二个字的TILE时候已经不会发生重叠了。

    但是屏幕上还是发生了重叠,很明显,这回就是写第二个汉字MAP这边的指针只递增了一位,所以这里要改成递增两位。

    写完TILE之后,回到分配MAP的程序上。

    805-2017-09-10-152951-jpg

    发现,分配MAP的程序就在隔壁,所以直接整合进去就好了,不需要再去另外写跳板在HOMEBANK。

    那么直接去到TILE写完即将回到主程序上的地方。

    首先把CALL 2594删掉,

    806-2017-09-10-153243-jpg

    没错,就是在这个程序上改造。

    807-2017-09-10-153443-jpg

    调用程序,到7F80。把原来的CALL 2594上的程序 复制下来。

    808-2017-09-10-153827-jpg

    然后再把2131的程序复制下来。进行改造。原本只写一个TILE编号的。现在就要写4个。

    810-2017-09-10-154659-jpg

    当程序运行到7FE9的时候,看寄存器上的A,就是将要写入的TILE编号。HL就是需要写入的位置。

    811-2017-09-10-154931-jpg

    查看MAP这边就可以知道,9957这个位置输入大字的下半部分,但是入口CA是大字的上半部分,

    所以呢,需要先把9957的位置偏移到9937。

    由于程序写太开了,所以后面位置不太够,可以在上面空白的地方去找。

    812-2017-09-10-160018-jpg

    要将9957-20通常都是以加的方式来做到的。加FFE0其实就是-20,加FFC0其实就是-40。

    那么这里经过简单分配,第一个字是显示出来了,后续就是一些TILE编号指针的偏移之类的。

    到了这里,就是重要的TILE写入了,由于GBC的设计,VRAM并不是随时都可以写入的,

    所以需要判定在可以写TILE的情况下才能写屏。这是设计资料LCD状态

    803-2017-09-10-152108-jpg

    首先关中断,判断VRAM是否可写,不可写则循环,等待可写时候通过。

    读取一字节HL,写入两次,但是要注意的是,VRAM在判定通过之后就要尽快写入操作,不然等下又不能写了。

    804-2017-09-10-152311-jpg

    运行这段程序之后,TILE上立马可以看到这个字了。

    然后,就可以进入MAP分配环节。

    791-2017-09-10-133457-jpg

    这里要把原来处理清浊音的程序去掉,改成连续读取两个字节,分别存放到A B寄存器上。

    首先把第一套程序拆分一下,把多的部分写HOMEBANK以外。

    792-2017-09-10-135132-jpg

    这条新加入的汇编跟之前读取文本的有点像,就是先把当前BANK号读取出来保存到栈,

    然后取出B的数值,计算得出正确需要切换BANK号的数值。


    793-2017-09-10-135147-jpg

    这里把程序做拆分是因为需要把B数值转换成切换bank号位置。不拆分的话也行,但是要先把A压入栈。

    因为程序会最初会把A写入到FF88。


    先说说这里出现的两个汇编。

    第一个是AND A,XX 这种就是逻辑运算 与。详情百度百科 逻辑与

    但是这里需要用到的基本是两种

    AND A,F0 这个可以直接理解为取高位。譬如说 64 运算之后 结果 就是60,73运算之后就是70。

    AND A,0F 这个就是取低位。譬如说 64运算之后就是04,73运算之后就是03。

    具体可以打开WIN自带计算器运算一下。

    794-2017-09-10-140419-jpg


    第二个SWAP XX呢,简单来说就是高低互换,譬如说SWAP A,A的数值是 73,那么运算之后就是37。

    796-2017-09-10-141215-jpg

    首先第二套程序复制过来,调用它,当程序运行到7F33这里,FF89的数值CA已经转换成8CA0了。

    证明至今为止并没有出现任何问题。

    为了方便理解,首先转到这个字库所在的位置,再去看程序。

    798-2017-09-10-144635-jpg

    在CT找到这个字库的数据,转到ROM对应位置。

    程序需要读取FF88的文本计算得出5F00这个最终结果。

    那么在这里需要单步进行。按F7单步运行。

    799-2017-09-10-144735-jpg

    当程序运行到7F3F的时候HL=09D0,刚好是13A0的一半,很显然,这里只需要把HL * 2就可以了。

    乘以二,也就是 XX*2=XX+XX,那么就是ADD HL,HL,把HL跟HL相加就可以了。

    但是这里又因为一个BANK存在两套码位,第一套是4000开始的,第二套就是5E20开始的。

    800-2017-09-10-145945-jpg

    当第一个字节码位是61的时候就采用4000的数值相加,当码位是62的时候就采用5E20的数值来相加。

    801-2017-09-10-150306-jpg

    当程序运行到7F50的时候,DE,HL都正确,剩下就是读取字库数据写入到TILE了。

    看原第三套程序里面,A在里面只是用来切换BANK写字库,但是我这里已经不需要切BANK了,当前BANK就是字库BANK。

    所以LD A,42可以删掉不要,原程序每写完一个字节到TILE就会减去一个C,证明,C就是循环的次数。

    前面我有提到过GB 2BPP色的字库,是读一写一,单色是1BPP就是读1写2。

    简单来说,GB 2BPP 原来一个8*8就是 读16个字节写16个字节,要是GB 2BPP的16*16的话就是读64写64 ,

    由于这里做的是单色1BPP 所以就是 读32写64。所以就是LD C,20。

    789-2017-09-10-130932-jpg

    这里我说一下GB/GBC的VRAM设计,在VRAM设计上GB跟GBC的不太一样。

    TILE主要分6大块,其中左边三块为GB或者GB共通使用,右边三大块只能在GBC专用游戏上使用。

    然后呢三大块中的一大块,会被设计成OAM,剩余两大块就设计成一般使用的TILE分配到MAP上面。

    等于要实现屏幕上的显示,就必须写完TILE上的8*8格子,然后这些格子的TILE编号就分配到MAP上。

    790-2017-09-10-131658-jpg

    GBC的显示设计

    等于是先把数据写到8A60,然后再把8A60对应的编号A6写到MAP地址98F7。

    这很好理解,但是要深入研究的话,还需要知道怎么设置优先级,XY翻转,调色板之类的。

    很简单,给C99E上断点就知道是哪个程序在读取它来处理。

    785-2017-09-10-123154-jpg

    首先读取C99B 跟C99C指针在DE寄存器上。

    然后读取第一个字节处理清浊音,再读取第二个字节CALL 25DA写TILE字库,CALL2594分配TILE编号到MAP。

    把程序复制出来,每个字库BANK放上同一个程序,在同一个位置上,这样HOMEBANK上的主跳板就会调用到程序了。

    首先我把一连串写TILE的程序贴上来。

    786-2017-09-10-125121-jpg

    由后续程序2103可以看出,这个FF89主要就是存放TILE编号指针的。FF88就是文本的编码内容。


    787-2017-09-10-125213-jpg

    FF89计算出DE,FF88计算出HL。DE是TILE所在位置,HL是字库所在位置。


    788-2017-09-10-125231-jpg

    这个就是关中断写字库数据到TILE了。写完再开中断回来。

    GBC设计上VBLANK会产生中断,所以某些游戏写屏时候会预先关掉中断。

    这个就需要学习更多的GBC设计知识了,一般来说,程序原来是怎样的就参照着来写就可以了。

    详情参照PANDOCS的GBC中断设计

    那么回到刚才读取文本的程序,就可以看到。程序在读取的就是我修改过的文本。

    781-2017-09-10-112926-jpg

    确认刚才的修改没问题之后就可以开始修改读取文本的程序了。

    首先把整套CALL 23FE的程序复制出来,因为一般来说修改原程序很容易造成BUG的发生,

    因为有可能不止是读取文本用到这个程序,有可能其他会用到这个程序。

    因为GBC的设计,MBC5的卡带ROM0:0000-3FFF的内容是固定的称之为HOMEBANK。

    所以一般来说,多个BANK在下面切换时候你都需要调用HOMEBANK的程序。所以这类程序可以写在HOMEBANK上。

    但是也可以反过来,在HOMEBANK上去调用多个其他BANK上的程序,但是这样的方式只能调用,程序的位置要相同。

    譬如说,在HOMEBANK上CALL 5010上的程序。

    你多个BANK上的程序都必须在5010的位置上,不然的话HOMEBANK的跳板都要写多个CALL来调用。

    这里可以利用他原来的切BANK程序,在HOMEBANK写出跳板。

    782-2017-09-10-114656-jpg

    首先读取当前BANK号,压入栈保存起来,读取C99A就是文本当前BANK,切换BANK去调用读取文本的程序,

    后面就弹出栈,切换回原来的BANK位置。返回到程序。很好理解。

    这里需要注意的是我这样写都是为了方便这个教程,一般来说BANK号还是另外找个非常安全的地方保存起来会比较好。

    首先观察一些这一套读取文本的程序,文本读取之后,就会CALL 2535

    具体看看2535是干嘛的。

    783-2017-09-10-115737-jpg

    可以看到程序读取文本之后并不会一下子就计算字库文字,写屏,而是先存放起来,读取完一批再去处理。

    经过一番思考可以得出,原程序中A是文本正文处理,B是清浊音处理。

    这里可以刚好利用这个把BANK号直接写进去。因为后续文本压根就不需要清浊音了。

    784-2017-09-10-121120-jpg

    首先读取第一个字节判定是不是控制符,是的话就跳过读取第二个字节,直接处理掉,

    要不是控制符的话,就把这个BANK号写到B,读取第二个字节。

    最终这个结果会写到所在的内存当中。

    然后把处理清浊音的程序删掉。换成处理bank号。切换到所需字库bank号。

    那么现在就需要找出读取文本的程序,把他改成双字节适用的程序。

    因为文本已经找到了,所以可以使用断点的方式直接就可以看到读取文本的程序。

    点击转到位置。

    771-2017-09-10-110001-jpg

    可以看到这一段刚才的文本。

    772-2017-09-10-110110-jpg

    同时也需要把程序指向新导入文本的BANK号以及指针堆的位置。

    774-2017-09-10-110755-jpg

    首先设置文本读取断点,程序一读取这个文本就会发生断点。

    然后就一直返回到主程序上。修改整套程序。

    775-2017-09-10-111024-jpg


    776-2017-09-10-111053-jpg


    777-2017-09-10-111116-jpg


    从这一套程序中可以看出。程序是读取HL上的地址作为文本内容,读取C99A作为BANK号。

    CALL 0AED就是来回切换BANK的一个子程序。


    那么就需要在C998,C99A上打断点看原是哪里存放着BANK号以及总指针入口的。

    778-2017-09-10-111851-jpg

    经过一层一层的反复往上追踪发现,游戏在进入场景时候写入BANK号跟总体指针的数值到C2B3 C2B4 C2B5,

    原目标就是59FD -3,因为已经运行三个LDI了。

    779-2017-09-10-112133-jpg

    那么只需要把这三个字节改成所需的就可以了。

    新文本在ROM40,指针在6A50。那么就是

    780-2017-09-10-112451-jpg

    那么重新进去游戏,场景就会发现C2B3一列已经是所需要的指针BANK号信息。

    首先关于字库的制作,可以制作成GB 2BPP颜色,在程序上就是读1写1,也可以制作成单色1BPP字库,程序上就是读1写2。

    具体点阵写屏方式跟GBC设计有关,这里可以看看GB的显存资料

    现在看不懂显存资料也无所谓,反正有强大的CT可以做出字库。


    由于原本是单字节码表的,所以在改用双字节码表时候,需要用到一个方法,譬如说双字节码表上的第一个字节,可以用来计算字库所在的BANK号等信息。

    第二个字节就是计算具体字库的对应位置。因为一个BANK只做256个汉字有点浪费所以可以多做点,然后给他一个偏移就可以了。

    譬如说,一个汉字暗的编码是21 00,那么21中的2就计算出BANK号用,1就计算整体开头用,00就是计算字库具体位置用。

    就好像 21 的编码,把2取出来 计算出BANK号是 20,1取出来 计算出整体字库位置是 4000开始的。

    那么就可以按照这个思路去做汉字码表跟字库。

    制作字库时候要注意的是,16*16的字库数据需要设置成OBJ (H)或者OBJ (V),也就是水平重组跟垂直重组。

    至于为什么要重组,这个跟GBC显存设计和CT生成字库的方式有关。

    字库做完之后,就可以导一块文本进去,改指针试试效果。

    765-2017-09-10-094504-jpg

    然后刚才的文本也做修改,导到一块空白的地方去,原本的地方就不一定不够用的了,毕竟改了双字节。占位比较多。

    766-2017-09-10-100618-jpg

    找到文本译文中刚才的句子,改成中文。导回去游戏一个空白的地方。

    767-2017-09-10-100857-jpg

    通过修改文本中的信息,让蓝山的工具认为是这个地方导出来的文本,长度也是给他一个超长的长度,不然文本导进去有可能不全。

    768-2017-09-10-101257-jpg

    导入的时候,码表当然是用汉字码表,控制符也是按自己所需重新编辑一个,譬如说,全汉化的文本中都不需要清浊音了,所以留着也没用了。

    然后这里有一个字节填充的功能,其实就是当译文比原文短的时候,为了用空白字符去填充这块文本时候需要用到的。

    但是这个在这里是没用的,不需要填充,原因就是单字节改双字节的时候,整体文本指针都需要重写,空白填充是没有任何意义的。


    所谓指针,就是程序用来读取文本开头位置的数据堆。

    譬如说 一堆数据为 0040 1040 2040

    程序需要读取第二块文本,那么他就会计算到1040这个指针载入到寄存器去读取。文本内容的正文。

    指针一般在游戏中都是高低置换的,0040 就是 4000载入到寄存器。

    让你会使用高级电脑语言的时候就可以批量处理这些指针,不会的话就只能手写,又或者使用汇编。

    这里我推荐小白用汇编,这样也可以顺便熟悉汇编。

    文本中每段话开头紧接就是换页控制符,也就是说,你程序上识别到换页就把换页后面的指针保存下来。然后再稍作调整就好了。

    769-2017-09-10-104030-jpg

    然后把指针复制到ROM里面,这些临时的指针就没用的了。

    770-2017-09-10-104656-jpg

    把开头的0040 第一个句子的指针补上去。

    那么关于文本导出,上面提到蓝山的工具,就用蓝山吧,但是蓝山工具是多年前的产物,对WIN10这一类系统支持不太好,

    所以就只能在XP或者WIN7虚拟机,或者双系统的之类的使用。

    764-2017-09-10-092219-jpg

    首先把找到的这一段文本开头到结尾的地址写下来,然后其他参数自行调整一下。

    因为控制符存有双字节的编码,所以双字节优先比较好。其实控制符跟码表的码位没有重复的情况下怎么选都是一样的。

    然后就可以预览一下效果。文本导出就可以交到翻译手上了。

    然后剩下的,就是做字库。字库可以做全字库,也可以做只需要用到的字库进去。

    P.S.全字库占用位置比较多,但是比较适合游戏内植入拼音输入法之类的可以打出全简中汉字。

    首先关于字库的断点查找。就是直接在TILE上打断点。

    754-2017-09-10-082950-jpg

    很清楚可以看到,字库是由ROM20 的63A9写入到8D00。

    因为LDI,HL+1了。实际上是63A8。那么地址就是823A8,

    在CT上输入823A8。就可以看到整体的字库了,一般来说GBC游戏默认都是GB 2BPP就可以看到的,但是某些个别的是单色就要改为单色才能看到。

    755-2017-09-10-083555-jpg

    然后根据这块字库就可以写出这个游戏用的日文顺序。等确定好哪个日文采用哪个码位再给他定位。

    然后就是文本查找,文本查找方面需要用到相对搜索,因为目前并不知道码位,但是只知道游戏字库用的日文顺序。

    756-2017-09-10-084307-jpg

    用这个字库的顺序去搜索一段文本。

    757-2017-09-10-085109-jpg

    马上就看到这个在游戏中的码位。

    758-2017-09-10-085519-jpg

    然后给刚才写好的字库顺序去给上码位就可以了,M=70,C=66,一直往上往下推,就可以得到完整的码表。

    759-2017-09-10-085830-jpg

    导入刚才写好的码表。然后就可以去搜索刚才的句子。

    760-2017-09-10-090037-jpg

    现在就可以仔细去观察文本中一些没有用到的编码是干嘛的。

    761-2017-09-10-090334-jpg

    放在游戏中对比就知道。FE是换行,FF是换页,FC 01 就是清浊音符号。

    763-2017-09-10-091057-jpg

    然后就可以把主要的控制符先写下来,后续遇到的,再添加上去就可以了。

    至于为什么换行换页要用这两个符号,因为有面向小白的通用文本导出导入工具,常见的有死神的WQSG跟蓝山魔导工具。