VBGood网站全文搜索 Google

搜索VBGood全站网页(全文搜索)
首页 - 经验之谈 - Command & Conquer 文件格式
发表评论(0)作者:, 平台:, 阅读:9693, 日期:2000-03-17
Command & Conquer 文件格式


修订版3

作者:Vladan Bato (i3100785@univ.trieste.it)

译者:Sunway (codingboy@126.com)


---


目录


一、.MIX 文件

二、.PAL 文件

三、.TMP文件 和 .BIN 文件

五、.SHP 文件

Format80 格式

Format40 格式

六、.CPS 文件

七、.WSA 文件

八、附录

九、声明




前言


这篇文章解释了Command & Conquer使用的文件格式。


'Command & Conquer' 是 Westwood Studios 的商标。

'Command & Conquer' Westwood Studios 版权所有。

这里提供的信息对那些想写C&C编辑器和工具的程序员十分有意。尽管我的解释不是最好的但它已经足够了。


我不能保证这里所说的都是正确的,如果你发现了错误,请告诉我。


在这篇文章里,我用了Pascal语言描述,例子的代码也是用Pascal写的。我本想用C再写一遍,可惜我没有时间测试代码。因此,为了避免任何的风险,我用了 MIXMAN程序的代码。


万一你不懂,这里提供的很多的信息都用在了程序MAXMAN中,他包括了很多不同文件格式转换的工具。要得到更多的信息,可以到我的主页上来。(见文章末尾)


一、.MIX 文件[Top]


你可能已经知道了这个文件的格式,不过我将增加一些完整性的描述。


MIX 文件有两部分组成:

-- 头部分(header),包括包含在这个文件里的所有文件的索引

-- 体部分(body),包括了所有的文件



 


Header : record

NumFiles : word; {包含在MIX文件中的文件个数}

DataSize : longint; {body部分的大小}

Index : array [1..NumFiles] of

record

ID : longint; {文件ID号}

Start : longint; {相对body开始的偏移量}

Size : longint; {文件大小}

end;

end;

ID 域是被计算作原始文件名的。文件名是不存储在MIX文件中的。记录总是按ID 号(申明为的LONGINT)的顺序存储的。


注意:偏移量是相对BODY开始的。所以实际的偏移量要加上HEADER 部分的大小,既 NUMFILES*12+6 字节。


[译者注] 这是OLD C&C的MIX文件格式,在‘红色警报’中MIX的头可能加了密。 现在无法搞定。


二、.PAL 文件[Top]


最简单的文件格式.这个文件包含了和VGA显卡一样的调色板的格式。


格式如下:


 


Palette : array [0..255] of record

red,green,blue:byte;

end;

注意每个字节的前六位有效,这总共提供了262144种颜色(这和PCX文件使用8位刚好相反)。


[译者注] 好象PCX文件也是用6位呀!


三。.TMP文件 和 .BIN 文件[Top]


TMP文件包含了地图(TILE)图片,他能被发现在剧情特殊的MIX文件中(如 TEMPERAT.MIX, WINTER.MIX, DESERT.MIX)。BIN文件包含了任务地图,它和.ini 文件联合使用。


我在此不对它们解释。它们已在我前不久写的一篇题为“Command & Conquer maps” 的文章中详细的解释了。你可以在我的主页上看到。


五. .SHP 文件[Top]


SHP文件包含和几乎全部的图片,包括:单元、建筑、树木... 文件头是如下的结构:


 


Header : record

NumImages : word; {包含的图片的个数}

A,B : word; {未知}

Width,

Height : word; {图片的宽和高}

C : longint; {未知}

end;

如果你知道“未知”部分的意思,请E-MAIL给我。下面的这个记录数组,每一个代表一个图片:


 


Offsets : array [0..NumImages+1] of

record

Offset : word; {图片在文件中的偏移量}

Format : word; {图片的格式}

