简单入门Z80汇编,学习GB/GBC汉化

  • 要是有想学习Z80汇编,做汉化又或者做游戏修改。但是又找不到入口的,可以耐心看下。不过我自己也是半桶水,或者有写错的,请指出,我做修改。

    学习GBC汉化是要有耐心的,基本靠自己去学,去理解,去写汇编,然后你才会慢慢深入了解。

    汇编基本都是靠我自己的理解去定义的,说实话我并不知道汇编里面原来的英文是什么,即便是知道我也看不懂,所以我就自己去定义这个汇编是干嘛用。

    但是GBC的设计资料还是要有的,但是一开始就去看那玩意,也很难上手。

    所以呢详细的资料后续再去补,现在就不看。

    我就说说简单的几样,首先我们需要一个BGB模拟器。BGB模拟器汉化版 或者 BGB官网

    首先是寄存器,寄存器就是用来临时存放数值,然后加减乘除运算或者不运算写入到工作内存。

    731-2017-09-09-114802-png

    GB/GBC寄存器总共6个,A,BC,DE,HL,SP,PC,但是一般能用的就是A,BC,DE,HL ,

    SP是栈,PC就是当前CPU运行到的位置。但是在复杂的程序上,可以对栈进行加减操作。

    所谓栈就是用来临时保存寄存器数值的玩意。


    内存呢就是 可以读取写入 数据 的玩意,分为电池存档部分的叫SRAM,地址范围是A000~BFFF。

    跟用来工作用的部分叫WRAM,地址范围是C000~DFFF。还有别的,现在先不说,说太多也不好消化。

    733-2017-09-09-133021-png734-2017-09-09-133042-png

    当然电池存档部分的内存也可以当做工作内存来使用,因为都有共通一个特性,可读可写。SRAM关闭情况下显示全是FF数值。

    但是GB/GBC的设计一般是存档部分通常是需要用到的时候才去打开来使用,不使用的时候就把他关掉,这样存档就会比较安全。


    这里我就说说几种比较常见的汇编指令。


    LD XX,XX ----载入数值用,譬如说LD A,50,就是将数值50载入到寄存器A,LD B,A就是将寄存器A的数值载入到寄存器B,等于是复制黏贴过去。

    LD XX,(XX) ----这种带括号的,其实就是引用括号里面的寄存器上的数值。譬如说 LD A,(HL),当前HL寄存器的数值是5010,

    那么这条指令就是 将地址5010上的数值载入到寄存器A。反过来LD (HL),A,当前HL寄存器数值是C120,那么就是将A的数值载入到地址C120。

    LDI A,(HL) 和 LDI (HL),A 等于是 读取/写入之后寄存器+1,

    譬如说 LD A,(HL) HL寄存器数值是6130,那么运行之后HL的数值就变成6131。


    CP XX,XX ----对比用指令,譬如说CP A,50,用A的数值跟A来对比,要是符合50就激活F标志位。

    CP XX ----这种对比指令相当于A寄存器跟XX做对比,譬如说CP B,运算方式就是寄存器A跟寄存器B的数值相减。

    (F标志有四种,就是寄存器上右边四个,Z,N,H,C ,)

    说对比,实际就是做减法操作,但是数值就不保留,激活F标志位,譬如说CP A,50,实际上就是 寄存器A的数值减去50,结果分三种。正数,零,负数。

    然后根据标志位上的去定段,标志位上的Z就是ZERO,为零激活,N就是NOT,就是否,C就是溢出,负数激活。


    JR XXXX ---跳转指令,跟JP差不多,但是只能短距离跳转。

    JP XXXX ---跳转指令,可以长距离跳转。

    譬如说JR 1050 ,JP 1050 ,就是跳转到1050。带标志位的一般都是跟CP配套使用。带标志位指令就是JR Z,XXXX ,JR C,XXXX。要将条件反过来就是JR NC,XXXX。

    配套使用的话,譬如说

    CP A,30

    JR Z,1650

    先是寄存器A跟30相减,要是得出的结果是零的话,跳转就生效,否则无视。


    ADD XX,XX ---- 加法指令,譬如说ADD A,将寄存器A跟寄存器A的数值相加。ADD A,50,将寄存器A的数值加50。

    SUB XX,XX ---- 减法指令,用法跟加一样。

    INC XX ---- 这个也是加法指令,不同的是这个一般用在寄存器上的加减,而且是只加一。譬如说INC A,寄存器A的数值+1,INC DE,寄存器DE的数值加一。

    DEC XX ----这个是减法指令,用法跟加一样。


    CALL XXXX ---- 这个就用来调用子程序的,具体是将当前PC位置数值+3之后压入栈,然后去运行子程序,等运行到返回指令的时候就弹出栈的数值回到PC的位置。

    RET ---- 这个通常就是用来调用子程序之后返回用。

    譬如说 CALL 1520 ,当前PC的数值是 3260,程序会将当前PC的数值3260+3之后压入到栈,然后跳转到1520的位置。

    当程序运行到RET之后,就自动跳转回3263的位置。至于为什么是+3呢,我猜应该是 CALL XXXX的指令占用三个字节的机器码位置吧。


    PUSH XX ----这个就是压入栈的指令,压入栈说得好理解就是,把数值保存到栈的位置。

    POP XX ----这个是弹出栈的指令,弹出栈就是把当前栈位置上的数值恢复到寄存器上。

    譬如说PUSH BC,BC的数值是 1620,SP是CF00,

    那么这个1620就会保存到SP数值CF00的位置上,当你弹出栈的时候这个数值就会恢复到寄存器的位置上。


    好了那么,可以把这些指令全写一遍上去,BGB模拟器按F7就可以一步一步的运行,然后观察,就很好理解了。

    732-2017-09-09-132203-png

    捣鼓完一些简单的代码之后,就可以开始着手汇编了,学会看游戏程序的汇编指令,可以拿一些游戏来开刀。

    可以简单做HACK开始上手。最初我也是做HACK上手汇编的。顺便还可以熟悉BGB的一些使用方法。

  • 首先熟悉BGB的操作,从搜索金手指开始,到设置断点,看汇编,以及修改。

    首先是搜索金手指,明显有数值的就按照数值去搜索就好了,

    735-2017-09-09-233925-png

    点击开始,初始化一下金手指搜索器,然后输入十六进制的数值进去。就可以搜索到了。

    然后就可以转到这个金手指位置在调试器里面显示出来。这样就方便查看附近的一些数值。

    736-2017-09-09-234548-jpg

    把这个数值输入到金手指列表里面看看是否搜索对了。

    738-2017-09-09-235041-jpg

    输入好金手指之后,启用他,发现时间已经不减了。那么这个就是时间的金手指,所以就在这个地址上设置断点。

    737-2017-09-09-235334-jpg

    设置断点的方式有四种,读取 就是当程序读取这个地址的时候才发生断点,写入 就是当这个地址发生写入就发生断点,

    执行就是执行到这个地址就断点,跳转就是当跳转到这个地址的时候才发生断点。

    因为现在是要看是谁在修改了这个地址,所以就看写入的,设置断点之后,看到汇编程序。

    740-2017-09-10-000140-jpg

    很明显,程序将C20A上的数值读取出来然后减一,再写回去C20A,

    LDI XX,XX是LD XX,XX的变种,等于是LD XX,XX之后再INC HL,HL寄存器加一。LDD XX,XX就是反过来,HL减一。

    所以呢,就可以把这个指令稍作修改。

    SUB A,01改成SUB A,00 或者 干脆删掉不做修改,直接将原来的数值写回去。这样就可以得到时间不减的修改效果。

    而另外一种金手指搜索就是模糊搜索,用在一些看不到数值的身上,譬如说HP血条之类的。

    741-2017-09-10-001908-png

    首先点击开始初始化一下搜索器,然后去受点伤害HP条减少再搜索。小于以前的数值就好了。

    743-2017-09-10-002546-png

    转到调试器对应这两个数值观察就可以看到C2A2就是HP的金手指。

    那么断点HP的地址,再去受点伤害,就可以看到汇编程序。

    744-2017-09-10-002912-jpg

    LD HL,C2A2 载入C2A2数值到HL寄存器

    JR 1070 跳转到1070

    LD HL,C2AC 载入C2AC数值到HL寄存器

    LD C,A 寄存器A数值载入到寄存器C,(这里就是1070的位置)

    LD A,(HL) 读取寄存器HL地址上的数值到寄存器A

    SUB C 寄存器A跟寄存器C的数值相减

    LDI (HL),A 将寄存器A的数值写入到寄存器HL上的地址,并且HL+1

    LD A,(HL)

    SBC A,00 寄存器A减去00,(SBC是带进位的减法指令)

    LD (HL),A

    RET NC RET变种,等于符合NC标志就激活RET返回到程序

    XOR A 异或,计算方式就是A跟A异或,结果就是零。

    LDD (HL),A

    LD (HL),A

    RET

    很明显这一串的指令就是,读取C2A2上的数值,然后将所需要受到伤害的数值写入到C,然后相减,将结果写回去。

  • 然后简单的汇编就是这样去看程序,并且理解。要是要做游戏汉化的话,就是需要学习GBC设计上的另外一些知识。

    首先GBC多半都是以8*8的小点阵来显示文字的,但是8*8的小汉字。

    在显示上很不好看,所以就需要修改程序去实现大字体显示。

    原理就是四个8*8拼接在一起,等于是16*16。

    首先你需要一些工具,譬如说CT,这样的可以用来查看图片数据,字库也属于图片。

    但是日语只有50音,英文大小写只有52个字母,

    原来存放字库的位置实在是太小,所以需要扩容字库,把字库做在新的空白地址上。

    但是由于原来的rom一般情况下或许会出现空白的位置不够,所以就需要扩容rom本体。

    扩容rom本体,神奇误差有专门的工具,也可以使用普通的方式来扩容,譬如说CT自带的。

    GBC ROM的扩容资料

    745-2017-09-10-005725-jpg

    746-2017-09-10-005939-jpg

    但是要注意的是,一般GBC ROM都是整数方式的。

    譬如说 128K 256K 512K 1M 2M 4M 8M,目前rom是1M的话就扩容1M进去。最终rom就是2M大小了。

    那么首先说说GBC的设计,GBC都是以BANK来访问rom的。

    以常见卡带芯片(MBC1 2 3 5)为例子ROM0:0000~3FFF这个位置固定,

    后面所有数据都是以ROM1 ROM2 ROM3 来分块访问,

    所以就要切换BANK,其中ROM0是固定的,ROM1往后的就是随意切换。

    也就是说,你要访问8000这个位置的内容,你就要切换BANK到ROM2。

    然后我这里有一张自己整理的图片可作参考。

    747-gbc-rom-png

  • 对于汉化来说,你需要找到两样东西,第一是码表,第二是字库。

    字库可以直接用于写日文码表,而原来的字库并没有什么用的。

    码表用于呈现文本的内容,并加以导出。字库用于显示于屏幕上。

    GBC的设计就是先把字库的数据写入到TILE,然后再按编号分配到MAP,从而屏幕上显示得到内容。

    首先关于字库的查找。这里有两种方法,第一打开CT直接往下拉一个一个TILE查看。

    第二,BGB设置断点,看汇编程序,到底是在哪个位置把字库数据写到TILE的。

    找到字库之后,就可以按照字库日文的排序方式写出码表。

    然后把码表启用到rom里面就可以看到文本了。(要是文本没压缩或者加密的话)

    753-2017-09-10-022802-jpg

  • 首先关于字库的断点查找。就是直接在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跟蓝山魔导工具。

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

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

    764-2017-09-10-092219-jpg

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

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

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

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

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

  • 首先关于字库的制作,可以制作成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 第一个句子的指针补上去。

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

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

    点击转到位置。

    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号信息。

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

    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号。

  • 很简单,给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中断设计

  • 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翻转,调色板之类的。

  • 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。

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

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

    803-2017-09-10-152108-jpg

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

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

    804-2017-09-10-152311-jpg

    运行这段程序之后,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编号指针的偏移之类的。

  • 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这边的指针只递增了一位,所以这里要改成递增两位。

  • 在这里,可以逐步运行刚才所写一连串的程序,可以找到,主要分配出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

    教程到这里就完成了。

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

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

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

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

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

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

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

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

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

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

Join us

Have your own thoughts on this discussion? Wanna help others, avoid the mistakes you met before? Wanna contribute more to this or other topic? Just join us! Registration is free. Join us!