| 1 |
|
|---|
| 2 | COMMAND & CONQUER FILE FORMATS
|
|---|
| 3 |
|
|---|
| 4 | Revision 4
|
|---|
| 5 |
|
|---|
| 6 | by Vladan Bato (bat22@geocities.com)
|
|---|
| 7 |
|
|---|
| 8 | This document explains the file formats used by Command & Conquer.
|
|---|
| 9 |
|
|---|
| 10 | Command & Conquer is a tradmark of Westwood Studios, Inc.
|
|---|
| 11 | Command & Conquer is Copyright (C)1995 Westwood Studios, Inc.
|
|---|
| 12 |
|
|---|
| 13 | The information provided here is meant for programmers that want to make
|
|---|
| 14 | editor and utilites for Command & Conquer. My explanation might not be
|
|---|
| 15 | the best one, but it should be enough.
|
|---|
| 16 |
|
|---|
| 17 | I can't guarantee that the information in here is correct. If you find any
|
|---|
| 18 | errors, please report them to me.
|
|---|
| 19 |
|
|---|
| 20 | In this document I'll use Pascal notation, and any code samples will be in
|
|---|
| 21 | Pascal....
|
|---|
| 22 | I wanted to rewrite them in C, but I don't have the time to test the code.
|
|---|
| 23 | So, to avoid any risks, I'll use the code from Mix Manager.
|
|---|
| 24 |
|
|---|
| 25 | In case you don't know, the information contained here has been used to
|
|---|
| 26 | make the program Mix Manager, which contains a lot of conversion utilities
|
|---|
| 27 | for the various formats. For more info, check my homepage (see the end of the
|
|---|
| 28 | document).
|
|---|
| 29 |
|
|---|
| 30 | ===================
|
|---|
| 31 | 1. THE .MIX FILES
|
|---|
| 32 | ===================
|
|---|
| 33 |
|
|---|
| 34 | You probably already know the format of these files, but I will add a
|
|---|
| 35 | description here for completeness.
|
|---|
| 36 |
|
|---|
| 37 | The MIX file consists of two parts :
|
|---|
| 38 | -A header including the index of all the files contained within
|
|---|
| 39 | -A body containing all the files
|
|---|
| 40 |
|
|---|
| 41 | It's format is :
|
|---|
| 42 |
|
|---|
| 43 | Header : record
|
|---|
| 44 | NumFiles : word; {Number of files in MIX}
|
|---|
| 45 | DataSize : longint; {Size of body}
|
|---|
| 46 | Index : array [1..NumFiles] of
|
|---|
| 47 | record
|
|---|
| 48 | ID : longint; {File ID}
|
|---|
| 49 | Start : longint; {Offset of file from the start of the body}
|
|---|
| 50 | Size : longint; {file size}
|
|---|
| 51 | end;
|
|---|
| 52 | end;
|
|---|
| 53 |
|
|---|
| 54 | The ID field is computed from the original filename, which is not stored in
|
|---|
| 55 | the MIX.
|
|---|
| 56 | The records are always sorted by the ID field (the numbers are signed
|
|---|
| 57 | longints).
|
|---|
| 58 | Note that the offsets are relative to the start of the body so to find the
|
|---|
| 59 | actual offset in the MIX you have to add the size of the header which is
|
|---|
| 60 | NumFiles*12+6
|
|---|
| 61 |
|
|---|
| 62 | ===================
|
|---|
| 63 | 2. THE .PAL FILES
|
|---|
| 64 | ===================
|
|---|
| 65 |
|
|---|
| 66 | The most easiest files....
|
|---|
| 67 | These files contain the palette in the same format used by VGA cards.
|
|---|
| 68 |
|
|---|
| 69 | Palette : array [0..255] of record
|
|---|
| 70 | red,green,blue:byte;
|
|---|
| 71 | end;
|
|---|
| 72 |
|
|---|
| 73 | Note that only the first 6 bits of each number are used, giving a total of
|
|---|
| 74 | 262144 possible colors (as opposed to the 8 bits used by .PCX files for
|
|---|
| 75 | example).
|
|---|
| 76 |
|
|---|
| 77 | =================================
|
|---|
| 78 | 3. THE TEMPLATE AND .BIN FILES
|
|---|
| 79 | =================================
|
|---|
| 80 |
|
|---|
| 81 | The Template files contain the map graphics, and can be found in the
|
|---|
| 82 | theater specific MIX files (TEMPERAT.MIX, WINTER.MIX, DESERT.MIX).
|
|---|
| 83 | The .BIN files contain the maps for the missions and are used in conjunction
|
|---|
| 84 | with the .INI files.
|
|---|
| 85 |
|
|---|
| 86 | I won't explain them here. They are explained with great detail in the
|
|---|
| 87 | document titled "Command & Conquer maps" I wrote some time ago.
|
|---|
| 88 | The said document can be found on my homepage.
|
|---|
| 89 |
|
|---|
| 90 | ===================
|
|---|
| 91 | 5. THE .SHP FILES
|
|---|
| 92 | ===================
|
|---|
| 93 |
|
|---|
| 94 | The .SHP files contain almost all the graphics : units, structures, trees,...
|
|---|
| 95 | The header has the following structure :
|
|---|
| 96 |
|
|---|
| 97 | Header : record
|
|---|
| 98 | NumImages : word; {Number of images}
|
|---|
| 99 | A,B : word; {Unknown}
|
|---|
| 100 | Width,
|
|---|
| 101 | Height : word; {Width and Height of the images}
|
|---|
| 102 | C : longint; {Unknown}
|
|---|
| 103 | end;
|
|---|
| 104 |
|
|---|
| 105 | If you know something about those unknown fields, please e-mail me.
|
|---|
| 106 | Following that there's an array of records, one for each image :
|
|---|
| 107 |
|
|---|
| 108 | Offsets : array [0..NumImages+1] of
|
|---|
| 109 | record
|
|---|
| 110 | Offset : longint; {Offset and format of image in file}
|
|---|
| 111 | RefOffs : longint; {Offset and format of image on
|
|---|
| 112 | which it is based}
|
|---|
| 113 | end;
|
|---|
| 114 |
|
|---|
| 115 | The most significant byte (last) of the Offset and RefOffs fields
|
|---|
| 116 | contains the format, while the lower three are used for the offset.
|
|---|
| 117 | The format byte can have one of the three values : 80h, 40h, 20h.
|
|---|
| 118 | I will call the three image formats Format80, Format40 and Format20.
|
|---|
| 119 |
|
|---|
| 120 | The Format80 images are compressed with a compression method I'll explain
|
|---|
| 121 | later.
|
|---|
| 122 |
|
|---|
| 123 | The Format40 images must be xor-ed with a Format80 image. That's what the
|
|---|
| 124 | RefOffs field is used for. It tells which Format80 image they are
|
|---|
| 125 | based upon. The Format40 will be explained in detail later.
|
|---|
| 126 |
|
|---|
| 127 | The Format20 images use the same format as the Format40, the difference is
|
|---|
| 128 | that they are xor-ed with the image that precedes them in the file. That can
|
|---|
| 129 | be either in Format20 or in Format40.
|
|---|
| 130 | The offset part of the RefOffs field contains the number of the first
|
|---|
| 131 | Format40 image in the chain, and the format field is always 48h.
|
|---|
| 132 |
|
|---|
| 133 | Here's an example :
|
|---|
| 134 |
|
|---|
| 135 | 0) Off0(three bytes) 80h 000000h 00h
|
|---|
| 136 | 1) Off1(three bytes) 80h 000000h 00h
|
|---|
| 137 | 2) Off2(three bytes) 40h Off1 80h
|
|---|
| 138 | 3) Off3(three bytes) 80h 000000h 00h
|
|---|
| 139 | 4) Off4(three bytes) 40h Off1 80h
|
|---|
| 140 | 5) Off5(three bytes) 20h 000400h 48h
|
|---|
| 141 | 6) Off6(three bytes) 20h 000400h 48h
|
|---|
| 142 | 7) Off7(three bytes) 40h Off3 80h
|
|---|
| 143 |
|
|---|
| 144 | For example to draw image 7, you have to draw the image 3 first (whose offset
|
|---|
| 145 | and format are given) and then xor image 7 over it.
|
|---|
| 146 |
|
|---|
| 147 | To draw image 6, you have to xor it over the previous image, i.e. 5, which
|
|---|
| 148 | is format20 again, that means that it has to be xor-ed over image 4, which
|
|---|
| 149 | is in format40, i.e. it must be xor-ed over the image in format80 it has a
|
|---|
| 150 | reference to. In this case it's image 1. Thus the chain is 1,4,5,6.
|
|---|
| 151 | This is one way to see it, the other could be :
|
|---|
| 152 | Image 6 is in Format20, the RefOffs field contains the number of the first
|
|---|
| 153 | Format40 image in the chain, in this case image 4. To draw Image 4, the
|
|---|
| 154 | Image 1 has to be drawn first, next is image 4, and then all the images
|
|---|
| 155 | from the 4th to the 6th have to be xor-ed over the previous.
|
|---|
| 156 |
|
|---|
| 157 | I made some experiments and found out that you don't have to use the
|
|---|
| 158 | Format40 and Format20 images. I tried converting all of them into Format80
|
|---|
| 159 | and it worked.
|
|---|
| 160 |
|
|---|
| 161 | Also, when changing graphics, note that all the unit and structure graphics
|
|---|
| 162 | should be drawn using the GDI colors, which will be automatically converted
|
|---|
| 163 | for the other sides.
|
|---|
| 164 | The palette you should use is one of those found in DESERT.MIX, WINTER.MIX
|
|---|
| 165 | and TEMPERAT.MIX. The GDI colors are colors 0B0h-0BFh. The other colors
|
|---|
| 166 | won't be converted and will remain the same for all the sides (be sure to
|
|---|
| 167 | use only the colors that are the same all three palettes).
|
|---|
| 168 |
|
|---|
| 169 | The above applies only to the graphics that appear in all three theaters
|
|---|
| 170 | (the .SHP file found in CONQUER.MIX). The graphics for the structures and
|
|---|
| 171 | overlays that appear in a single theater (found inside the theater specific
|
|---|
| 172 | MIX) can use the palette entries that are unique for that theater (and will
|
|---|
| 173 | be shown with garbled colors in the others).
|
|---|
| 174 |
|
|---|
| 175 | Also a special color is used for shadows. It's color 04h. In the palettes
|
|---|
| 176 | it's bright green, but C&C puts a shadow instead of it. I don't know how
|
|---|
| 177 | the shadows are calculated however.
|
|---|
| 178 |
|
|---|
| 179 | You should've noticed that the array has NumImages+2 elements when only
|
|---|
| 180 | NumImages elements are needed. The last one contains zeros, and the one before
|
|---|
| 181 | that points to the end of the file. These two can be used to identify the file
|
|---|
| 182 | as a .SHP.
|
|---|
| 183 |
|
|---|
| 184 | Here's the description of the compression formats : Format80 and Format40.
|
|---|
| 185 |
|
|---|
| 186 | ----------
|
|---|
| 187 | Format80
|
|---|
| 188 | ----------
|
|---|
| 189 |
|
|---|
| 190 | There are several different commands, with different sizes : form 1 to 5
|
|---|
| 191 | bytes.
|
|---|
| 192 | The positions mentioned below always refer to the destination buffer (i.e.
|
|---|
| 193 | the uncompressed image). The relative positions are relative to the current
|
|---|
| 194 | position in the destination buffer, which is one byte beyond the last written
|
|---|
| 195 | byte.
|
|---|
| 196 |
|
|---|
| 197 | I will give some sample code at the end.
|
|---|
| 198 |
|
|---|
| 199 | (1) 1 byte
|
|---|
| 200 | +---+---+---+---+---+---+---+---+
|
|---|
| 201 | | 1 | 0 | | | | | | |
|
|---|
| 202 | +---+---+---+---+---+---+---+---+
|
|---|
| 203 | \_______________________/
|
|---|
| 204 | |
|
|---|
| 205 | Count
|
|---|
| 206 |
|
|---|
| 207 | This one means : copy next Count bytes as is from Source to Dest.
|
|---|
| 208 |
|
|---|
| 209 | (2) 2 bytes
|
|---|
| 210 | +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
|
|---|
| 211 | | 0 | | | | | | | | | | | | | | | | |
|
|---|
| 212 | +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
|
|---|
| 213 | \___________/\__________________________________________________/
|
|---|
| 214 | | |
|
|---|
| 215 | Count-3 Relative Pos.
|
|---|
| 216 |
|
|---|
| 217 | This means copy Count bytes from Dest at Current Pos.-Rel. Pos. to
|
|---|
| 218 | Current position.
|
|---|
| 219 | Note that you have to add 3 to the number you find in the bits 4-6 of the
|
|---|
| 220 | first byte to obtain the Count.
|
|---|
| 221 | Note that if the Rel. Pos. is 1, that means repeat Count times the previous
|
|---|
| 222 | byte.
|
|---|
| 223 |
|
|---|
| 224 | (3) 3 bytes
|
|---|
| 225 | +---+---+---+---+---+---+---+---+ +---------------+---------------+
|
|---|
| 226 | | 1 | 1 | | | | | | | | | |
|
|---|
| 227 | +---+---+---+---+---+---+---+---+ +---------------+---------------+
|
|---|
| 228 | \_______________________/ Pos
|
|---|
| 229 | |
|
|---|
| 230 | Count-3
|
|---|
| 231 |
|
|---|
| 232 | Copy Count bytes from Pos, where Pos is absolute from the start of the
|
|---|
| 233 | destination buffer. (Pos is a word, that means that the images can't be
|
|---|
| 234 | larger than 64K)
|
|---|
| 235 |
|
|---|
| 236 | (4) 4 bytes
|
|---|
| 237 | +---+---+---+---+---+---+---+---+ +-------+-------+ +-------+
|
|---|
| 238 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | | | | | |
|
|---|
| 239 | +---+---+---+---+---+---+---+---+ +-------+-------+ +-------+
|
|---|
| 240 | Count Color
|
|---|
| 241 |
|
|---|
| 242 | Write Color Count times.
|
|---|
| 243 | (Count is a word, color is a byte)
|
|---|
| 244 |
|
|---|
| 245 | (5) 5 bytes
|
|---|
| 246 | +---+---+---+---+---+---+---+---+ +-------+-------+ +-------+-------+
|
|---|
| 247 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | | | | | |
|
|---|
| 248 | +---+---+---+---+---+---+---+---+ +-------+-------+ +-------+-------+
|
|---|
| 249 | Count Pos
|
|---|
| 250 |
|
|---|
| 251 | Copy Count bytes from Dest. starting at Pos. Pos is absolute from the start
|
|---|
| 252 | of the Destination buffer.
|
|---|
| 253 | Both Count and Pos are words.
|
|---|
| 254 |
|
|---|
| 255 | These are all the commands I found out. Maybe there are other ones, but I
|
|---|
| 256 | haven't seen them yet.
|
|---|
| 257 |
|
|---|
| 258 | All the images end with a 80h command.
|
|---|
| 259 |
|
|---|
| 260 | To make things more clearer here's a piece of code that will uncompress the
|
|---|
| 261 | image.
|
|---|
| 262 |
|
|---|
| 263 | DP = destination pointer
|
|---|
| 264 | SP = source pointer
|
|---|
| 265 | Source and Dest are the two buffers
|
|---|
| 266 |
|
|---|
| 267 |
|
|---|
| 268 | SP:=0;
|
|---|
| 269 | DP:=0;
|
|---|
| 270 | repeat
|
|---|
| 271 | Com:=Source[SP];
|
|---|
| 272 | inc(SP);
|
|---|
| 273 | b7:=Com shr 7; {b7 is bit 7 of Com}
|
|---|
| 274 | case b7 of
|
|---|
| 275 | 0 : begin {copy command (2)}
|
|---|
| 276 | {Count is bits 4-6 + 3}
|
|---|
| 277 | Count:=(Com and $7F) shr 4 + 3;
|
|---|
| 278 | {Position is bits 0-3, with bits 0-7 of next byte}
|
|---|
| 279 | Posit:=(Com and $0F) shl 8+Source[SP];
|
|---|
| 280 | Inc(SP);
|
|---|
| 281 | {Starting pos=Cur pos. - calculated value}
|
|---|
| 282 | Posit:=DP-Posit;
|
|---|
| 283 | for i:=Posit to Posit+Count-1 do
|
|---|
| 284 | begin
|
|---|
| 285 | Dest[DP]:=Dest[i];
|
|---|
| 286 | Inc(DP);
|
|---|
| 287 | end;
|
|---|
| 288 | end;
|
|---|
| 289 | 1 : begin
|
|---|
| 290 | {Check bit 6 of Com}
|
|---|
| 291 | b6:=(Com and $40) shr 6;
|
|---|
| 292 | case b6 of
|
|---|
| 293 | 0 : begin {Copy as is command (1)}
|
|---|
| 294 | Count:=Com and $3F; {mask 2 topmost bits}
|
|---|
| 295 | if Count=0 then break; {EOF marker}
|
|---|
| 296 | for i:=1 to Count do
|
|---|
| 297 | begin
|
|---|
| 298 | Dest[DP]:=Source[SP];
|
|---|
| 299 | Inc(DP);
|
|---|
| 300 | Inc(SP);
|
|---|
| 301 | end;
|
|---|
| 302 | end;
|
|---|
| 303 | 1 : begin {large copy, very large copy and fill commands}
|
|---|
| 304 | {Count = (bits 0-5 of Com) +3}
|
|---|
| 305 | {if Com=FEh then fill, if Com=FFh then very large copy}
|
|---|
| 306 | Count:=Com and $3F;
|
|---|
| 307 | if Count<$3E then {large copy (3)}
|
|---|
| 308 | begin
|
|---|
| 309 | Inc(Count,3);
|
|---|
| 310 | {Next word = pos. from start of image}
|
|---|
| 311 | Posit:=Word(Source[SP]);
|
|---|
| 312 | Inc(SP,2);
|
|---|
| 313 | for i:=Posit to Posit+Count-1 do
|
|---|
| 314 | begin
|
|---|
| 315 | Dest[DP]:=Dest[i];
|
|---|
| 316 | Inc(DP);
|
|---|
| 317 | end;
|
|---|
| 318 | end
|
|---|
| 319 | else if Count=$3F then {very large copy (5)}
|
|---|
| 320 | begin
|
|---|
| 321 | {next 2 words are Count and Pos}
|
|---|
| 322 | Count:=Word(Source[SP]);
|
|---|
| 323 | Posit:=Word(Source[SP+2]);
|
|---|
| 324 | Inc(SP,4);
|
|---|
| 325 | for i:=Posit to Posit+Count-1 do
|
|---|
| 326 | begin
|
|---|
| 327 | Dest[DP]:=Dest[i];
|
|---|
| 328 | Inc(DP);
|
|---|
| 329 | end;
|
|---|
| 330 | end else
|
|---|
| 331 | begin {Count=$3E, fill (4)}
|
|---|
| 332 | {Next word is count, the byte after is color}
|
|---|
| 333 | Count:=Word(Source[SP]);
|
|---|
| 334 | Inc(SP,2);
|
|---|
| 335 | b:=Source[SP];
|
|---|
| 336 | Inc(SP);
|
|---|
| 337 | for i:=0 to Count-1 do
|
|---|
| 338 | begin
|
|---|
| 339 | Dest[DP]:=b;
|
|---|
| 340 | inc(DP);
|
|---|
| 341 | end;
|
|---|
| 342 | end;
|
|---|
| 343 | end;
|
|---|
| 344 | end;
|
|---|
| 345 | end;
|
|---|
| 346 | end;
|
|---|
| 347 | until false;
|
|---|
| 348 |
|
|---|
| 349 | Note that you won't be able to compile this code, because the typecasting
|
|---|
| 350 | won't work. (But I'm sure you'll be able to fix it).
|
|---|
| 351 |
|
|---|
| 352 |
|
|---|
| 353 | ----------
|
|---|
| 354 | Format40
|
|---|
| 355 | ----------
|
|---|
| 356 |
|
|---|
| 357 | As I said before the images in Format40 must be xor-ed over a previous image,
|
|---|
| 358 | or against a black screen (as in the .WSA format).
|
|---|
| 359 | It is used when there are only minor changes between an image and a following
|
|---|
| 360 | one.
|
|---|
| 361 |
|
|---|
| 362 | Here I'll assume that the old image is in Dest, and that the Dest pointer is
|
|---|
| 363 | set to the beginning of that buffer.
|
|---|
| 364 |
|
|---|
| 365 | As for the Format80, there are many commands :
|
|---|
| 366 |
|
|---|
| 367 |
|
|---|
| 368 | (1) 1 byte
|
|---|
| 369 | byte
|
|---|
| 370 | +---+---+---+---+---+---+---+---+
|
|---|
| 371 | | 1 | | | | | | | |
|
|---|
| 372 | +---+---+---+---+---+---+---+---+
|
|---|
| 373 | \___________________________/
|
|---|
| 374 | |
|
|---|
| 375 | Count
|
|---|
| 376 |
|
|---|
| 377 | Skip count bytes in Dest (move the pointer forward).
|
|---|
| 378 |
|
|---|
| 379 | (2) 3 bytes
|
|---|
| 380 | byte word
|
|---|
| 381 | +---+---+---+---+---+---+---+---+ +---+-----+-------+
|
|---|
| 382 | | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 0 | ... | |
|
|---|
| 383 | +---+---+---+---+---+---+---+---+ +---+-----+-------+
|
|---|
| 384 | \_____________/
|
|---|
| 385 | |
|
|---|
| 386 | Count
|
|---|
| 387 |
|
|---|
| 388 | Skip count bytes.
|
|---|
| 389 |
|
|---|
| 390 | (3) 3 bytes
|
|---|
| 391 | byte word
|
|---|
| 392 | +---+---+---+---+---+---+---+---+ +---+---+-----+-------+
|
|---|
| 393 | | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 1 | 0 | ... | |
|
|---|
| 394 | +---+---+---+---+---+---+---+---+ +---+---+-----+-------+
|
|---|
| 395 | \_____________/
|
|---|
| 396 | |
|
|---|
| 397 | Count
|
|---|
| 398 |
|
|---|
| 399 | Xor next count bytes. That means xor count bytes from Source with bytes
|
|---|
| 400 | in Dest.
|
|---|
| 401 |
|
|---|
| 402 | (4) 4 bytes
|
|---|
| 403 | byte word byte
|
|---|
| 404 | +---+---+---+---+---+---+---+---+ +---+---+-----+-------+ +-------+
|
|---|
| 405 | | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 1 | 1 | ... | | | |
|
|---|
| 406 | +---+---+---+---+---+---+---+---+ +---+---+-----+-------+ +-------+
|
|---|
| 407 | \_____________/ value
|
|---|
| 408 | |
|
|---|
| 409 | Count
|
|---|
| 410 |
|
|---|
| 411 | Xor next count bytes in Dest with value.
|
|---|
| 412 |
|
|---|
| 413 | 5) 1 byte
|
|---|
| 414 | byte
|
|---|
| 415 | +---+---+---+---+---+---+---+---+
|
|---|
| 416 | | 0 | | | | | | | |
|
|---|
| 417 | +---+---+---+---+---+---+---+---+
|
|---|
| 418 | \___________________________/
|
|---|
| 419 | |
|
|---|
| 420 | Count
|
|---|
| 421 |
|
|---|
| 422 | Xor next count bytes from source with dest.
|
|---|
| 423 |
|
|---|
| 424 | 6) 3 bytes
|
|---|
| 425 | byte byte byte
|
|---|
| 426 | +---+---+---+---+---+---+---+---+ +-------+ +-------+
|
|---|
| 427 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | |
|
|---|
| 428 | +---+---+---+---+---+---+---+---+ +-------+ +-------+
|
|---|
| 429 | Count Value
|
|---|
| 430 |
|
|---|
| 431 | Xor next count bytes with value.
|
|---|
| 432 |
|
|---|
| 433 |
|
|---|
| 434 | All images end with a 80h 00h 00h command.
|
|---|
| 435 |
|
|---|
| 436 | I think these are all the commands, but there might be some other.
|
|---|
| 437 | If you find anything new, please e-mail me.
|
|---|
| 438 |
|
|---|
| 439 | As before here's some code :
|
|---|
| 440 |
|
|---|
| 441 | DP = destination pointer
|
|---|
| 442 | SP = source pointer
|
|---|
| 443 | Source is buffer containing the Format40 data
|
|---|
| 444 | Dest is the buffer containing the image over which the second has
|
|---|
| 445 | to be xor-ed
|
|---|
| 446 |
|
|---|
| 447 |
|
|---|
| 448 | SP:=0;
|
|---|
| 449 | DP:=0;
|
|---|
| 450 | repeat
|
|---|
| 451 | Com:=Source[SP];
|
|---|
| 452 | Inc(SP);
|
|---|
| 453 |
|
|---|
| 454 | if (Com and $80)<>0 then {if bit 7 set}
|
|---|
| 455 | begin
|
|---|
| 456 | if Com<>$80 then {small skip command (1)}
|
|---|
| 457 | begin
|
|---|
| 458 | Count:=Com and $7F;
|
|---|
| 459 | Inc(DP,Count);
|
|---|
| 460 | end
|
|---|
| 461 | else {Big commands}
|
|---|
| 462 | begin
|
|---|
| 463 | Count:=Word(Source[SP]);
|
|---|
| 464 | if Count=0 then break;
|
|---|
| 465 | Inc(SP,2);
|
|---|
| 466 |
|
|---|
| 467 | Tc:=(Count and $C000) shr 14; {Tc=two topmost bits of count}
|
|---|
| 468 |
|
|---|
| 469 | case Tc of
|
|---|
| 470 | 0,1 : begin {Big skip (2)}
|
|---|
| 471 | Inc(DP,Count);
|
|---|
| 472 | end;
|
|---|
| 473 | 2 : begin {big xor (3)}
|
|---|
| 474 | Count:=Count and $3FFF;
|
|---|
| 475 | for i:=1 to Count do
|
|---|
| 476 | begin
|
|---|
| 477 | Dest[DP]:=Dest[DP] xor Source[SP];
|
|---|
| 478 | Inc(DP);
|
|---|
| 479 | Inc(SP);
|
|---|
| 480 | end;
|
|---|
| 481 | end;
|
|---|
| 482 | 3 : begin {big repeated xor (4)}
|
|---|
| 483 | Count:=Count and $3FFF;
|
|---|
| 484 | b:=Source[SP];
|
|---|
| 485 | Inc(SP);
|
|---|
| 486 | for i:=1 to Count do
|
|---|
| 487 | begin
|
|---|
| 488 | Dest[DP]:=Dest[DP] xor b;
|
|---|
| 489 | Inc(DP);
|
|---|
| 490 | end;
|
|---|
| 491 | end;
|
|---|
| 492 | end;
|
|---|
| 493 | end;
|
|---|
| 494 | end else {xor command}
|
|---|
| 495 | begin
|
|---|
| 496 | Count:=Com;
|
|---|
| 497 | if Count=0 then
|
|---|
| 498 | begin {repeated xor (6)}
|
|---|
| 499 | Count:=Source[SP];
|
|---|
| 500 | Inc(SP);
|
|---|
| 501 | b:=Source[SP];
|
|---|
| 502 | Inc(SP);
|
|---|
| 503 | for i:=1 to Count do
|
|---|
| 504 | begin
|
|---|
| 505 | Dest[DP]:=Dest[DP] xor b;
|
|---|
| 506 | Inc(DP);
|
|---|
| 507 | end;
|
|---|
| 508 | end else {copy xor (5)}
|
|---|
| 509 | for i:=1 to Count do
|
|---|
| 510 | begin
|
|---|
| 511 | Dest[DP]:=Dest[DP] xor Source[SP];
|
|---|
| 512 | Inc(DP);
|
|---|
| 513 | Inc(SP);
|
|---|
| 514 | end;
|
|---|
| 515 | end;
|
|---|
| 516 | until false;
|
|---|
| 517 |
|
|---|
| 518 |
|
|---|
| 519 |
|
|---|
| 520 | ===================
|
|---|
| 521 | 6. THE .CPS FILES
|
|---|
| 522 | ===================
|
|---|
| 523 |
|
|---|
| 524 | The .CPS files contain 320x200x256 images. The images are compressed with the
|
|---|
| 525 | Format80 compression method. They may or may not contain a palette.
|
|---|
| 526 |
|
|---|
| 527 | The header has the following structure :
|
|---|
| 528 |
|
|---|
| 529 | Header : record
|
|---|
| 530 | Size : word; {File size - 2}
|
|---|
| 531 | Unknown : word; {Always 0004h}
|
|---|
| 532 | ImSize : word; {Size of uncompressed image (always 0FA00h)}
|
|---|
| 533 | Palette : longint; {Is there a palette ?}
|
|---|
| 534 | end;
|
|---|
| 535 |
|
|---|
| 536 | If Palette is 03000000h then there's a palette after the header, otherwise
|
|---|
| 537 | the image follows.
|
|---|
| 538 | CPS file without palette can be found in the SETUP.MIX file, and they all use
|
|---|
| 539 | the Palette that can be found inside the same .MIX.
|
|---|
| 540 |
|
|---|
| 541 | The image that follows the palette (or the Header) is in Format80 which is
|
|---|
| 542 | explained above.
|
|---|
| 543 |
|
|---|
| 544 | ===================
|
|---|
| 545 | 7. THE .WSA FILES
|
|---|
| 546 | ===================
|
|---|
| 547 |
|
|---|
| 548 |
|
|---|
| 549 | WSA files contain short animations and can be found in the GENERAL.MIX files.
|
|---|
| 550 | They are basically a series of Format40 images, that are then compressed with
|
|---|
| 551 | Format80.
|
|---|
| 552 |
|
|---|
| 553 | The header is :
|
|---|
| 554 |
|
|---|
| 555 | Header : record
|
|---|
| 556 | NumFrames : word; {Number of frames}
|
|---|
| 557 | X,Y : word; {Position on screen of the upper left corner}
|
|---|
| 558 | W,H : word; {Width and height of the images}
|
|---|
| 559 | Delta : longint; {Frames/Sec = Delta/(2^10)}
|
|---|
| 560 | end;
|
|---|
| 561 |
|
|---|
| 562 | Following that there's an array of offsets :
|
|---|
| 563 |
|
|---|
| 564 | Offsets : array [0..NumFrames+1] of longint;
|
|---|
| 565 |
|
|---|
| 566 | The obtain the actual offset, you have to add 300h. That is the size of the
|
|---|
| 567 | palette that follows the Offsets array.
|
|---|
| 568 | As for .SHP files the two last offsets have a special meaning.
|
|---|
| 569 | If the last offset is 0 then the one before it points to the end of file
|
|---|
| 570 | (after you added 300h of course).
|
|---|
| 571 | If the last one is <>0 then it points to the end of the file, and the
|
|---|
| 572 | one before it points to a special frame that gives you the difference between
|
|---|
| 573 | the last and the first frame. This is used when you have to loop the
|
|---|
| 574 | animation.
|
|---|
| 575 |
|
|---|
| 576 | As I said before, the images are in Format40 but are then compressed with
|
|---|
| 577 | Format80. That means that you first have to uncompress the Format80 and then
|
|---|
| 578 | decode the Format40 image you obtain.
|
|---|
| 579 | The first frame should be xor-ed over a black image (filled with zeros), all
|
|---|
| 580 | the other are xor-ed over the previous one.
|
|---|
| 581 |
|
|---|
| 582 | There is a variant of the file without the palette that can be found in
|
|---|
| 583 | SETUP.MIX but I wasn't able to decode it (maybe there are some commands I
|
|---|
| 584 | don't know about)...
|
|---|
| 585 |
|
|---|
| 586 | =====================
|
|---|
| 587 | 8. ADDITIONAL NOTES
|
|---|
| 588 | =====================
|
|---|
| 589 |
|
|---|
| 590 | The VQA files (that contain movies) have been decoded by Aaron Glover
|
|---|
| 591 | (arn@ibm.net), and are explained in a document he wrote up.
|
|---|
| 592 | You can find the document on my homepage (or ask him directly).
|
|---|
| 593 |
|
|---|
| 594 | What is still missing are the .AUD files.
|
|---|
| 595 | It seems that the AUD files use some kind of lossy sound compression,
|
|---|
| 596 | which means that it is almost impossible to decode them.
|
|---|
| 597 | However if someone manages to work them out, I'd really appreciate some
|
|---|
| 598 | info.
|
|---|
| 599 |
|
|---|
| 600 | I know my explanations are not very good, but you'll have to bear them,
|
|---|
| 601 | unless someone else wants to rewrite this.
|
|---|
| 602 |
|
|---|
| 603 | ============
|
|---|
| 604 | 9. CREDITS
|
|---|
| 605 | ============
|
|---|
| 606 |
|
|---|
| 607 | I wish to thank the following people :
|
|---|
| 608 |
|
|---|
| 609 | -Andrew Griffin (buggy@adam.com.au) for starting it all.
|
|---|
| 610 | -Aaron Glover (arn@ibm.net) and
|
|---|
| 611 | Denis Moeller (d.moeller@rendsburg.netsurf.de) for their work on .SHP files.
|
|---|
| 612 | -Aaron Glover for decoding the VQA files.
|
|---|
| 613 | -Carl Kenner (andrew.kenner@unisa.edu.au) for the info on .CPS files.
|
|---|
| 614 |
|
|---|
| 615 |
|
|---|
| 616 | Vladan Bato (bat22@geocities.com)
|
|---|
| 617 | http://www.geocities.com/SiliconValley/8682
|
|---|
| 618 |
|
|---|