FC游戏合卡ROM制作教程

本教程主要讲述Mapper52的合卡制作教程。

  1. 选择宿主游戏

Mapper52是Mapper4的合卡Mapper,为了实现菜单功能,需要选择一个合适的宿主游戏来插入菜单指令然后实现菜单功能。作为宿主游戏,这个游戏必须是TLROM(Mapper4)并且大小为256KB(128KPRG+128CHR)。下面我们以热血格斗传说(HERO FIGHT)为例进行讲解。

 

                                                     

2. 将宿主游戏的PRG和CHR进行扩容

为了操作方便专门开发了一个扩容还原的小工具,工具界面如下图:

                                                        

 

点扩容按钮,然后找到第一步选好的宿主游戏”HERO FIGHT.nes”,扩容完成后会在HERO FIGHT.nes所在的同文件夹下面生成扩容后的文件”扩容后_HERO FIGHT.nes”.操作完成后再用模拟器打开扩容后的文件,查看文件信息如下:  

                                               

 

扩容后的PRG和CHR都翻了一倍,游戏的大小变成了512KB(256PRG+256CHR).

3.寻找可以插入菜单指令的空白区域

宿主游戏必须有足够的空白区域来插入菜单指令。所谓的空白区域是指用十六进制编辑器打开ROM后连续的FF或者00的区域。注意:寻找空白区域一定要在扩容的区域找,PRG的扩容区域在ROM地址(不是PRG内存地址)的$020010~$040010区域,CHR的扩容区域在ROM内存的$060010~$080010区域。 下面是详细查找的方法:

 

3.1 菜单入口指令的区域

这段指令大概需要30h 字节的空白区域(用16进制编辑器查看大概是3行)。这段空白区域有个限制就是必须在PRG内存地址(不是ROM内存地址)的$C000~$FFFF区域找。以”HERO FIGHT.nes“为例,首先用FCEUX模拟器打开”扩容后_HERO FIGHT.nes“,然后从模拟器的菜单栏找到:调试->十六进制编辑器->查看->NES内存(也就是我们常说的PRG内存)。把滚动条拖到$C000~$FFFF找到有至少3行以上的FF空间,我喜欢从底部往上倒退着找,然后一下子就找到了适合的区域如下:

 

很明显$00FFA0~00FFCF这段区间符合我们的要求,搞定!

 

3.2菜单执行逻辑指令的PRG区域

这个区域大概需要600h 字节,并且要保证这600h字节都在同一个bank区域内。记住:一个TLROM(Mapper4)游戏PRG bank的大小是2000h字节。以” 扩容后_HERO FIGHT.nes”为例子:用FCEUX模拟器打开” 扩容后_HERO FIGHT.nes”, 然后从模拟器的菜单栏找到:调试->十六进制编辑器->查看->ROM文件(也就是我们常说的ROM内存),注意:上面已经说过,一定要在扩容的PRG区域($020010~$040010)找,找到的区域如下:

 

从$037880~$37E80(600h字节)这个区域都是连续的FF,正好符合我们的要求。

 

 

3.3. 菜单字模的CHR区域

    菜单用到的字模ascii.chr文件如下:

 

所以菜单的字模需要三行的空白区域。找菜单的空白区域同样需要在扩容区域找, CHR的扩容区域在ROM文件的$060010~$080010区域。以” 扩容后_HERO FIGHT.nes”为例,作步骤如下:

用字模工具YY-CHR打开” 扩容后_ HERO FIGHT.nes”,把进度条拖到$060010区域如下:

 

然后开始找至少三行以上的空白区域来插入菜单需要用到的那三行字模。使用YY-CHR这个软件可以使用键盘上的Pg-Up和Pg-Dn来上下翻页,这样每按下一次切换的是一整页方便后期的内存计算。查找之后发现从ROM地址$068010开始有足够的空白区域(CHR的空白区域只要是纯色的没有任何图案就可以,不一定是下图这样的)插入字模:

 

 

到此为止,菜单入口空白区域、PRG空白区域、CHR空白区域都已经找到,那么这个游戏就可以作为宿主游戏来hack菜单了。如果这三个区域只要有一个没有足够的空白区域那么对于我们的教程来说这个游戏就无法hack菜单(也可以有别的办法,但是不在我们这个教程讨论的范围之内)。

 

 

4. 调整菜单代码

(建议用nodepad)打开menu.asm文件,找到下面几个非常重要的变量:

PRG_BANK : 菜单PRG所在的bank 号,PRG_BANK=PRG空白区域起始地址/$2000 (这里的/是数学上的除以)