RefOffs : word; {‘基’图片的偏移量}

RefForm : word; {‘基’图片的文件格式}

end;

FORMAT域有三种值:8000h,4000h,2000h。我称之为Format80,Format40,Format20。


FORMAT80 图片是用一种压缩方法压缩的。我在后面解释。


FORMAT40 图片必须和FORMAT80格式的图片作异或运算。这就是REFOFFS 和REFFORM域的用处所在。它们告诉了哪一个FORMAT80格式的图片将被作为“基”打开。FORMAT40 格式我在后面解释。


FORMAT20 图片是和FORMAT40一样格式的图片,不同之处是它要和在SHP文件里排在它前面的图片做异或运算。这些图片可以是FORMAT20和FORMAT40格式的。在FORMAT20格式中的REFOFFS域包含了第一个FORMAT40格式图片的号码,REFFORM域确总是4800H。


这有个例子:


0) Off0 8000h 0000h 0000h

1) Off1 8000h 0000h 0000h

2) Off2 4000h Off1 8000h

3) Off3 8000h 0000h 0000h

4) Off4 4000h Off1 8000h

5) Off5 2000h 0400h 4800h

6) Off6 2000h 0400h 4800h

7) Off7 4000h Off3 8000h

如果画图片7,你不得不先画图片3,然后在画图片7。


如果画图片6,你不得不先把它和前面的图片异或,象图片5,它也是FORMAT20格式,这意味着它也要和前面的图片4异或,因为它是FORMAT40格式的,所以它要与FORMAT80 格式的图片异或。在这里是图片1。这样形成的链是1,4,5,6。


这是一个方法理解它,还有一个是:


图片6是FORMAT20格式的,它的REFOFFS域包含了链中第一个FORMAT40格式图片的号码,在这里是图片4。所以图片 1先画,然后是图片4,下面从图片4到图片6的所有图片都和前面的图片异或。


我得到了一些经验发现你可以不用FORMAT20和FORMAT40的图片。我尝试的把所有这些格式的图片转换成FORMAT80格式也照样工作。


同样,当变换图片时,注意所有的单元和建筑都要用GDI颜色来画,图片将自动的被转换。 [译者注]这里我没搞懂什么意思。你还是看看E文吧!


你使用的调色板可以是在DESERT.MIX、WINTER.MIX和TEMPERAT.MIX中发现的调色板中的一个。GDI颜色是0B0H--0BFH。其他的颜色将不能被改变,并且要和所有的SIDES保持一致(要确信使用所有三个调色板中相同的颜色)。 [译者注]这里我也没搞懂什么意思。你还是看看E文吧!


前面说的仅仅针对在三个特殊场景显示的图片(SHP文件在CONQUER.MIX中)。在单独场景显示的结构和覆盖图片(在特殊MIX文件中)能够使用在场景中单独的调色板并且可以和其他的混合使用。


也有一种特殊的颜色被用作阴影,它是颜色04H,在调色板中是“亮绿色”,但是C&C用一种阴影代替它,我不知道阴影是如何计算出的。 [译者注]这里我又没搞懂什么意思。你还是看看E文吧!


你要注意数组有 NUMIMAGES+2 个元素(仅只有NUMIMAGES申明)。最后一个是零,倒数第二个指着最后一个文件。这两个可以用来判断是否是SHP文件。


Format80 格式[Top]


在文件中有几个不同尺寸的命令,从1个字节到5个字节。


下面提及的位置总是参考目标缓冲区(比如,未压缩的图象)。相对位置是相对目标缓冲区的当前位置。也就是最后写入的一个字节。


我将在后面给一个例子代码。


 


(1) 1 byte

+---+---+---+---+---+---+---+---+

| 1 | 0 | | | | | | |

+---+---+---+---+---+---+---+---+

\_______________________/

|

Count


意义:拷贝下面 Count 个字节从源到目标。


(2) 2 bytes

