Command & Conquer Wiki

Welcome to the Command & Conquer Wiki! Log in and join the community.

READ MORE

Command & Conquer Wiki
Advertisement
THE RED ALERT FILE FORMATS GUIDE
			
Release v1.4
Last Updated: 18th April 1997
(c) 1997 Gavin Pugh
(email - rascenedit@geocities.com)
(WWW - http://www.geocities.com/TimesSquare/Arcade/5553)
 
 
 
 
 
     The purpose of this guide is to detail the structure of files used
in the Game Red Alert, for use to create utilities or editors.
 
     Command & Conquer : Red Alert is a trademark and copyright of
Westwood Studios, and is so acknowledged.
Any trademarks not mentioned here are still acknowledged.
 
 
 
If you intend to use quite a bit of this guide in your FAQ or similar
text then I would quite like to hear from you, as I can create a reference
to it in my guide. Also I want be credited if you use parts of this guide in your own.
 
Any use of information in this guide should credit the relevant author,
(me in most cases), in such programs as utilities and editors.
 
If you have a contribution then please email it to the above address, it'll be more than
welcome, and of course, you'll be credited for it, any help is appreciated.
 
Web Site Authors : You are welcome (and encouraged) to have my guide on your page(s), as
long as you do not modify the HTML file in any way whatsoever, and also I request that you include
a link on your site to my site at the address at the bottom of this document.
 
Enough of the legal crap, enjoy....
 
MIX Files
 
All MIX files I have seen can be used with the old C&C utilites, with the MIX headers
following this format, In Red Alert only the more minor MIX files hidden in the CD
directories follow the normal MIX format, the others are RMIX files.
 
+--------+------------------------+------+
| HEADER | ARRAY OF OFFSETS/SIZES | BODY |
+--------+------------------------+------+
 
struct MIXheader {
    WORD   NumFiles;  //Number Of Files In the MIX
    LONG   DataSize;  //Size Of The Body
};
 
The Array of offsets has one entry for each file:
 
struct MIXrec {
    LONG   FileID;  //The ID Of The File, derived from the name of the file
    LONG   Offset;  //Offset Of The FIle From The Start Of The Body
    LONG   Size;    //Size Of The File
};
 
If you know how the ID is calculated, I'd like to hear it, just for completeness.
 
 
RMIX Files
 
However, the two which don't though are : MAIN.MIX and REDALERT.MIX. These both contain
other MIX files which also can't be read by Mixman.
I'll refer to these 'special' MIX files as RMIX from now on, as a few others working
on MIX files have done.
 
Here is a list of all the RMIX files I have found:
MAIN.MIX          ;Contains most other MIX files
REDALERT.MIX
MOVIES1.MIX
MOVIES2.MIX
GENERAL.MIX
SCORES.MIX
CONQUER.MIX
SPEECH.MIX
SOUNDS.MIX
RUSSIAN.MIX
ALLIES.MIX
LOCAL.MIX
LORES.MIX
HIRES.MIX
NCHIRES.MIX
EDITOR.MIX
EDHI.MIX
EDLO.MIX
TRANSIT.MIX
and SC*.MIX and SS*.MIX, probably used on Counterstrike
 
Well, so far I can amount the structure of an RMIX to:
 
+--------+------+
| HEADER | BODY |
+--------+------+
 
The header is an encoded representation of where and how long each file is in
the body section.
The body where all the contained files are, stored one after the other, with
nothing inbetween.
RMIX Header
I can almost definately say that the headers include at least:
* The offsets of the files, from the start of the body.
* The lengths of the files
* And some sort of ID, similar to the C&C one.
 
Looking at MAIN.MIX, it is structured like this:
 
         +--------+-------------+----------+----------- ...
         | HEADER | CONQUER.MIX | EDHI.MIX | EDLO.MIX .....
         +--------+-------------+----------+----------- ...
OFFSETS: 0        EC         213903      220D42     222D68
LENGTHS:     EC        213817       D43F       2026
 
Here is the header in HEX View:
00 00 02 00 6E 3A 77 4B 7A BB E8 57 DB 10 8B 77
EC 67 5C 0C D9 8A 6B 50 47 AC 8D A4 31 FD 0A A1
EB CF F1 5F 93 19 4D FD C6 49 3F 10 67 A5 7B E2
5D 11 98 3C B4 D8 35 40 3B 36 E6 B3 13 37 70 9C
3F 3C E0 70 97 47 1F BC CE 1B B0 D1 68 D4 F3 B7
E2 F6 8A 32 C2 4B 7D BF 43 87 0B 40 63 27 77 9E
9E 94 40 86 9A B6 59 09 15 52 D2 8E FB E6 BA B8
6A 15 FC 31 5A 1C 4A 9E 54 B3 F6 98 66 24 DB 5E
33 14 82 3D 6E 6B 7C 37 EF 3D 58 83 A5 08 D8 2F
9C A0 D0 86 6F C7 65 5F 56 EF E8 7E 13 5F 08 5A
1E E3 E1 E7 47 0E 72 34 4C 65 BD DD 71 AC 83 FD
4C 4C D2 A3 85 E5 06 C3 55 18 BE FA 70 01 81 F1
40 31 5E 71 64 BB 54 04 95 1E 51 10 B6 DF 96 6F
71 C4 6A 19 CE 19 DC 3E 85 1C 4B B1 B3 DC 21 79
D7 B1 65 C1 B8 73 C9 77 A5 14 7B 0C
 
(still in progess, I'm uploading my site now, so I'll be stopping here for the mo)
 
 
RMT Files (TMP files in Red Alert) Thanks To Moritz Mertinkat, (and Andrew Griffin for the Xdim/Ydim Info)
 
My Note: These RTM files are used in Red Alert for the map tiles, the 3 theater RMIX files
contain many of these tiles to put over your maps. These tiles are those you can place
using the RA Terrain Editor, but using this method you could also extract the graphics
for the INDOOR theater.
 
The header (in pascal):
 
TRMTHeader = record
    Width    : Word;    {Width of images, always 24 (18h)}
    Height   : Word;    {Heigth of images, always 24 (18h)}
    NumTil   : Word;    {Number of Tiles}
    Unknown1 : Word;
    XDim     : Word;
    YDim     : Word;
    Size     : LongInt; {Size of file}
    ImgStart : LongInt; {Start of image-data}
    Unknown3 : LongInt;
    Unknown4 : LongInt;
    Index2   : LongInt;
    Unknown5 : LongInt;
    Index1   : LongInt; {Offset of "Index"}
  end;
 
  You can use XDim and YDim to determine how the tiles should be used
  to construct the uber-tile. For example, say XDim = 3 and YDim = 2, then
  the uber-tile would be a 3x2 tile. This is probably only of use when
  placing the uber-tile in the first place, as the individual sub-tiles
  would be placed when the map is being drawn. XDim and YDim give you the
  dimensions of the uber-tile.
 
  If XDim and YDim are both equal to 1, then there is no uber-tile. If
  this RMT file holds more than 1 tile, then they are all individual tiles
  and have no special relationship to each other in regards to being parts
  of a larger tile.
 
  Index2-Index1 should be the number of tiles!
 
  Index1 is an offset for an array of bytes:
    Index: ARRAY[1..NumTil] of Byte;
 
  Every entry in this array which points to a specified tile.
  If the entry is 255 (FFh) then the tile is empty!
  An example:
    If you want to display tile 8 of a RMT-file you have to do
    the following:
      - open the file
      - read the header
      - seek to pos. INDEX1
      - read the index
      - read the 9th byte of it (for tile 8, because the index
                                 starts with 0!}
      - seek to: SizeOf(Header) + Index[9] * (24*24)
      - read 576 byte (24*24) and display them!
      - close the file
 
  All the graphics-data is uncompressed!
 
 
PCX-files (Documentation by Moritz Mertinkat)
 
My Note: These PCX files are used for 640x400 images in the Windows 95' version of
Red Alert, where CPS files are used for the 320x200 ones in DOS.
 
PCX-Header (in pascal):
-----------------------
 
  TPCXHeader = RECORD
    Signature : Byte;
    Version   : Byte;
    Encoding  : Byte;
    BitsPixel : Byte;
    XMin      : Word;
    YMin      : Word;
    XMax      : Word;
    YMax      : Word;
    HRes      : Word;
    VRes      : Word;
    Palette16 : ARRAY[1..48] of Byte;
    Reserved  : Byte;
    NumPlanes : Byte;
    BytesLine : Word;
    PalType   : Word;
    Dummy     : ARRAY[1..58] of Byte;
  end;
 
Description:
------------
  Signature:
    10 = ZSoft PCX-files
 
  Version:
    0 = PC Paintbrush v2.5
    2 = Version 2.8 with palette information
    3 = Version 2.8 without palette information
    4 = PC Paintbrush for Windows (Plus for Windows uses Ver 5)
    5 = Version 3.0: Used by Paintbrush in Win3.x and Win95,
        Can be used for 24-bit images!!
        >>>> NOTE: Version 5 is standard!!
 
  PalType:
    1 = Color/BW   (use this one for 256-color images!)
    2 = Grayscale
 
  XMin, XMax, YMin and YMax are the image dimensions.
  HRes and VRes are the horizantal and vertical Resultion
  of the image in DPI. If you create your own PCX-files, set
  HRes and VRes to 300.
 
  The image data is encoded with RLE (Run Length Encoding) and
  follows directly after the header.
 
 
Decoding the PCX-data:
----------------------
First you have to calculate the X- and Y-dimension of the image.
X-dimension:
  Width:= BytesLine*NumPlanes
  (But I've seen, that there's another way doing this:
   Width:= XMax-XMin+1)
 
Y-dimension:
  Height:= YMax-YMin+1
 
Now, read a single byte (B1) from the PCX-file. If the top two bits of
this byte (B1) are set, then the remaining six bits show how many times
you have to duplicate the next byte (after B1) in the file.
[That means: If the byte (B1) is > 192, then it is a "Repeat-byte" and
 you have to duplicate the next byte (after B1) RepeatByte-192 times]
 
If the top two bits are not set, the byte (B1) itself is the data with
a count of one.
[That means: If the byte B1 < 192 then this byte represents a pixel
 itself]
 
Simply do this with all bytes (and don't forget the linebreaks after
Width decoded bytes).
 
If FileSize(PCXFile)-(768+1) = 12 [the byte before the pal-array],
then the following 768 bytes contain the palette information - otherwise
there's no palette.
 
(If you have any questions, comments, ect. please email me:
 Moritz Mertinkat)
 
Some sample-code (in pascal) at:
  http://home.t-online.de/home/moehrchen (TP Programmers Page)
  (Download-area, "PCX-viewer 4.0b for 256-color-bitmaps")
 
 
SHP Files
The SHP files are stored in the MIX files. They are used for the units, icons in the sidebar,
structures and other graphics.
 
A 6 image SHP would look like:
 
[Header][ImgInfo1][ImgInfo2]....[ImgInfo5][ImgInfo6][ImgInfo7][ImgInfo8][THE SHP DATA]
 
Note that the two extra Imginfo parts are special, the last one is all nulls, where
the offset in the penultimate one points to the end of the file.
 
The header for these SHP files is as follows:
 
struct SHPheader {
    WORD   NumImages;  //Number Of Images In SHP file
    WORD   A;          //Unknown (please email me if you know what they are)
    WORD   B;          //Unknown
    WORD   Width;      //Width Of The Images, in pixels
    WORD   Height;     //Height Of The Images, in pixels
    LONG   C;          //Unknown
};
 
Each Image (and those 2 special bits), are represented by a info part here.
 
struct ImgInfo {
 3 BYTES   Offset;     //Offset of image in file
    CHAR   Format;     //Format Of Image (&h80 is Format80, &h40 is Format40, etc..)
    WORD   RefOff;     //Offset of reference image for Format20/40
    WORD   RefForm;    //Format of reference image
};
 
Note that the Offset field is different from C&C, with it being 3 bytes, the RefOff
field may also be 3 bytes now as well, but the Refform can be a word, so it is most
likely not 3 bytes.
 
 
 
 
 
Packed Sections
 
First, in relation to C&C1 where each cell is represented by 2 bytes, as the total map size in
RA seems to be 128x128 then the binary file for the map which could then be fiddled with and read
by third-party editors would be a 128x128x3 byte binary file (=48k). Note that 3 bytes per cell
in a map section are used in RA.
 
(This would definately be needed if an editor was created allowing the creation of INDOOR maps)
To think about.....Maybe putting a 48k SCG01EA.BIN file along with the INI (a'la C&C1), this would
be a solution, but unfortunately the RA terrain editor only handles packed maps :(
(note that NewINIFormat=1 would be needed for this way to work, and the OVERLAY section used instead
of the OverlayPack)
 
This would be a 2-part process:
 
[MapPack]
1=983704304RREREW84790.......
2=8743907547054.........         >    Compressed Binary          >    48k Map Binary
3=.....                               6 8K Chunks In Format80         3 bytes per cell
.....        And So On
..
  <      70 chars a line    >
 
 
Aha! Looked in GAME.DAT for the full alphabet and saw:
                       ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
(This most probably is the same as Base64, but for completeness, I've decoded it myself)
 
Theory:
-------
The GAME.DAT sequence shows that A would be 0, B=1, C=2..... +=62 and /=63
Each character represents 6 bits, arranged as follows
 
6 bits [000000][111111][000000][111111]
 
So in the compressed Binary form:
 
8 bits [00000011][11110000][00111111]
 
The '=' character means take off 2 bits from the byte sequence, this means that
the whole sequence is MOD 8, so doesn't leave any stray bits behind.
 
Now all the data can be handled in normal hex byte form.
 
This Process In Reverse
-----------------------
If you want to get from the byte sequence to the ASCII string again (maybe for a
map tile placing utility), use this:
 
Convert the hex bytes into a long string of bits: (example only here.)
 
09 00 00 20
 
00001001 00000000 00000000 00100000
 
00001001000000000000000000100000
 
Then start pulling out 6 bits at a time and compare with the ASCII table I made
earlier until you've got less than 6 bits left.
 
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
(Where A=0, B=1, C=2,..... +=62, /=63)
 
000010 010000 000000 000000 001000 00
 
>>>>>>>> C Q A A I .....
 
So after making 5 characters, there are 2 bits left, Red Alert needs this to be 6 bits,
so you would need another 4 bits.
As you know, each character means 6 bits, and the '=' character means take the last 2
bits off.
So you would use this idea to pad 4 bits onto the end using 'A=' which means 0000
 
The final string therefore would be:
CQAAIA=
 
And remember that 2 bits could also be left behind, you would use 'A==' in this case.
 
How To Decode The OverlayPack in HEX Form
 
Well, it will produce a 16k binary, with 1 byte representing each cell
 
Here is the format of the packed section
 
[aa bb cc] 20 [.....]
 
Where ccbbaa is the length of the [...] section
 
The &h20 may have a special meaning, but I've no idea yet.
 
There are two of these in each [OverlayPack], with each representing 8k.
 
After a VERY VERY VERY long time, I was able to work out how the [....]
part was coded, just by luck really. Use Format80 to decode this, using
an 8K destination buffer in each case, then join both these together to
get a 16k file.
Look at Appendix A (the Format80 images) for more information on this algorithm.
 
This 16k file produced by the algorithm then reads from left to right like this:
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-+
+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+ ......
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-+
+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+FF+ ...
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
........
 
The top left cell would be offset 0, the one below 128, and the one below
that 256, (the same as the cell number).
 
Here is a table of what each Hex represents in the OverlayPacks:
FF - Blank
00 - Sandbags (SBAG)
01 - Chain-link Fence (CYCL)
02 - Concrete Wall (BRIK)
03 - C&C Barbed Wire (FENC)
04 - Wooden Fence (WOOD)
05 - Ore (GOLD01) Most Dense
06 - Ore (GOLD02)                        The Ore/Gem tiles do not SEEM to be
07 - Ore (GOLD03)                        any different, but they must be, both
08 - Ore (GOLD04) Least Dense            RA and the editor seem to make single
09 - Gems (GEM01) Most Dense             cell gem/ore tiles look the same, and
0A - Gems (GEM02)                        they only look different in clumps.
0B - Gems (GEM03)
0C - Gems (GEM04) Least Dense
0D - Haystacks (V12)
0E - Haystack (V13)
0F - Wheat Field (V14)
10 - Fallow Field (V15)
11 - Corn Field (V16)
12 - Celery Field (V17)
13 - Potato Field (V18)
14 - Circular Thing (FPLS)
15 - Wood Crate (WCRATE)
16 - Silver Crate (SCRATE)
17 - RA Barbed Wire (BARB)
18 - RA Sandbags (exactly same as C&C ones) (SBAG)
 
19
.. - I've only tested 19h and 1Ah, but I assume the rest also crash RA
FE
 
I've noticed that the Water Crate (WWCRATE) is missing, I've tried 19h and 1Ah
onto Water tiles, but it still crashes. Also the concrete floor tile (CONC) is
not there either, although if you look at my scenario creation guide, you can
put both these on using the [OVERLAY] section.
 
Recompressing Overlay Data To An Overlaypack
 
 
 
 
How To Get The 'Compressed' Binary To A Map File
 
It is nearly exactly the same as the overlaypacks,
 
with 6 [....] parts though instead of the two mentioned above.
The map should be 48k when expanded (i.e 3 bytes per cell, 128x128x3)
Using Format80 again for each [...] section, an 8k destination buffer,
and again, splice all these 6 together to make 48k.
 
Here is a simple BASIC-like representation of how it is done:
 
DIM MAP(0 to 127,0 to 127,1 to 3) as byte
 
FOR Y=0 to 127
	FOR X=0 to 127
		GET 1 BYTE, PUT IT INTO MAP(X,Y,1)
		GET 1 BYTE, PUT IT INTO MAP(X,Y,2)
	NEXT
NEXT
FOR Y=0 to 127
	FOR X=0 to 127
		GET 1 BYTE, PUT IT INTO MAP(X,Y,3)
	NEXT
NEXT
 
It is quite strange, but It's Westwood's solution to use more than 256 tiles,
which was the limit in C&C.
 
Well the hex from the new 48k file is 3 bytes per cell, with them meaning
the following :
 
[ xx xx ]  [ xx ]
Tile I.D.  Part Of That Tile
           To Show In That Cell
 
Here are some of them, I'll probably get round to doing a full list sometime,
but I havent checked the old C&C resources for this *yet*.
 
Remember the Tile ID is a word, so I've switched it round (as you should), just
in case you think it looks wrong :)
 
TILE ID  NO. OF PARTS
-------  ------------
FFFF 		? 	- Blank Tile
0001 		? 	- Water
 
Recompressing Map Data back into a MapPack
 
 
 
 
Appendix A : Format80/40/20 Images (thanks to Vladan Bato)
 
I will call the three image formats Format80, Format40 and Format20.
 
The Format80 images are compressed with a compression method I'll explain
later.
 
The Format40 images must be xor-ed with a Format80 image. That's what the
RefOffs and RefForm fields are used for. They tell which Format80 image they
are based upon. The Format40 will be explained in detail later.
 
The Format20 images use the same format as the Format40, the difference is
that they are xor-ed with the image that precedes them in the file. That can
be either in Format20 or in Format40.
The RefOffs field contains the number of the first Format40 image in the
chain, and the RefForm field is always 4800h.
 
Here's an example :
 
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
 
For example to draw image 7, you have to draw the image 3 first (whose offset
and format are given) and then xor image 7 over it.
 
To draw image 6, you have to xor it over the previous image, i.e. 5, which is
format20 again, that means that it has to be xor-ed over image 4, which is in
format40, i.e. it must be xor-ed over the image in format80 it has a reference
to. In this case it's image 1. Thus the chain is 1,4,5,6.
This is one way to see it, the other could be :
Image 6 is in Format20, the RefOffs field contains the number of the first
Format40 image in the chain, in this case image 4. To draw Image 4, the Image
1 has to be drawn first, next is image 4, and then all the images from the 4th
to the 6th have to be xor-ed over the previous.
 
I made some experiments and found out that you don't have to use the Format40
and Format20 images. I tried converting all of them into Format80 and it
worked.
 
Also, when changing graphics, note that all the unit and structure graphics
should be drawn using the GDI colors, which will be automatically converted
for the other sides.
The palette you should use is one of those found in DESERT.MIX, WINTER.MIX
and TEMPERAT.MIX. The GDI colors are colors 0B0h-0BFh. The other colors
won't be converted and will remain the same for all the sides (be sure to
use only the colors that are the same all three palettes).
 
The above applies only to the graphics that appear in all three theaters
(the .SHP file found in CONQUER.MIX). The graphics for the structures and
overlays that appear in a single theater (found inside the theater specific
MIX) can use the palette entries that are unique for that theater (and will
be shown with garbled colors in the others).
 
Also a special color is used for shadows. It's color 04h. In the palettes
it's bright green, but C&C puts a shadow instead of it. I don't know how
the shadows are calculated however.
 
You should've noticed that the array has NumImages+2 elements when only
NumImages elements are needed. The last one contains zeros, and the one before
that points to the end of the file. These two can be used to identify the file
as a .SHP.
 
Here's the description of the compression formats : Format80 and Format40.
 
----------
 Format80
----------
 
There are several different commands, with different sizes : form 1 to 5
bytes.
The positions mentioned below always refer to the destination buffer (i.e.
the uncompressed image). The relative positions are relative to the current
position in the destination buffer, which is one byte beyond the last written
byte.
 
I will give some sample code at the end.
 
(1) 1 byte
      +---+---+---+---+---+---+---+---+
      | 1 | 0 |   |   |   |   |   |   |
      +---+---+---+---+---+---+---+---+
              \_______________________/
                         |
                       Count
 
      This one means : copy next Count bytes as is from Source to Dest.
 
(2) 2 bytes
  +---+---+---+---+---+---+---+---+   +---+---+---+---+---+---+---+---+
  | 0 |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+   +---+---+---+---+---+---+---+---+
      \___________/\__________________________________________________/
            |                             |
         Count-3                    Relative Pos.
 
  This means copy Count bytes from Dest at Current Pos.-Rel. Pos. to
  Current position.
  Note that you have to add 3 to the number you find in the bits 4-6 of the
  first byte to obtain the Count.
  Note that if the Rel. Pos. is 1, that means repeat Count times the previous
  byte.
 
(3) 3 bytes
  +---+---+---+---+---+---+---+---+   +---------------+---------------+
  | 1 | 1 |   |   |   |   |   |   |   |               |               |
  +---+---+---+---+---+---+---+---+   +---------------+---------------+
          \_______________________/                  Pos
                     |
                 Count-3
 
  Copy Count bytes from Pos, where Pos is absolute from the start of the
  destination buffer. (Pos is a word, that means that the images can't be
  larger than 64K)
 
(4) 4 bytes
  +---+---+---+---+---+---+---+---+   +-------+-------+  +-------+
  | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |   |       |       |  |       |
  +---+---+---+---+---+---+---+---+   +-------+-------+  +-------+
                                            Count          Color
 
  Write Color Count times.
  (Count is a word, color is a byte)
 
(5) 5 bytes
  +---+---+---+---+---+---+---+---+   +-------+-------+  +-------+-------+
  | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |   |       |       |  |       |       |
  +---+---+---+---+---+---+---+---+   +-------+-------+  +-------+-------+
                                            Count               Pos
 
  Copy Count bytes from Dest. starting at Pos. Pos is absolute from the start
  of the Destination buffer.
  Both Count and Pos are words.
 
These are all the commands I found out. Maybe there are other ones, but I
haven't seen them yet.
 
All the images end with a 80h command.
 
To make things more clearer here's a piece of code that will uncompress the
image.
 
  DP = destination pointer
  SP = source pointer
  Source and Dest are the two buffers
 
 
  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;
 
Note that you won't be able to compile this code, because the typecasting
won't work. (But I'm sure you'll be able to fix it).
 
 
----------
 Format40
----------
 
As I said before the images in Format40 must be xor-ed over a previous image,
or against a black screen (as in the .WSA format).
It is used when there are only minor changes between an image and a following
one.
 
Here I'll assume that the old image is in Dest, and that the Dest pointer is
set to the beginning of that buffer.
 
As for the Format80, there are many commands :
 
 
(1) 1 byte
               byte
  +---+---+---+---+---+---+---+---+
  | 1 |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+
      \___________________________/
                   |
                 Count
 
  Skip count bytes in Dest (move the pointer forward).
 
(2) 3 bytes
              byte                           word
  +---+---+---+---+---+---+---+---+  +---+-----+-------+
  | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |  | 0 | ... |       |
  +---+---+---+---+---+---+---+---+  +---+-----+-------+
                                         \_____________/
                                                |
                                              Count
 
  Skip count bytes.
 
(3) 3 bytes
                byte                              word
  +---+---+---+---+---+---+---+---+  +---+---+-----+-------+
  | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |  | 1 | 0 | ... |       |
  +---+---+---+---+---+---+---+---+  +---+---+-----+-------+
                                             \_____________/
                                                   |
                                                 Count
 
 Xor next count bytes. That means xor count bytes from Source with bytes
 in Dest.
 
(4) 4 bytes
              byte                               word           byte
  +---+---+---+---+---+---+---+---+  +---+---+-----+-------+  +-------+
  | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |  | 1 | 1 | ... |       |  |       |
  +---+---+---+---+---+---+---+---+  +---+---+-----+-------+  +-------+
                                             \_____________/    value
                                                   |
                                                 Count
 
  Xor next count bytes in Dest with value.
 
5) 1 byte
               byte
  +---+---+---+---+---+---+---+---+
  | 0 |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+
      \___________________________/
                   |
                 Count
 
  Xor next count bytes from source with dest.
 
6) 3 bytes
              byte                     byte       byte
  +---+---+---+---+---+---+---+---+  +-------+  +-------+
  | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |  |       |  |       |
  +---+---+---+---+---+---+---+---+  +-------+  +-------+
                                       Count      Value
 
  Xor next count bytes with value.
 
 
