发信人: tedyboy()
整理人: chocobo(2001-01-30 17:32:09), 站内信件
|
《仙剑奇快传》是一个极老的游戏,关于它的修改方法也常见于各种
电脑游戏刊物,各种不死版、暴富版相信各位也见得多了,不知还会不会
对我的这个“简体中文版”感兴趣?本人玩游戏只能算菜青虫级,但一直
对制作游戏很感兴趣,于是常爱分析一下游戏,终于摸索了一点经验。
一般游戏中的文字显示常是由程序自己来实现,并不调用系统平台的
显示功能,因此台湾人做的游戏始终只能看到繁体字,这一点连《东方快
车》也没用。当然《仙剑》的“98柔情版”是重新修改编译过的,可以显
示简化汉字了。但我更钟情于DOS版的《仙剑》,因为它对系统的要求很低,
只要8MB内存和30MB硬盘就行了。可是美中不足的是它的繁体字,于是我花
了一整夜,对《仙剑》的汉字显示方法作了一番解剖,终于找到了一个
“简化”的方法。
首先说明我选择的《仙剑》是DOS版的,磁盘版和CD版是一样的,只要
将程序生成的字库文件拷贝并覆盖原来的同名文件即可。但如果你是“98
柔情版”就别照做了,因为它本身就是简体中文版,而且字库文件好像也
不兼容。不过如果有人想“反其道而行之”做一个“98柔情繁体中文版”
也可以照此法做,至于程序如何修改就得靠自己了,当然得先理解本文。
“简化”工作中最为重要的就是找出游戏中汉字的显示方法和相关的
数据文件的结构。游戏的程序代码是不用改的,因为“简体”和“繁体”
之间只是字模数据的差异而已,如果我们把游戏中的字库文件由繁体换成
简体,游戏中相应的就会显示出简体中文。
但是直接从UCDOS中把HZK16拷贝过来行不行呢?当然不行,原因在于:
①DOS游戏对内存的使用都是斤斤计较的,且游戏中用到的汉字数目是有限
的,制作者绝不会把整个字库都搬来,一定是使用小字库,那么这个小字
库及其汉字存储格式等就要先弄清楚。②HZK16中的汉字字模使用的是
16 X 16点阵,而《仙剑》是台湾出的软件,它们的中文系统中汉字常是
BIG5内码16 X 15点阵,因此也得先仔细分析才能转化。
第一个问题先得靠观察和猎测,在PAL下找找两个文件:WOR16.ASC和
WOR16.FON,WOR像是Word,16又像HZK16,那么WOR16.FON就该是小字库了,
WOR16.ASC又是什么呢?在CCDOS97下TYPE一看,乱码……不过有点眼熟,
CTRL+F8换成BIGS码,屏幕上顿时变得亲切起来--“经验值状态仙术物品
系统新的故事旧回忆打败敌人得文钱……”哈哈哈,这不就是游戏中使用
的汉字总表吗?然后是小字库中的汉字次序,我猜它就是按这张汉字表中
的次序来存储的,可是究竟是不是呢,这就要自编一个程序来验证了。
第二个问题,字库中的汉字字模是什么点阵显示的,又是如何存储的?
打开《仙剑》,瞪大眼睛屏住呼吸数屏幕上汉字的点阵,说句实话我从没
和逍遥兄挨这么近过,鼻子都快贴着屏幕了。终于让我数清楚了,15 X 15
点阵,但水平方向相邻两字之间有一点空隙,应该再加上一个点,16 X 15
才对,这才好存储,所以每个汉字字模占16X 15/8=30字节。
开始写了一个程序PALHZ.CPP,它从WOR16.FON中指定位置读出32字节,
按HZK16中的表示方法将字模显示在屏幕上,根据屏幕显示来推测汉字的具
体存储方法。程序很简单,清单见后。
用这个程序尝试了很多次,可总是一些莫名其妙的图案,于是试着输
入了一个2000,结果出现了一个好像是“新”字的图案,逐渐逼近,1999、
1998、1997,终于在1996处是完整的“新”字,再试前一个字,用1966,
出现了“统”,1936,出现了“系”……果然是如我所料,30字节一个汉
字字模,且按WOR16.ASC的次序存储,起始位置是W0R16.FON的1666字节处。
现在就可以统正式的“简化”程序(MAKEPAL.CPP)了,简化汉字字模
肯定是来自HZK16,而且WOR16.ASC也必须先转化成GB码才好处理,具体可
见程序清单及注释。这里又有几个问题:1.如何把HZK16的16 X 16点阵变
成16 X 15点阵?这其实很容易,只须将16 X 16字模中的顶行或底行去掉
就行了,但这肯定会丢笔划,我是这样处理的,这两行中哪一行的16位中
的“1”产少些就拿哪行开刀;2.用UCDOS和CCDOS97的内码转换工具转换
WOR16.ASC时都有些字会转错,相比之下CCDOS97的GB5.EXE要好一些,但还
是有一些字错或不合适,如把“舅”转成了“肝”,这些都要自己手工修
改一下,工具最好用DE或UltraEdit(如果你想当游戏的主人公,只需此刻
把“李逍遥”改成自己的大名就行了^_^)。还有一些字干脆成了“??”,
这个不好找,程序中对它们就还是取原来的繁体字模了。
程序写好,编译调试通过(Turb C++3.0),就可以得到我们的《仙剑
奇快传》“简体中文版”了。具体方法如下:
1.在硬盘上任意位置建一个子目录如Palhh。
2.将PALWOR16.ASC、PALWOR16.FON和UCDOSHZK16拷贝到这个目录。
WOR16.ASC是《仙剑》的所有汉字的内码表(BIG5),也是在小字库中直找
字模的索引。WOR16.FON是《仙剑》的所有汉字的显示字库(16 x 15),
在偏移1666处开始是汉字字模数据,每字占一记录,长度30字节(字模点
阵接由上到下(0-14行)、由左到右(0-15点)存储),汉字记录按
WOR16.FON中的次序存储。
3.用CCDOS97的GB5.EXE或其它汉字内码转换工具,将WOR16.ASC转换
成GB码(原来是BIG5码的)。然后,可以适当修改。
4.执行自编程序MAKEPAL.CPP,生成WOR16.FOG,这个文件就是已将所
有字模转化为简体字的字库。
5.将WOR16.FOG改名拷贝为PALWOR16.FON,一定要覆盖原来的
WOR16.FON。
现在,《仙剑》就是简体中文版了,CDPAL,PAL,怎么样,耳目一新吧!^_ ^
//文件名:PALHZ.CPP
//用于显示WOR16.FON中指定偏移量处的汉字字模(16 * 15)
//在Turbo C++ V3.0 for DOS中调试通过
#include <STDIO.H>
#include <IOSTREAM.H>
#include <CONIO.H>
// 显示一个字节的各位
int PutBit(unsigned char dat, int x, int y)
{int ix;
for (ix = 0; ix <8; ix + + )
{gotoxy(ix + x, y);
if (dat & (0x80>>ix))
cprintf("%c",'@');
else
cprintf("%c",'');}
return 0; }
int main(void)
{int x, y;
long offset = 0;
unsigned char buf[600];
FILE * fP;
fP = fopen("wor16.fon", "rb");
clrscr();
do
{cout << "Offset:";
cin >> Offset;
fseek(fp, offset, SEEK_SET);
fread(buf,1,32,fp);
for (x = 0; x <15; x + +)
for (y =O; y <2; y + + )
PutBit(buf[x * 2 + y], 1 + y * 8, 3 + x);
} while (offset! = 0); //输入0退退出
fclose(tp);
return 0; }
//文件名:MAKEPAL.CPP
//此程序用于由WOR16.ASC生成小字库文件WOR16.FOG
//在Turbo C+ + V3.0 for DOS 中调试通过。
#include <STDIO.H>
#include <CONIO.H>
#include <IOSTREAM.H>
int BitCount(void * );
int main(void)
{FILE *fpi2, *fpi, *fpt, *fpo;
long of1;
int i, delline = 0, nochange;
unsigned char buf[60], tbuf[4];
fPi2 = fopen("wor16.fon", "rb");
fpo = fopen("wor16.fog","wb");
for (i =0; i <1666; i+ +) //0 到1665字节原样复制
{fread(buf, 1, 1, fpi2);
fwrite(buf, 1, 1, fpo); }
fpt = fopen("wor16.asc", "rb");
fpi = fopen("hzk16", "rb");
for(i = 0, nochange = 0; !feof(fpt); i + = 2) //开始替换字模
{fseek(fpt, i, SEEK_SET);
fread(tbuf, 1, 2, fpt);
if(tbuf[0] <=0xa0) //如果是内码转换中无法识别的"??"竺,则用WOR16.FON 中的繁体字模
{fseek(fpi2, 1666L + i * 15L, SEEK_SET);
fread(buf, 1, 30, fpi2);
cout < < 1666L + i * 15L;
delline = 0;
nochange + +; }
else //是汉字则从HZK16中读出简化字模
{of1 = (tbuf[0] - 161) * 94L + (tbuf[1] - 161);
cout < < tbuf[0] < < tbuf[1] < < of1 * 32 < < char
(delline +'A');
fseek(fpi, of1 * 32, SEEK_SET);
fread(buf, 1, 32, fpi);
if (BitCount(buf) delline =2; //则用buf[02..31]的字模数据
else
delline =0; //否则用bfu[0..29]的字模数据 }
fwrite(buf + delline, 1, 30, fpo); }
fclose(fpi);
fclose(fpo);
fclose(fpt);
fclose(fpi2);
cout << "n有"<< nochange <<"字未转换!n";
return 0; }
//统计一个字中的各位的"1"的个数
int BitCount(void * p)
{int s = 0, i;
unsigned int w;
w = * ((unsigned int * )p);
for (i =0; i <16; i + + )
if (w> > i & 1)
s + +;
return s; }
-- 观自在菩萨 行深般若波罗蜜多时 照见五蕴皆空 度一切苦厄 舍利子 色不异空 空不异色 色即是空 空即是色 受 胄惺?亦复如是 舍利子 是诸法空相 不生不灭 不垢不净 不增不减 是故空中无色 无受想行识 无眼耳鼻舌身意
无色声香味触法 无眼界 乃至无意识界 无无明 亦无无明尽 乃至无老死 亦无老死尽 无苦集灭道 无智亦无得 ?BR>※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.96.191.124]
|
|