发信人: 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]
  | 
 
 
 |