All images end with a 80h 00h 00h command.
 
I think these are all the commands, but there might be some other.
If you find anything new, please e-mail me.
 
As before here's some code :
 
  DP = destination pointer
  SP = source pointer
  Source is buffer containing the Format40 data
  Dest   is the buffer containing the image over which the second has
         to be xor-ed
 
 
  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;
 
 
 
 
Appendix B : CPS Files
The .CPS files contain 320x200x256 images. The images are compressed with the
Format80 compression method. They may or may not contain a palette.
 
The header has the following structure :
 
  Header : record
             Size    : word;  {File size - 2}
             Unknown : word;  {Always 0004h}
             ImSize  : word;  {Size of uncompressed image (always 0FA00h)}
             Palette : longint; {Is there a palette ?}
           end;
 
If Palette is 03000000h then there's a palette after the header, otherwise
the image follows.
CPS file without palette can be found in the SETUP.MIX file, and they all use
the Palette that can be found inside the same .MIX.
 
The image that follows the palette (or the Header) is in Format80 which is
explained above.
 
My Note : The CPS files contain all the full screen Red Alert Images, where
PCX files are used for the 640x400 images used in the Windows '95 version.
 
 
Thanks to:
Westwood for making the great game
 
Everyone who contributed to the "Scenario Creation Guide"
 
Mike Cocca for help on the MapPacks.
 
Moritz Mertinkat for writing RA-MiXer 3.0, I found this very
handy when looking for the offsets, as I myself only could find the SHP files reliably :), and for the RMT/PCX info!
 
Vladan Bato for the C&C Format80/40/20 images
and for the great work on the old C&C MIX files.
 
Andrew Griffin for the correction of the RMT files.
 
Anyone who thinks they deserve it.
 
 
 
Also, email me if you see anything that is wrong, or missing, or should be included, I'll
give you credit for that particular part of course :)
 
 
You'll find the latest version of this text here:
http://www.geocities.com/TimesSquare/Arcade/5553
 
 
(c)Gavin Pugh 1997
rascenedit@geocities.com
Advertisement