+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+

| 0 | | | | | | | | | | | | | | | | |

+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+

\___________/\__________________________________________________/

| |

Count-3 Relative Pos.



意义:拷贝 Count 个字节从目标 当前-Rel 位置到目标当前的位置。注意你要

加3在位4--6字节上来得到Count。注意如果 Rel 是1,说明重复 Count

次前一个的字节。


(3) 3 bytes

+---+---+---+---+---+---+---+---+ +---+---+

| 1 | 1 | | | | | | | | | |

+---+---+---+---+---+---+---+---+ +---+---+

\_______________________/ Pos

|

Count-3



意义:拷贝 Count 个字节从位置 Pos(绝对于目标缓冲区的开始)。Pos是字,

所以图象不能超过 64K 。



(4) 4 bytes

+---+---+---+---+---+---+---+---+ +---+---+ +---+

| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | | | | | |

+---+---+---+---+---+---+---+---+ +---+---+ +---+

Count Color



意义:写‘Count’次‘Color’。‘Count’是字,‘color’是字节。



(5) 5 bytes

+---+---+---+---+---+---+---+---+ +---+---+ +---+---+

| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | | | | | |

+---+---+---+---+---+---+---+---+ +---+---+ +---+---+

Count Pos


意义:从目标拷贝‘Count’个字节。开始于‘Pos’。‘Pos’绝对于目标缓冲

区的开始。‘Count’和‘Pos’是字。

这是我所发现的所有命令。可能还有其他的命令。但我没有发现。


所有的图象都是结束于‘80h’命令


为了搞的更清楚,这里提供了一些代码用来解压缩图象。 [译者注]我加了部分注释


 


DP = 目标缓冲区指针

SP = 源缓冲区指针


SP:=0;

DP:=0;

repeat

Com:=Source[SP];

inc(SP);

b7:=Com shr 7; {b7 is bit 7 of Com}

case b7 of

0 : begin {copy command (2)}

{Count is bits 4-6 + 3}

Count:=(Com and $7F) shr 4 + 3;

{Position is bits 0-3, with bits 0-7 of next byte}

Posit:=(Com and $0F) shl 8+Source[SP];

Inc(SP);

{Starting pos=Cur pos. - calculated value}

Posit:=DP-Posit;

for i:=Posit to Posit+Count-1 do

begin

Dest[DP]:=Dest[i];

Inc(DP);

end;

end;

1 : begin

{Check bit 6 of Com}

b6:=(Com and $40) shr 6;

case b6 of

0 : begin {Copy as is command (1)}

Count:=Com and $3F; {mask 2 topmost bits}

if Count=0 then break; {EOF marker}

for i:=1 to Count do

begin

Dest[DP]:=Source[SP];

Inc(DP);

Inc(SP);

end;

end;

1 : begin {large copy, very large copy and fill commands}

{Count = (bits 0-5 of Com) +3}

{if Com=FEh then fill, if Com=FFh then very large copy}

Count:=Com and $3F;

if Count<$3E then {large copy (3)}

begin

Inc(Count,3);

{Next word = pos. from start of image}

Posit:=Word(Source[SP]);

Inc(SP,2);

for i:=Posit to Posit+Count-1 do

begin

Dest[DP]:=Dest[i];

Inc(DP);

end;

end

else if Count=$3F then {very large copy (5)}

begin

{next 2 words are Count and Pos}

Count:=Word(Source[SP]);

Posit:=Word(Source[SP+2]);

Inc(SP,4);

for i:=Posit to Posit+Count-1 do

begin

Dest[DP]:=Dest[i];

Inc(DP);

end;

end else

begin {Count=$3E, fill (4)}

{Next word is count, the byte after is color}

Count:=Word(Source[SP]);

Inc(SP,2);

b:=Source[SP];

Inc(SP);

for i:=0 to Count-1 do

begin

Dest[DP]:=b;

inc(DP);

