游戏汉化实战-- GF汉化详细教程

游戏汉化实战-- GF汉化详细教程
游戏汉化实战-- GF汉化详细教程

游戏汉化实战--GF汉化详细教程[前言]

我是一个普通的游戏的玩家,与其它玩家一样喜欢收藏精典游戏和品尝新游戏。但很多时候由于语言的原因,无法体会到游戏的精髓,而只是按照攻略走一个流程罢了。一个很偶然的机会,尝试汉化一款精典游戏--Grim Fandango,在半个月的时间里,通过看文档、分析文件格式、制作字体等一系列步骤,最终将这款游戏进行了彻底地内核汉化,随后只要将对话部分翻译成中文就可以推出与玩家见面了。

我平时的工作是dotNet程序员,对程序有一定了解。对游戏汉化很感兴趣,但是这项技术似乎很神秘,网上很少有关此类的教程可以参考,特别是PC游戏的汉化,几乎没有。这也是我写这系列教程的目的。特别献给那些对游戏汉化感兴趣,但又不知道从何下手的人们。希望能对他们有所帮助。GF是什么?

GF可不是Gril friend,呵呵,GF=Grim Fandango,是一款卢卡斯1998年制作的冒险游戏,中文译名神通鬼大,是一款画面精美,构思独特、有内涵的3D图形冒险游戏。曾被Gamespot评为年度最佳游戏。

游戏汉化与应用软件汉化的区别

1.字库。应用软件一般采用的是操作系统自带的矢量字体,而游戏大多不用系统字体,而是自制字库,用自己的字体。为什么这样做的我也没完全理解,现在考虑到可能有两个原因,

1。系统字体无法满足游戏中美化字体的需要2。为了游戏的可移植性性。

2.汉化方式。应用软件的汉化主要是资源文件的汉化,利用相关软件把英文字符串替换成中文就完成了。游戏汉化本质也是修改游戏资源文件,但实现起来却要复杂的多。由于游戏大

多是用自制的字库,汉化游戏就不得不修改游戏字库文件,将需要用到的中文加入字库,游

戏才有显示中文的可能性。其次,由于英文是单字节中文是双字节,为了正常显示中文,可

能还需要对游戏程序部分的字库读取方式作一定修改,这在没有游戏源代码文件情况下是十

分困难的。

对于过去的游戏软件,由于技术和硬件条件所限,一般会将字库和字体读取方式做死,对此类游戏的汉化一般需要开发商提供部分源代码进行修改才能实现。现在的游戏开发时一般就会考虑到国际化发行的问题,在程序中预留了接口,使得游戏做很少修改就能变成各种语言的版本,以多语言发行。这样的游戏汉化起来很容易,有时仅仅需要修改几个配置文件即可。

本教程将会划分成以下几部分相继推出:

GF汉化详细教程[文件格式篇]

GF汉化详细教程[游戏字体篇]

GF汉化详细教程[字库制作篇]

GF汉化详细教程[内核修改篇]

游戏汉化实战--GF汉化详细教程[文件格式篇]

进行游戏汉化最开始的工作就是分析游戏的文件格式,找出要汉化的部分在哪个文件里,文件结构是什么样子的,应该怎么修改。

汉化游戏主要是要找出两种文件及对应的文件格式:

1。游戏的字体文件

2。游戏的英文脚本文件(就是游戏中的情节、对话部分)

但是如何找,这却是一个难题。由于游戏厂商一般对自已出品的游戏文件格式都是不公开的,它们不希望玩家能随意修改游戏(这仅仅是一厢情愿罢了),很多骨灰级玩家还是能够找出游戏的文件结构,进而修改游戏。

这样看来,找出文件格式主要有两种方式:

1.搜索网上的资源,寻找骨灰级玩家,求得帮助。

2.自己充当骨灰级玩家,分析出游戏文件的格式来,难度较大。