PRG_ADDR_OF_RAM : 菜单PRG的起始内存地址(这里是NES内存地址不是ROM地址)PRG_ADDR_OF_RAM= PRG空白区域起始地址% $2000 + $8000 (这里的%是数学上的求余数)

CHR_BANK: 菜单CHR所在的bank号,CHR_BANK= (TLP Page down count * 4 --> Convert to hex)(就是用Tile Layer Pro这个软件打开扩容后的宿主文件,然后一直按键盘上的Page Down键,直到找到符合要求的空白区域,并且记下按Page Down键的次数,再将这个次数乘以4,最后转换成16进制的值就是这个CHR_BANK了)

ORG_RST :宿主游戏的原始复位向量

HARD_FREE :宿主游戏菜单入口的PRG内存地址

下面以“扩容后_ HERO FIGHT.nes”为例详解介绍上面的几个变量是怎么计算的。

(1)PRG_BANK

在第3部分中,我们已经找到了合适的PRG空白区域,起始地址为ROM内存的$037880。这里要注意的是,ROM文件的头文件(10h字节)是用来给模拟器使用的,对物理机来说没有头文件这么一说,是不存在的,所以我们要跳过这10h字节,所以正在的空白区域起始地址应该是$037880-$010 = $037870。按照我们上面给出的计算公式:

PRG_BANK = $037870 / $2000 = $1B

(2)PRG_ADDR_OF_RAM

          在第3部分中,我们已经找到了合适的PRG空白区域,起始地址为ROM内存的$037880。这里要注意的是,ROM文件的头文件(10h字节)是用来给模拟器使用的,对物理机来说没有头文件这么一说,是不存在的,所以我们要跳过这10h字节,所以正在的空白区域起始地址应该是$037880-$010 = $037870。按照我们上面给出的计算公式:

      PRG_ADDR_OF_RAM =  $037870 % $2000 + $8000 = $9870

 (3)CHR_BANK

       在第3部分中,我们已经找到了合适的CHR空白区域,然后我记录了一下,从打开文件到找到合适的空白区域共按下了 40次Page Down按键(注意:由于是在扩容区域找在按下Page Down的过程中可能出现两次上面找到的空白区域,第二次出现时按下的按键次数才是咱们需要的值),按照上面的公式:

       CHR_BANK = 40 * 4 = 160(10进制) = $A0(16进制)

(4)ORG_RST

           游戏的复位向量,固定在PRG内存的倒数第3和第4字节。用FCEUX模拟器打开“扩容后_ HERO FIGHT.nes”,然后从模拟器的菜单栏找到:调试->十六进制编辑器->查看->NES内存,拖到最底部如下图:

 

发现最后两个字节是F4和FF,又由于6502CPU是低字节序,即低字节在前高字节在后,所以复位向量应该是FFF4而不是F4FF。那么对于“扩容后_ HERO FIGHT.nes”这个游戏来说他的原始复位向量(ORG_RST)就是FFF4

                           ORG_RST = $FFF4

(5)HARD_FREE

         复位向量是游戏的入口,当FC游戏机接通电源或者按下复位键时,CPU执行指令的顺序都会重定向到复位向量所指向的内存地址然后向下直接。单个游戏的复位向量就是我们上面提到的ORG_RST,现在我们要做合卡,所以当接通电源或者按下复位键时不能再让CPU从游戏原来的复位向量执行了而是应该让CPU从我们的菜单入口的内存地址开始执行,这个地址很简单,就是我们第3部分苦苦寻找的菜单入口指令的区域的起始地址,对于” 扩容后_ HERO FIGHT.nes”来说是FFA0.

                         HARD_FREE = $FFA0

 

最后还有一处要修改的,在menu.asm代码文件中找到如下代码做修改:

 

对于” 扩容后_ HERO FIGHT.nes”来说是PRG_ADDR_OF_RAM的值为$9870,所以设置如上图。

 

 

5. 设计菜单