end;

end;

end;

end;

end;

end;

until false;

注意:你不可能编译这个代码,因为它没有类型声明。不过你可以修改它。


Format40 格式[Top]


我已说过FORMAT40格式的图片要和前面的图片或和黑色背景(如WSA格式)异或。


这被用在从一幅图片到另一幅图片的微小变化。


这里我假设旧图片是目标,并且目标指针指在缓冲去的开始。


象FORMAT80格式同样也有很多的命令:


 


(1) 1 byte

byte

+---+---+---+---+---+---+---+---+

| 1 | | | | | | | |

+---+---+---+---+---+---+---+---+

\___________________________/

|

Count



意义: 跳过目标‘count’个字节。 (向前移动指针)。



(2) 3 bytes

byte word

+---+---+---+---+---+---+---+---+ +---+-+---+

| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 0 | ... | |

+---+---+---+---+---+---+---+---+ +---+-+---+

\_____________/

|

Count



意义:跳过‘count’个字节。



(3) 3 bytes

byte word

+---+---+---+---+---+---+---+---+ +---+---+-+---+

| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 1 | 0 | ... | |

+---+---+---+---+---+---+---+---+ +---+---+-+---+

\_____________/

|

Count



意义:异或下面‘count’个字节。这意味把源的字节和目标字节异或。



(4) 4 bytes

byte word byte

+---+---+---+---+---+---+---+---+ +---+---+-+---+ +---+

| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 1 | 1 | ... | | | |

+---+---+---+---+---+---+---+---+ +---+---+-+---+ +---+

\_____________/ value

|

Count



意义:用‘Value’异或目标缓冲区中的‘count’个字节。



5) 1 byte

byte

+---+---+---+---+---+---+---+---+

| 0 | | | | | | | |

+---+---+---+---+---+---+---+---+

\___________________________/

|

Count



意义:用目标异或源缓冲区‘count’个字节。



6) 3 bytes

byte byte byte

+---+---+---+---+---+---+---+---+ +---+ +---+

| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | |

+---+---+---+---+---+---+---+---+ +---+ +---+

Count Value


意义:用‘Value’异或‘Count’个字节。

所有的图片都是结束于一个 80h 00h 00h 命令。我想这是所有的命令,但是可能还有其他的命令。如果你发现了请EMAIL我。象前面一样,这有一些代码:


 


DP = 目标缓冲区指针

SP = 源缓冲区指针



SP:=0;

DP:=0;

repeat

Com:=Source[SP];

Inc(SP);



if (Com and $80)<>0 then {if bit 7 set}

begin

if Com<>$80 then {small skip command (1)}

begin

Count:=Com and $7F;

Inc(DP,Count);

end

else {Big commands}

begin

Count:=Word(Source[SP]);

if Count=0 then break;

Inc(SP,2);



Tc:=(Count and $C000) shr 14; {Tc=two topmost bits of count}



case Tc of

0,1 : begin {Big skip (2)}

Inc(DP,Count);

end;

2 : begin {big xor (3)}

Count:=Count and $3FFF;

for i:=1 to Count do

begin

Dest[DP]:=Dest[DP] xor Source[SP];

Inc(DP);

Inc(SP);

end;

end;

3 : begin {big repeated xor (4)}

Count:=Count and $3FFF;

b:=Source[SP];

Inc(SP);

for i:=1 to Count do

begin

Dest[DP]:=Dest[DP] xor b;

Inc(DP);

end;

end;

end;

end;

end else {xor command}

begin

Count:=Com;

if Count=0 then

begin {repeated xor (6)}

Count:=Source[SP];

Inc(SP);

b:=Source[SP];

Inc(SP);

for i:=1 to Count do

begin

Dest[DP]:=Dest[DP] xor b;

Inc(DP);

end;

end else {copy xor (5)}

for i:=1 to Count do

begin