幸运的是Lucas公司的游戏Fans很多,甚至还成立了一个专门的网站LucasHacks(https://www.360docs.net/doc/304336491.html,)用来讨论怎么修改其出品的各种游戏。我所需要的游戏文件格式的文档全是出自此网站,从而为汉化工作提供了极大的帮助,节省了很多时间,在此表示万分感谢,向那些撰写文档的前辈们致敬。

下面针对GF开始介绍用到的几种游戏文件格式

1..tab文件格式

是存放游戏所有英文脚本的文件,文件内容是加密存储的,用一般文本编辑器打开是看不到任何可用信息。解密内容的方法是对文件所有字节与0xDD进行异或操作。

以下是解密文件的源码(C#):

private void button1_Click(object sender,System.EventArgs e)

{

//Create the reader for data.

FileStream fs=new FileStream("c:\\grim.tab",FileMode.Open, FileAccess.Read);

BinaryReader r=new BinaryReader(fs);

FileStream fs2=new FileStream("c:\\text.txt",FileMode.Create);

BinaryWriter w=new BinaryWriter(fs2);

fs.Position=4;

while(fs.Position

{

w.Write((byte)(r.ReadByte()^0xdd));

}

r.Close();

w.Close();

fs.Close();

fs2.Close();

}

解密后的文件内容就是一般的文本,可以看到所有游戏对话都在其中。下面节选文件内容的2段进行分析:

sito030Oh yeah,yeah.Yeah.That is what I told him.

sito031Are you kidding me?

sito032gave him the idea in the first place!

可以看出左边是说话人的名称标识,右边是说话的内容,分割这两者的是看似一个空格,其实是ASCII 码表中的制表符Tab,16进制表示是0x09。

对游戏角本的汉化修改此文件的内容为中文就可以了,还有一点值得注意,修改完此文件后无需再对其反加密,只要将解密的文件保存成以前加密文件的文件名覆盖即可。应该是游戏运行时候会对文件是否加密进行判断

2..lab文件格式

是游戏的资源文件格式,游戏所有的资源声音、图片、动画、全存于此。它很类似于常用的压缩文件的格式,如zip、rar,作用是把很多文件压缩成一个文件,需要用的时候再解压出来供使用。Lab文件也是这个用途,它把很多用到的声音、动画等文件放到一个lab文件中,供需要时调用。Lab 文件不对文件进行压缩,只是简单地把所有文件头尾相连,保存成一个文件而已。

GF汉化详细教程[游戏字体篇]

GF汉化详细教程[游戏字体篇]

现在的游戏大部分是用矢量字体了,但以前的游戏一般都是用点阵字体。下面先介绍一下点阵字体显示原理。

汉字内码

点头表示什么?是“对”、“YES”,偏偏有的地方表示的意义却恰恰相反。一个动作,有不同的诠释;一个问题,有不同的答案;而一个符号,却有不同的意义,关键在于:你是如何地理解。在电脑中亦如此,所有的数据都是以0和1保存的,按不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有5000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。

汉字字模

得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模中是这样记载的:

而中文的“你”在字模中却是这样记载的:

所有的汉字字模组成点阵字库,像以前Dos下常用的Ucdos汉字系统就是用的点阵字库,点阵字库根据不同需要有好多种尺寸,如16*1624*24,点越多显示的字越细致,特别是显示那些笔划比较多的字,效果越好。

下面进入GF字体的世界,GF的字体扩展名是.LAF,都打包存储于https://www.360docs.net/doc/304336491.html,B文件中。先分析一下LAF的文件格式,然后再讨论如何在字库中加入中文。LAF格式由文件头、字体索引表、字体偏移量表、字体点阵四部分组成。

2.字体索引表

与字体编码范围相对应,每个双字节保存一个字模在偏移量表中的偏移量。如GF的英文字库是显示ASCII码表中0-FF的字符,所以有256个字模,字体索引表有256*2=512字节。

保存内容为这256个字模在字体偏移量表中的偏移量

4.字体点阵

保存字体点阵。字体点阵的保存顺序是,从左到右,从上到下。0代表无点,ff代表有点。(这是GF点阵与一般字体点阵的区别,一般字体点阵一个二进制位的1代表一个点,但是GF的字库0xFF才代表一个点)。

现在举一个GF中的点阵的例子,下图是GF中汉字“选”的点阵,可以基本看出字形吧,每个汉字都要做成这样的点阵加入到字库中去。

现在举一个例子,说明GF程序如何显示一个英文字母N。(N的ASCII码是0x4E)

1.在字体索引表中找到字模在偏移量表中的偏移量。读文件32+4E*2=0xBC处的双字,得到偏移量4E。

2.在字体偏移量表中得到字体点阵的偏移量。读文件32+512+4E*16=0x700处得到字体点阵的偏移量0x17c0,再读0x708h得到字体N的宽0x0A,再读0x70ch处得到字体N 的高0x0C。

3.读字体点阵显示字符N。字体点阵的首地址为16*256+512+32=0x1220H。字体N的点阵部分是在文件0x1220H+0x17c0H到0x1220H+0x17c0H+0D*0A之间。

汉字编码GB2312-80简介

GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。

GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。

GB2312将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区,10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计

3008个,置于56-87区,按部首/笔画顺序排列。故而GB2312最多能表示6763个汉字。

GB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。

改造字库

我们现在要做的就是将GB2312中的6763个汉字加入到GF的字库中去。汉字点阵定为16*16。因为游戏中仍要部分内容要以英文方式显示,所以我们加入汉字并不应该破坏原有的英文点阵字库,而是应该在英文字库尾部追加这6763个汉字。

1.首先要修改文件头部分,每个字段都要做相应调整。

2.由于汉字编码范围是2121H-777EH,所以字体索引表至少要扩大为777E*2个字节。索引表的内容前512字节为原始的英文字体索引表,应该保留。在此之后,凡遇到字体索引表中

GB2312汉字编码处是汉字的位置,添加汉字在字体偏移量表中的偏移量。汉字偏移量应该

从0x100开始(前256是英文字库)

3.重建字体偏移量表,将6763个汉字在字体点阵的偏移量、汉字宽0x10,汉字高0x10写入。

4.将6763个汉字的点阵追加到原来英文点阵的尾部。

经过以上4部,字库改造完毕。虽然修改只有4部分,但是每部分都涉及到各种偏移量的计算,多字节高低位的读取等、文件头的再修改等步骤,代码实现起来非常麻烦,稍有不甚就会失败,甚至导致GF运行时直接崩溃,调试时需要特别的耐心才行。

在生成新的字库后,把新字库覆盖掉原来https://www.360docs.net/doc/304336491.html,B中的同名字库文件,字库的修改就大功告成了。

GF汉化详细教程[字库制作篇]

在上次字体篇提到要追加GB2312的全部汉字到点阵字库中。但由于GF的字库不是标准点阵字库,它用FF表示一个点,所以字库无法在现有的点阵字库中得到,而只能通过写程序生成GF格式的点阵字库。引出另一个问题,这么多汉字的点阵应该怎么生成。比较好的解决方法是把的矢量字库中的字转换成我们需要的点阵格式。

矢量字体转换成点阵字体需要以下几步,(以转换为16*16点阵的字体为例):

1.准备一个背景是白色的16*16点阵的位图。

2.读位图到内存,在图片上居中写入你要转换的字。

3.循环读位图每一位的颜色信息,如果此点颜色是黑色,证明是一个点,写入FF,其它位置写入0,得到点阵。

以下是生成单个字的转换函数(c#实现):

///

///生成单个16*16点阵的字库

///

///

///

private byte[,]DrawChar(string str)

{

byte[,]result=new byte[16,16];

StringForm at sf=new StringFormat();

sf.Alignment=StringAlignment.Center;

sf.LineAlignment=StringAlignment.Near;

Bitmap bmp=new Bitmap(Application.StartupPath +"\\blank.bm p",true);

Graphics g=Graphics.From Image(bmp);

//参数大小只适用于16*16点阵

g.DrawString(str,new Font("宋体",12),Brushes.Black,new Rectangle(0,0,16,16),sf);

//结果写入16*16字节数组

for(int i=0;i

for(int j=0;j

{

if(bm p.GetPixel(j,i)==Color.FromArgb(255,255,255))//白色

result[i,j]=0;

else

result[i,j]=0xff;

}

return result;

}

GF汉化详细教程[内核修改篇]

经过前边的字库改造,已经完成了一半的工作,剩下最关键的显示汉字部分了。字库已经是中文的了,但是能让中文显示出来却不是件容易的事。不信现在进游戏试试,看到的中文全是乱码。为何?因为中文是双字节,两个字节才代表一个汉字。游戏显示英文字体的函数是为显示单字节的英文设计的,是不适合显示中文的,必须要修改。因为不可能得到程序的源代码,修改方法只能采用比较极端的修改可执行文件的方法了,即所谓的逆向工程。

于是操起常用的调试工具Ollydbg开始调试游戏。经过2天的不懈努力,终于找到了显示字库的函数,以下列出读取字符的函数部分代码:

004AA9098A08mov cl,byte ptr ds:[eax]

004AA90B40inc eax

004AA90C8BF1m ov esi,ecx

004AA90E8BD6mov edx,esi

004AA910F7DA neg edx

004AA9121BD2sbb edx,edx

004AA91423D0and edx,eax

004AA91685F6test esi,esi

004AA9188917mov dword ptr ds:[edi],edx

函数开始Eax指向脚本文件grim.tab文件中某行脚本的第一个字符。例如主菜单”Control Help”中的C位置。004AA909一行的意图很明显,读取字符串中当前位置的的一个字符的ASCII 码到放到cl中,然后Eax加一,指向下一个字符。然后会将此cl中的字符当作参数,调用另外一个显示字符的函数,完成读取字库文件并显示字符到屏幕的功能。

我们需要对此部分做改造。如当前Eax指向一个英文字符,则还沿用程序原来的部分,读取一个字节到cl,并使Eax增一;如当前Eax指向一个中文汉字,则需要程序读取2个字节到cx中,并使Eax增二,指向下一个字符的正确位置。那么如何判断当前Eax指向的是一个英文字符还是中文汉字呢,GB2312汉字的编码有一个的特性:两个字节编码最高位(第8位)一定是1。每次读取字符时,

先判断第8位是0还是1,如果是1一定是中文,是0则是英文。

有了思路,对读取字符的函数做如下修改,红色为新增代码:

004AA9098A08mov cl,byte ptr ds:[eax]

004AA90B40inc eax

f6c180test cl,80h

7406je4aa90c

c1e108shl ecx,08h

8a08mov cl,byte ptr ds:[eax]

40inc eax

004AA90C8BF1mov esi,ecx

004AA90E8BD6mov edx,esi

004AA910F7DA neg edx

004AA9121BD2sbb edx,edx

004AA91423D0and edx,eax

004AA91685F6test esi,esi

004AA9188917mov dword ptr ds:[edi],edx

先放Eax一个字节到cl中,然后判断cl的第8位是否为1,如果是0,说明是英文字符,则按程序原来的进度跳转到004AA90C这行的代码继续执行。如果是1,则要将cl向左移8位,为汉字第二个字节留下位置,然后再取一次Eax的值,把第二个字节放到cl中。最后Eax增一(Eax增了两次1)。此时Ecx的数值正是一个汉字两个字节的内码。Finish!

然后用Uedit打开可执行文件,找到一段nop(90)比较多的位置,最后将红色部分的机器码加到合适位置就OK了。

相关主题
相关文档
最新文档