用YY-CHR软件打开” 扩容后_ HERO FIGHT.nes”文件,找到第3部分我们找到的CHR空白区域,

 

  1. 点鼠标右键选中左上角的第一个方块如上图
  2. 然后松开鼠标右键再按住鼠标右键不放拖动白色方块直到选中整个CHR页如下图:

                                                    

  1. 复制选中的CHR页到粘贴板
  2. 执行: 文件->新建,然后把剪贴板的内容粘贴到新建的文件里面,将文件保存为menu.chr。(对于上面的示例热血格斗来说可能是纯颜色什么都没有,但是对于其他游戏来说可能会有很多图案,这会不理解也没关系,多操作以后就明白了)
  3. 用YY-CHR打开ascii.chr,点鼠标右键选中左上角第一个方块,然后按住右键不放拖拽选中使用到的字模如下图,然后将选中的部分复制到粘贴板

 

  1. 用YY-CHR打开本节第4步中新建的menu.chr文件,然后把从ascii.chr复制的那部分字模粘贴到menu.chr中,保存menu.chr,这样menu.chr就算制作完成了。
  2. 运行菜单编辑器.bat,接下来菜单长啥样就尽情的设计吧,设计完了之后按Ctrl+S进行保存,菜单编辑器生成的menu.nam就是命名表+属性表数据。如果颜色不够用修改menu.pal进行修改。

 

文件说明:

     menu.chr菜单字模文件

     menu.nam菜单命名表+属性表

     menu.pal调色盘

编译菜单代码必须有这三个文件且需要把这三个文件放在和代码的同一个目录下面。

 

 

6. 编译菜单代码

     运行生成菜单.bat会把menu.asm,men.chr,menu.nam,menu.pal进行处理,最后生成menu.nes。这个menu.nes文件就是编译后的菜单了。这样编译之后菜单指令和字模是单独的文件,并不在宿主文件“扩容后_ HERO FIGHT.nes”上,接着往下看。

7. 将菜单指令、字模hack到宿主游戏上

7.1 hack菜单入口指令

       用FCEUX模拟器打开编译好的menu.nes文件,然后从模拟器的菜单栏找到:调试->十六进制编辑器->查看->NES内存,找到菜单入口指令的起始地址,对应我们的示例游戏来说,菜单入口的内存起始地址是FFA0:

 

        将这三行指令复制,然后新建一个记事本把这段指令临时保存到记事本上。

接着找PRG指令代码。我们在上面已经计算出来PRG_ADDR_OF_RAM的值是$9870,所以拖进度条到9870处找到PRG指令,如下图:

 

 将这段指令全部复制(至于怎么判断指令到哪结尾这个很简单,当出现连续FF的时候就结尾了)粘贴到临时记事本上面,如下:

 

 复制到记事本上之后用FCUEX模拟器打开宿主游戏” 扩容后_ HERO FIGHT.nes”, 然后从模拟器的菜单栏找到:调试->十六进制编辑器->查看->NES内存,找到菜单入口HARD_FREE变量指向的内存地址$FFA0,选中地址FFA0,点鼠标右键->转到ROM文件对应位置

 

这样就从PRG内存转到了ROM内存对应的位置,PRG内存的FFA0对应ROM内存的3FFB0。从刚才保存的临时记事本上面把菜单入口指令复制到粘贴板上,然后粘贴到这个位置,这样宿主游戏的菜单入口指令就加上了。

 

 

              添加菜单入口指令前                                                                                            添加菜单入口指令后

7.2 hack PRG指令

     从模拟器的菜单栏找到:调试->十六进制编辑器->查看->NES文件,参照我们3.2章节找到的空白区域起始地址,对于“扩容后_ HERO FIGHT.nes”来说是$0378800(这里不需要减掉nes头文件的10h字节,因为我们就是在nes文件上修改的),其他的游戏根据实际找到的确定。打开保存菜单指令的那个临时记事本,复制菜单PRG指令,然后粘贴到ROM文件的地址$0378800(这个地址根据上面找到的PRG空白起始区域来确定每个游戏都不同)处保存。

7.3hack CHR

     用YY-CHR打开ascii.chr,复制那三行字模到粘贴板。再用YY-CHR打开” 扩容后_ HERO FIGHT.nes”,按Page Down键找到chr空白的起始区域,把粘贴板的三行字模粘贴到空白区域。这样字模也就hack到宿主游戏” 扩容后_ HERO FIGHT.nes”上面了。

7.4修改复位向量

     到目前为止,” 扩容后_ HERO FIGHT.nes”每次启动或者按下复位键之后开始的内存地址依然是正常游戏的内存地址,并不是菜单指令的地址,所以需要把复位向量改成菜单指令的起始地址,操作步骤如下:

      用FCEUX模拟器打开” 扩容后_ HERO FIGHT.nes”, 从模拟器的菜单栏找到:调试->十六进制编辑器->查看->NES内存,拖到最底部,

 

修改前:

 

选择倒数第3个字节F4,右键->转到ROM文件对应位置,修改后(注意字节顺序):

8.生成最终模拟器可运行的Mapper52的NES文件

    用扩容还原工具将扩容+hack的ROM进行还原,将宿主游戏放在第2个位置就可以生成Mapper52的rom了