Dest[DP]:=Dest[DP] xor Source[SP];

Inc(DP);

Inc(SP);

end;

end;

until false;


六. .CPS 文件[Top]


CPS 文件包含了 320x200x256 图象。图象是用FORMAT80格式压缩的。它有或没有调色板。


图象的头(HEAD)是如下结构:


Header : record

Size : word; {文件大小: size - 2}

Unknown : word; {总是 0004h}

ImSize : word; {未压缩图象的大小 (总是 0FA00h)}

Palette : longint; {是否有调色板}

end;

如果 Palette 是 03000000h 那么在头后面有调色板,否则就没有。没有调色板的CPS文件可以在SETUP.MIX文件中发现。它们都使用相同的调色板,调色板在相同的MIX文件中。


[译者注] 在'红色警报'中增加了一种PCX图片,这是在WIN95下使用的,因为PCX可以支持 640x480。CPS文件只支持320x200。


七. .WSA 文件[Top]


WSA文件包含短小的动画,这可以在GENERAL.MIX文件中找到。它们都是一系列的FORMAT40 格式的图片,用FORMAT80格式压缩。


文件头是:


Header : record

NumFrames : word; {帧的数量}

X,Y : word; {屏幕左上角的坐标}

W,H : word; {图片的宽和高}

Delta : longint; {播放的速度 帧/秒 = Delta/(2^10)}

end;

接下来是一个偏移量数组:


Offsets : array [0..NumFrames+1] of longint;

为了得到实际的数据偏移量,你应该加上300H。那是数组后调色板的大小。


在SHP文件中最后两个偏移量有着特殊的含义。如果最后一个偏移量是0,那么前面一个偏移量指着最后一帧(当然你要加上300H)。如果最后一个偏移量不是0,那么它指着最后一帧,前面一个偏移量指着一个特殊帧,他指出了最后一帧和开始帧的差别。这在循环播放动画时非常有用。


我前面说了,图象是用FORMAT40格式的,同时是用FORMAT80格式压缩的。所以你要先解压缩,再解码。


第一帧的图象通常是和黑底图象(用0填充)异或的,其他的图象是和前面的图象异或。


在SETUP.MIX有一些不同的文件,它们没有调色板,可是我不能把它解码。(可能有一些命令我不知道)....


八. 附录[Top]


VQA文件(包含动画)已经被Aaron Glover (arn@ibm.net)解码了,并且在他的文章中有详细的解释。你可以在我的主页上找到(或直接问他)。


不过仍然没有提供 AUD 文件格式。AUD 文件可能是用一种有损压缩的音乐文件。这将很难被解码。如果有人解码了,我将很欣赏他。


我知道我解释的不好(译者:再加上我的翻译,哈哈!),但是你不得不忍受。除非有人想重新写一遍。


九. 声明[Top]


我要感谢以下的朋友:


-Andrew Griffin (buggy@adam.com.au) .

-Aaron Glover (arn@ibm.net) 和

Denis Moeller (d.moeller@rendsburg.netsurf.de) 提供了 SHP 文件信息.

-Aaron Glover 提供 VQA 文件解码.

-Carl Kenner (andrew.kenner@unisa.edu.au) 提供 CPS 文件信息.

[后记][Top]


这里提供的是OLD C&C 的文件格式。对于‘红色警报’,MIX文件的头部分现在无法 搞定,可能被随机数加了密。另‘红色警报’新增了一种文件格式:RMT。这些都在 RAMIX分析工具中有说明(不是格式说明)。如果有谁知道了这些内容请告诉我。我 的EMAIL在文件尾。另外,我提供了一个RAMIXER文件分析工具。它提供了强大的分 析功能。


[联系地址]

作者 Vladan Bato (i3100785@univ.trieste.it)

http://www.geocities.com/SiliconValley/8682


译者 Sunway (codingboy@126.com)

http://codingboy.163.net/

http://codingboy.soim.net/