ship a proper SDK for modders

including the OpenRA.TilesetBuilder.exe fixes #2316
and auto-generated trait documentation fixes #2437
compile Markdown to HTML for offline use
purge external files from the doc folder (moved to Wiki)
remove unused non-free Dune 2000 font
This commit is contained in:
Matthias Mailänder
2013-03-20 16:20:03 +01:00
parent d0cf627b23
commit 8226fd21f9
19 changed files with 32 additions and 11491 deletions

4
.gitignore vendored
View File

@@ -55,3 +55,7 @@ OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3
# KDE crap # KDE crap
*.kate-swp *.kate-swp
*.directory *.directory
# auto-generated documentation
DOCUMENTATION.md
*.html

View File

@@ -7,7 +7,7 @@ PHONY = core tools package all mods clean distclean
.SUFFIXES: .SUFFIXES:
core: game renderers mods utility tsbuild core: game renderers mods utility tsbuild
tools: editor ralint tsbuild tools: editor ralint tsbuild
package: core editor package: core editor docs
mods: mod_ra mod_cnc mod_d2k mods: mod_ra mod_cnc mod_d2k
all: core tools all: core tools
clean: clean:
@@ -205,6 +205,10 @@ INSTALL = install
INSTALL_PROGRAM = $(INSTALL) INSTALL_PROGRAM = $(INSTALL)
CORE = fileformats rcg rgl rsdl rnull game editor utility tsbuild CORE = fileformats rcg rgl rsdl rnull game editor utility tsbuild
# Documentation (d2k depends on all mod libraries)
docs:
@mono --debug OpenRA.Utility.exe --docs d2k > DOCUMENTATION.md
install: all install: all
@-echo "Installing OpenRA to $(INSTALL_DIR)" @-echo "Installing OpenRA to $(INSTALL_DIR)"
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR) @$(INSTALL_PROGRAM) -d $(INSTALL_DIR)

View File

@@ -491,28 +491,37 @@ namespace OpenRA.Utility
FileSystem.LoadFromManifest(Game.modData.Manifest); FileSystem.LoadFromManifest(Game.modData.Manifest);
Rules.LoadRules(Game.modData.Manifest, new Map()); Rules.LoadRules(Game.modData.Manifest, new Map());
foreach( var t in Game.modData.ObjectCreator.GetTypesImplementing<ITraitInfo>() ) Console.WriteLine("## Documentation");
Console.WriteLine("This documentation is aimed at modders and contributers of OpenRA. Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been automatically generated on {0}.\n", DateTime.Now);
Console.WriteLine("```yaml\n\n");
foreach(var t in Game.modData.ObjectCreator.GetTypesImplementing<ITraitInfo>())
{ {
if (t.ContainsGenericParameters || t.IsAbstract) if (t.ContainsGenericParameters || t.IsAbstract)
continue; // skip helpers like TraitInfo<T> continue; // skip helpers like TraitInfo<T>
var traitName = t.Name.Replace("Info",""); var traitName = t.Name.Replace("Info","");
var traitDesc = t.GetCustomAttributes<DescAttribute>(false).Select(a => a.Description).FirstOrDefault(); var traitDesc = t.GetCustomAttributes<DescAttribute>(false).Select(a => a.Description).FirstOrDefault();
if (string.IsNullOrEmpty(traitDesc))
traitDesc = "Trait documentation is missing.";
Console.WriteLine("{0}:", traitName); Console.WriteLine("\t{0}: # {1}", traitName, traitDesc);
var liveTraitInfo = Game.modData.ObjectCreator.CreateBasic(t); var liveTraitInfo = Game.modData.ObjectCreator.CreateBasic(t);
foreach(var f in t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)) foreach(var f in t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
{ {
var fieldDesc = f.GetCustomAttributes<DescAttribute>(true).Select(a => a.Description).FirstOrDefault(); var fieldDesc = f.GetCustomAttributes<DescAttribute>(true).Select(a => a.Description).FirstOrDefault();
if (string.IsNullOrEmpty(fieldDesc))
fieldDesc = "No description provided.";
var fieldType = NiceTypeName(f.FieldType); var fieldType = NiceTypeName(f.FieldType);
var defaultValue = FieldSaver.SaveField(liveTraitInfo, f.Name).Value.Value; var defaultValue = FieldSaver.SaveField(liveTraitInfo, f.Name).Value.Value;
if (string.IsNullOrEmpty(defaultValue)) if (string.IsNullOrEmpty(defaultValue))
defaultValue = "(none)"; defaultValue = "";
Console.WriteLine("\t{0}: {2} # type: {1}", f.Name, fieldType, defaultValue); Console.WriteLine("\t\t{0}: {2} # Type: {1}, {3}", f.Name, fieldType, defaultValue, fieldDesc);
} }
} }
Console.WriteLine("\n```");
} }
} }
} }

View File

@@ -64,6 +64,7 @@ namespace OpenRA.Utility
Console.WriteLine(" --remap SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP Remap SHPs to another palette"); Console.WriteLine(" --remap SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP Remap SHPs to another palette");
Console.WriteLine(" --r8 R8FILE PALETTE START END FILENAME [--noshadow] [--infrantry] [--vehicle] [--projectile] [--building] [--wall] [--tileset] Convert Dune 2000 DATA.R8 to PNGs choosing start- and endframe as well as type for correct offset to append multiple frames to one PNG named by filename optionally removing the shadow."); Console.WriteLine(" --r8 R8FILE PALETTE START END FILENAME [--noshadow] [--infrantry] [--vehicle] [--projectile] [--building] [--wall] [--tileset] Convert Dune 2000 DATA.R8 to PNGs choosing start- and endframe as well as type for correct offset to append multiple frames to one PNG named by filename optionally removing the shadow.");
Console.WriteLine(" --transpose SRCSHP DESTSHP START N M [START N M ...] Transpose the N*M block of frames starting at START."); Console.WriteLine(" --transpose SRCSHP DESTSHP START N M [START N M ...] Transpose the N*M block of frames starting at START.");
Console.WriteLine(" --docs MOD Generate trait documentation in MarkDown format.");
} }
static string GetNamedArg(string[] args, string arg) static string GetNamedArg(string[] args, string arg)

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,229 +0,0 @@
THE AUD FILE FORMAT
Revision 3
by Vladan Bato (bat22@geocities.com)
In this document I'll try to describe the AUD file format used in
Command & Conquer and Redalert.
Command & Conquer is a trademark of Westwood Studios, Inc.
Command & Conquer is Copyright (C)1995 Westwood Studios, Inc.
Command & Conquer: Red Alert is a trademark of Westwood Studios, Inc.
Command & Conquer: Red Alert is Copyright (C)1995,1996 Westwood Studios, Inc.
The information provided here is for anyone who would like to make an
AUD player program or AUD to WAV or WAV to AUD converters.
Most information about AUD files and IMA-ADPCM compression has been
provided by Douglas McFadyen.
I won't explain here the format of the WAV files. You'll have to find this
info yourself. I'll just tell you how to obtain 16-bit PCM data and how
to encode it.
I will use Pascal-like notation throughout this document.
===============================
0. IMPRTANT NOTE - WHAT'S NEW
===============================
This revision contains an important difference in the IMA-ADPCM compression
routine. Instead of computing the diffrence between the current and
previous sample, it computes the difference between the current sample
and the value that the decoding routine will predict for the previous
sample.
This is the way the algorithm is implemented in C&C.
If you implement it the way it was in previous revisions of this document,
the sound will be the same but there will be a "pop" sound at the end.
==============
1. AUD FILES
==============
The AUD files have the following header :
Header : record
SamplesPerSec : word; {Frequency}
Size : longint; {Size of file (without header)}
OutSize : longint; {Size of ouput data}
Flags : byte; {bit 0=stereo, bit 1=16bit}
Typ : byte; {1=WW compressed, 99=IMA ADPCM}
end;
There are two types of compression. The first is the IMA-ADPCM compression
used for 16-bit sound. It's used in most AUD files.
The other one is a Westwood's proprietary compression for 8-bit sound and
is used only for death screams. I won't describe it in this document
because I don't know how it works.
The rest of the AUD files is divided in chunks. These are usually 512
bytes long, except for the last one.
Each chunk has the following header :
ChunkHd : record
Size : word; {Size of compressed data}
OutSize : word; {Size of ouput data}
ID : longint; {Always $0000DEAF}
end;
The IMA-ADPCM compression compresses 16-bit samples to 4 bits. This means
that OutSize will be apporximately 4*Size.
The IMA-ADPCM compression and decompression are described in the following
sections.
Note that the current sample value and index into the Step Table should
be initialized to 0 at the start and are mantained across the chunks
(see below).
==========================
2. IMA-ADPCM COMPRESSION
==========================
I won't describe the theory behind the IMA-ADPCM compression. I will just
give some pseudo code to compress and decompress data.
The compression algorithm takes a stream of signed 16-bit samples in input
and produces a stream of 4-bit codes in output.
The 4-bit codes are stored in pairs (two codes in one byte). The first one
is stored in the lower four bits.
Two varaibles must be mantained while compressing : the previous sample
value and the current index into the step table.
You can find the Step Table in Appendix B.
The Index adjustment table is in Appendix A.
Here's the pseudo-code that will do the compression :
Index:=0;
Prev_Sample:=0;
while there_is_more_data do
begin
Cur_Sample:=Get_Next_Sample;
Delta:=Cur_Sample-Prev_Sample;
if Delta<0 then
begin
Delta:=-Delta;
Sb:=1;
end else Sb:=0;
{Sb is bit 4 of the output Code (sign bit)}
Code := 4*Delta div Step_Table[Index];
if Code>7 then Code:=7;
{These are the 3 low-order bits of output code}
Index:=Index+Index_Adjust[Code];
if Index<0 then Index:=0;
if Index>88 the Index:=88;
Predicted_Delta:=(Step_Table[Index]*Code) div 4 +
Step_Table[Index] div 8;
{This is the Delta that decoding routine will compute}
Prev_Sample:=Prev_Sample+Predicted_Delta;
if Prev_Sample>32767 then Prev_Sample:=32767
else if Prev_Sample<-32768 then Prev_Sample:=-32768;
{Prev_Sample is the sample value that the decoding routine
will compute}
Output_Code(Code+Sb*8);
end;
Note that this code is usually implemented in more efficient manner
(No need to divide).
The Get_Next_Sample function should return the next sample from the input
buffer.
The Output_Code function should store the 4-bit code to the output buffer.
One byte contains two 4-bit codes, and this function should take care of
this.
============================
3. IMA-ADPCM DECOMPRESSION
============================
It is the exact opposite of the above. It receives 4-bit codes in input
and produce 16-bit samples in output.
Again you have to mantain an Index into the Step Table an the current
sample value.
The tables used are the same as for compression.
Here's the code :
Index:=0;
Cur_Sample:=0;
while there_is_more_data do
begin
Code:=Get_Next_Code;
if (Code and $8) <> 0 then Sb:=1 else Sb:=0;
Code:=Code and $7;
{Separate the sign bit from the rest}
Delta:=(Step_Table[Index]*Code) div 4 + Step_Table[Index] div 8;
{The last one is to minimize errors}
if Sb=1 then Delta:=-Delta;
Cur_Sample:=Cur_Sample+Delta;
if Cur_Sample>32767 then Cur_Sample:=32767
else if Cur_Sample<-32768 then Cur_Sample:=-32768;
Output_Sample(Cur_Sample);
Index:=Index+Index_Adjust[Code];
if Index<0 then Index:=0;
if Index>88 the Index:=88;
end;
Again, this can be done more efficiently (no need for multiplication).
The Get_Next_Code function should return the next 4-bit code. It must
extract it from the input buffer (note that two 4-bit codes are stored
in the same byte, the first one in the lower bits).
The Output_Sample function should write the signed 16-bit sample to the
output buffer.
=========================================
Appendix A : THE INDEX ADJUSTMENT TABLE
=========================================
Index_Adjust : array [0..7] of integer = (-1,-1,-1,-1,2,4,6,8);
=============================
Appendix B : THE STEP TABLE
=============================
Steps_Table : array [0..88] of integer =(
7, 8, 9, 10, 11, 12, 13, 14, 16,
17, 19, 21, 23, 25, 28, 31, 34, 37,
41, 45, 50, 55, 60, 66, 73, 80, 88,
97, 107, 118, 130, 143, 157, 173, 190, 209,
230, 253, 279, 307, 337, 371, 408, 449, 494,
544, 598, 658, 724, 796, 876, 963, 1060, 1166,
1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749,
3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289,
16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 );
---
Vladan Bato (bat22@geocities.com)
http://www.geocities.com/SiliconValley/8682

View File

@@ -1,625 +0,0 @@
COMMAND & CONQUER FILE FORMATS
Revision 4
by Vladan Bato (bat22@geocities.com)
This document explains the file formats used by Command & Conquer.
Command & Conquer is a tradmark of Westwood Studios, Inc.
Command & Conquer is Copyright (C)1995 Westwood Studios, Inc.
The information provided here is meant for programmers that want to make
editor and utilites for Command & Conquer. My explanation might not be
the best one, but it should be enough.
I can't guarantee that the information in here is correct. If you find any
errors, please report them to me.
In this document I'll use Pascal notation, and any code samples will be in
Pascal....
I wanted to rewrite them in C, but I don't have the time to test the code.
So, to avoid any risks, I'll use the code from Mix Manager.
In case you don't know, the information contained here has been used to
make the program Mix Manager, which contains a lot of conversion utilities
for the various formats. For more info, check my homepage (see the end of
the document).
===================
1. THE .MIX FILES
===================
You probably already know the format of these files, but I will add a
description here for completeness.
The MIX file consists of two parts :
-A header including the index of all the files contained within
-A body containing all the files
It's format is :
Header : record
NumFiles : word; {Number of files in MIX}
DataSize : longint; {Size of body}
Index : array [1..NumFiles] of
record
ID : longint; {File ID}
Start : longint; {Offset of file from the start of the
body}
Size : longint; {file size}
end;
end;
The ID field is computed from the original filename, which is not stored in
the MIX.
The records are always sorted by the ID field (the numbers are signed
longints).
Note that the offsets are relative to the start of the body so to find the
actual offset in the MIX you have to add the size of the header which is
NumFiles*12+6
===================
2. THE .PAL FILES
===================
The most easiest files....
These files contain the palette in the same format used by VGA cards.
Palette : array [0..255] of record
red,green,blue:byte;
end;
Note that only the first 6 bits of each number are used, giving a total of
262144 possible colors (as opposed to the 8 bits used by .PCX files for
example).
=================================
3. THE TEMPLATE AND .BIN FILES
=================================
The Template files contain the map graphics, and can be found in the
theater specific MIX files (TEMPERAT.MIX, WINTER.MIX, DESERT.MIX).
The .BIN files contain the maps for the missions and are used in conjunction
with the .INI files.
I won't explain them here. They are explained with great detail in the
document titled "Command & Conquer maps" I wrote some time ago.
The said document can be found on my homepage.
===================
5. THE .SHP FILES
===================
The .SHP files contain almost all the graphics : units, structures,
trees,...
The header has the following structure :
Header : record
NumImages : word; {Number of images}
A,B : word; {Unknown}
Width,
Height : word; {Width and Height of the images}
C : longint; {Unknown}
end;
If you know something about those unknown fields, please e-mail me.
Following that there's an array of records, one for each image :
Offsets : array [0..NumImages+1] of
record
Offset : longint; {Offset and format of image in file}
RefOffs : longint; {Offset and format of image on
which it is based}
end;
The most significant byte (last) of the Offset and RefOffs fields
contains the format, while the lower three are used for the offset.
The format byte can have one of the three values : 80h, 40h, 20h.
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 field is used for. It tells 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 offset part of the RefOffs field contains the number of the first
Format40 image in the chain, and the format field is always 48h.
Here's an example :
0) Off0(three bytes) 80h 000000h 00h
1) Off1(three bytes) 80h 000000h 00h
2) Off2(three bytes) 40h Off1 80h
3) Off3(three bytes) 80h 000000h 00h
4) Off4(three bytes) 40h Off1 80h
5) Off5(three bytes) 20h 000400h 48h
6) Off6(three bytes) 20h 000400h 48h
7) Off7(three bytes) 40h Off3 80h
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;
===================
6. THE .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.
===================
7. THE .WSA FILES
===================
WSA files contain short animations and can be found in the GENERAL.MIX
files.
They are basically a series of Format40 images, that are then compressed
with
Format80.
The header is :
Header : record
NumFrames : word; {Number of frames}
X,Y : word; {Position on screen of the upper left
corner}
W,H : word; {Width and height of the images}
Delta : longint; {Frames/Sec = Delta/(2^10)}
end;
Following that there's an array of offsets :
Offsets : array [0..NumFrames+1] of longint;
The obtain the actual offset, you have to add 300h. That is the size of the
palette that follows the Offsets array.
As for .SHP files the two last offsets have a special meaning.
If the last offset is 0 then the one before it points to the end of file
(after you added 300h of course).
If the last one is <>0 then it points to the end of the file, and the
one before it points to a special frame that gives you the difference
between the last and the first frame. This is used when you have to loop the
animation.
As I said before, the images are in Format40 but are then compressed with
Format80. That means that you first have to uncompress the Format80 and then
decode the Format40 image you obtain.
The first frame should be xor-ed over a black image (filled with zeros), all
the other are xor-ed over the previous one.
There is a variant of the file without the palette that can be found in
SETUP.MIX but I wasn't able to decode it (maybe there are some commands I
don't know about)...
=====================
8. ADDITIONAL NOTES
=====================
The VQA files (that contain movies) have been decoded by Aaron Glover
(arn@ibm.net), and are explained in a document he wrote up.
You can find the document on my homepage (or ask him directly).
What is still missing are the .AUD files.
It seems that the AUD files use some kind of lossy sound compression,
which means that it is almost impossible to decode them.
However if someone manages to work them out, I'd really appreciate some
info.
I know my explanations are not very good, but you'll have to bear them,
unless someone else wants to rewrite this.
============
9. CREDITS
============
I wish to thank the following people :
-Andrew Griffin (buggy@adam.com.au) for starting it all.
-Aaron Glover (arn@ibm.net) and
Denis Moeller (d.moeller@rendsburg.netsurf.de) for their work on .SHP
files.
-Aaron Glover for decoding the VQA files.
-Carl Kenner (andrew.kenner@unisa.edu.au) for the info on .CPS files.
Vladan Bato (bat22@geocities.com)
http://www.geocities.com/SiliconValley/8682

View File

@@ -1,500 +0,0 @@
THE COMMAND & CONQUER MAPS
Rev. 1f
by Vladan Bato (bat22@geocities.com)
This document explains the format of the maps and the associated graphics
files. It has also a complete listing of all available map values.
This document is meant for people who want to make a C&C scenery editor.
You can also use it to edit manually the maps but IMHO it's a suicide if you
can't see what you are doing.
ABOUT .MIX FILES
First of all I will explain the structure of MIX files, since all the
graphics are in the TEMPERAT, DESERT, and WINTER.MIX files.
Each MIX file contains several internal files that can be extracted. I will
refer to the internal files as just "files".
The MIX file is made up of two parts: the first one is the Header, the
second one is the Body that contains all the files.
The structure of the header is:
(I will use pascal notation here)
Header = record
NumFiles : word; {Number of internal files}
BodyLength : longint; {Length of the body}
Index : array [1..NumFiles] of
record
ID : longint; {ID of file, computed from filename}
Start : longint; {Offset of file in the body}
Size : longint; {Size of the file}
end;
end;
Of course you can't use directly such a structure in pascal because its
length is not fixed.
Note that the offsets are relative to the start of the body so to find the
actual offset in the MIX you have to add the size of the header which is
NumFiles*12+6
Note also that the records in the Index are not in the same order as the
files are physically stored in the MIX. In this document I will always refer
to the record number in the index and not to the file's actual position in
the MIX.
ABOUT THE MAP
All the maps are 64x64 squares large. There are 2 bytes of information for
each square, thus the file is 8192 bytes long.
The two bytes indicate which image should be placed there. The first one
indicates in which of the internal files of TEMPERAT, DESERT or WINTER.MIX
it is. Each of these internal files contains several images; the second byte
tells which of those images should be taken. The images inside one of the
internal files, if put together, form a larger image. It can be a bridge,
a road section, etc. These are called "templates". Thus, each internal file
contains a template. Each template is made of several "tiles" (images).
Each square of the map contains one tile. It's not necessary to put all
the tiles of a template on the map.
There are templates of various sizes: from 1x1 to 6x8.
(I will always write the dimensions as WidthxHeight)
The tile numbers range from 0 to WxH-1.
However there are some tiles, which I call "empty tiles", that don't have
any images associated with them. If you try using them C&C will display
the default terrain for that Theater instead. There are empty tiles
especially in the corners of large templates.
An example may be useful:
The SW-NE bridge in the temperate theater has two empty tiles:
XXOr X - Empty tile O - other tiles
wbbO b - Bridge
Obbw w - Water (This is probably wrong, I can't check now)
rOOO r - road
We can see that in the upper left corner there are two empty tiles.
We can put the values 00 and 01 in our map (as the second byte; the first
would be A5h for the bridge), in that case we'll see some grass there. But
we can replace those two tiles with anything else without disturbing the
rest. What I mean, is that if we changed any other tile, a piece of river
would be missing or a rock could be cut, ruining the map; but if we
replace the empty tiles everything is OK.
So, when we have an empty tile, we can leave it there, or replace it with
anything else. There are two exceptions to this rule however:
1) Sometimes the empty tiles should be water, but if we don't replace them
C&C will show land in the middle of our lake or sea;
2) There are templates containing roads that finish in one of the corners,
so that the next template must have an empty tile in the opposite corner
to stick to the other.
An example might help:
Imagine that we have two road sections like these:
OOrr OOrr
Orrr Orrr
rrrO rrrO
rrOO rrOO
and we want to stick them diagonally:
OOrr
Orrr
rrrO
rrOO
OOrr
Orrr
rrrO
rrOO
Something is obviously missing. We need to add some tiles to fill it like
this:
OOrr
Orrr
rrrO
RrrOO
OOrrR
Orrr
rrrO
rrOO
The solution could be to have two templates like these:
OOOO ROOO
OOOO OOOO
OOOO OOOO
OOOR OOOO
or to have one little template with empty tiles:
RX
XR (Where X are empty tiles)
Now we can put this between the two road sections, replacing the empty
tiles with the corner tiles of the road sections.
There are many road sections like this and I've indicated them with
"(Conn.)" in the table at the end of this document.
ABOUT THE DESERT, TEMPERAT, and WINTER.MIX FILES
These are the files that hold the graphics for the templates. There's one
file inside the MIX for each template, and each file has several tiles
inside.
There are other files inside the MIXes, probably for the trees and other
overlay elements but I don't know the format. If somebody knows their
format, please let me know.
In each MIX there's also a palette, the entries are:
DESERT.MIX entry n. 26
TEMPERAT.MIX entry n. 62
WINTER.MIX entry n. 62
I will now explain the format of the files with map graphics.
First of all there's a header with the following structure:
Header = record
Width : word; {Width of images, always 24 (18h)}
Heigth : word; {Heigth of images, always 24}
NumTil : word; {Number of Tiles (may differ from num. of Images}
Zero1 : word; {Seems to be always 0000h}
Size : longint; {size of file}
ImgStart : longint; {Offset of first image}
Zero2 : longint; {Seems to be always 00000000h}
ID1 : word; {Always FFFFh}
ID2 : word; {Always 1A0Dh (or 0D1Ah I can't remeber}
Index2 : longint; {Offset of Index2}
Index1 : longint; {Offset of Index1} {I will explain these
later}
end;
The images follow the header but I suppose they could be anywhere.
They are all 24x24 pixel, uncompressed and are one after the other.
Note that the number of images may differ from the number of tiles if
there are some empty tiles. If there are empty tiles, the actual number of
images can be smaller than the number of tiles. To work out the number
of images you can use the formula : (Index1-ImgStart)/(24*24).
However, you won't have to do this if the index is not corrupt.
Index1 has the following format:
Index1 : array [0..NumTil-1] of byte;
where NumTil is the number of tiles.
Each entry in Index1 corresponds to one tile, and indicates which image
(of that file) is associated with it. If the entry is FFh than that tile
is empty.
Index2 is an array of NumImages bytes where NumImages is the real
number of images in the file. However it's always filled with zeros
(sometimes there's a 1 somewhere but I don't know it's meaning).
Note that there's no way to know the dimensions (Width and Height) of the
template. If there are 6 tiles it could be 6x1, 1x6, 3x2, 2x3. I worked out
the dimensions of all templates myself (It's easy, all you have to do is to
try different widths and look at the screen).
For example a procedure that has to display template 61h, tile 3 of the
Desert theater would do:
1) Look in the table and find in which file it is in (entry 168 of
DESERT.MIX)
2) Open that file (seek it inside the MIX)
3) Read the Header
4) Read Index1 and read the 4th byte (for tile 3), let it be N
5) Seek ImgStart+Width*Height*N
6) Read the Image and display it
AND FINALLY THE TABLE
Here is the table of all available map values (template numbers), the
dimensions and the relative entries in the DESERT, WINTER, and TEMPERAT.MIX.
There's also a brief description for those that don't want or don't know
how to write an editor. However, I think that it will be difficult to stick
the templates together without seeing them.
An "x" means that the template doesn't exist in that theater. There are many
templates that exist only in one theater and will show as black holes in the
others (causing the HOM effect). The WINTER and TEMPERATE theaters are
however very similar, and differ only in a few templates.
The roads and cliffs are mostly the same for the three theaters, but be
careful about the river and coast templates because they are not the same.
V | DES | TEM | WIN | Dim. | Name | Description
-----+-----+-----+-----+-------+----------+---------------------------------
--
00h | 007 | 011 | 028 | [4x4] | CLEAR1 | Default terrain
01h | 002 | 007 | 007 | [1x1] | W1 | Water (not animated)
02h | x | 009 | 009 | [2x2] | W2 | Water
03h | x | 087 | 087 | [3x3] | SH1 | Coast WD (1)
04h | x | 106 | 105 | [3x3] | SH2 | Coast WD
05h | x | 126 | 124 | [1x1] | SH3 | Rock in water
06h | x | 143 | 140 | [2x1] | SH4 | Rock in water
07h | x | 159 | 157 | [3x3] | SH5 | Coast WD
08h | x | 018 | 017 | [3x3] | SH11 | Fjord WD
09h | x | 024 | 023 | [3x3] | SH12 | Coast WU
0Ah | x | 031 | 031 | [3x3] | SH13 | Coast WU
0Bh | x | 037 | 037 | [3x3] | SH14 | Coast WU
0Ch | x | 042 | 042 | [3x3] | SH15 | Coast WU
0Dh | 106 | 074 | 074 | [2x2] | S01 | Cliff Left Edge
0Eh | 122 | 093 | 092 | [2x3] | S02 | Cliff Wu-Wd (2)
0Fh | 138 | 112 | 110 | [2x2] | S03 | Cliff W-E
10h | 154 | 131 | 128 | [2x2] | S04 | Cliff W-E
11h | 170 | 147 | 144 | [2x2] | S05 | Cliff W-E
12h | 185 | 163 | 161 | [2x3] | S06 | Cliff Wd-Eu
13h | 200 | 180 | 179 | [2x2] | S07 | Cliff Right Edge
14h | 212 | 195 | 195 | [2x2] | S08 | Cliff Top Edge
15h | 225 | 208 | 209 | [3x2] | S09 | Cliff N-S
16h | 096 | 064 | 064 | [2x2] | S10 | Cliff N-S
17h | 108 | 078 | 078 | [2x2] | S11 | Cliff N-S
18h | 124 | 097 | 096 | [2x2] | S12 | Cliff N-S
19h | 140 | 117 | 115 | [3x2] | S13 | Cliff N-S
1Ah | 157 | 135 | 132 | [2x2] | S14 | Cliff Bottom Edge
1Bh | 172 | 151 | 149 | [2x2] | S15 | Cliff Left Edge
1Ch | 187 | 167 | 166 | [2x3] | S16 | Cliff Wu-Ed
1Dh | 202 | 184 | 184 | [2x2] | S17 | Cliff W-E
1Eh | 215 | 199 | 200 | [2x2] | S18 | Cliff W-E
1Fh | 228 | 211 | 213 | [2x2] | S19 | Cliff W-E
20h | 098 | 068 | 069 | [2x3] | S20 | Cliff Wu-Ed
21h | 110 | 082 | 082 | [1x2] | S21 | Cliff Right Edge
22h | 126 | 101 | 100 | [2x1] | S22 | Cliff Corner S-E Internal
23h | 142 | 121 | 119 | [3x2] | S23 | Cliff Sl-Nr
24h | 159 | 139 | 136 | [2x2] | S24 | Cliff N-S
25h | 174 | 155 | 153 | [2x2] | S25 | Cliff N-S
26h | 189 | 171 | 170 | [2x2] | S26 | Cliff N-S
27h | 204 | 188 | 188 | [3x2] | S27 | Cliff Nl-Sr
28h | 218 | 202 | 203 | [2x2] | S28 | Cliff Bottom Edge
29h | 230 | 213 | 215 | [2x2] | S29 | Cliff Corner N-E External
2Ah | 101 | 070 | 071 | [2x2] | S30 | Cliff Corner S-E Ext
2Bh | 113 | 084 | 084 | [2x2] | S31 | Cliff Corner W-S Ext
2Ch | 129 | 103 | 102 | [2x2] | S32 | Cliff Corner N-W Ext
2Dh | 145 | 123 | 121 | [2x2] | S33 | Cliff Corner N-E Internal
2Eh | 162 | 141 | 138 | [2x2] | S34 | Cliff Corner S-E Int
2Fh | 177 | 157 | 155 | [2x2] | S35 | Cliff Corner W-S Int
30h | 192 | 173 | 172 | [2x2] | S36 | Cliff Corner W-N Int
31h | 207 | 190 | 190 | [2x2] | S37 | Cliff Junction NW-SE
32h | 221 | 204 | 205 | [2x2] | S38 | Cliff Junction SW-NE
33h | x | 027 | 026 | [3x3] | SH32 | Coast Corner N-W Int
34h | x | 033 | 033 | [3x3] | SH33 | Coast Corner N-E Int
35h | 017 | x | x | [4x1] | SH20 | Coast WD
36h | 024 | x | x | [3x1] | SH21 | Coast WD
37h | 041 | x | x | [6x2] | SH22 | Coast WD
38h | 049 | x | x | [2x2] | SH23 | Coast WD
39h | 118 | x | x | [1x1] | BR1 | Bush
3Ah | 134 | x | x | [1x1] | BR2 | Bush
3Bh | 150 | x | x | [1x1] | BR3 | Cactus
3Ch | 166 | x | x | [1x1] | BR4 | Cactus
3Dh | 181 | x | x | [1x1] | BR5 | ??? Purple square (bug ?)
3Eh | 196 | x | x | [2x2] | BR6 | Bushes
3Fh | 210 | x | x | [2x2] | BR7 | Bushes
40h | 223 | x | x | [3x2] | BR8 | Bushes
41h | 234 | x | x | [3x2] | BR9 | Bushes
42h | 016 | x | x | [2x1] | BR10 | ??? Purple squares (bug ?)
43h | 105 | 073 | x | [1x1] | P01 | Bones / Wall (3)
44h | 121 | 092 | x | [1x1] | P02 | Bones / Wall (3)
45h | 137 | 111 | x | [1x1] | P03 | Mud / UFO (3) (6)
46h | 153 | 130 | x | [1x1] | P04 | Rock / UFO (3) (6)
47h | 169 | x | x | [2x2] | P05 | Gray Sand
48h | 184 | x | x | [6x4] | P06 | Gray Sand
49h | 199 | 179 | 178 | [4x2] | P07 | Mud
4Ah | x | 194 | 194 | [3x2] | P08 | Mud
4Bh | x | 045 | 045 | [3x2] | SH16 | Fjord WU
4Ch | 072 | 047 | 047 | [2x2] | SH17 | Water (anim.)
4Dh | 078 | 049 | 049 | [2x2] | SH18 | Water (anim.)
4Eh | 084 | x | x | [3x2] | SH19 | Coast WD
4Fh | x | 116 | 114 | [3x2] | P13 | Destroyed House
50h | x | 134 | 131 | [2x1] | P14 | Walls
51h | x | x | 148 | [4x2] | P15 | Snow
52h | 001 | 006 | 006 | [1x1] | B1 | Rock
53h | 003 | 008 | 008 | [2x1] | B2 | Rock
54h | x | 010 | 010 | [3x1] | B3 | Rock
55h | 004 | x | x | [1x1] | B4 | ?? Rock (7)
56h | 005 | x | x | [1x1] | B5 | ?? Rock (7)
57h | 006 | x | x | [1x1] | B6 | ?? Rock (7)
58h | x | 175 | 174 | [3x3] | SH6 | Coast WD
59h | x | 191 | 191 | [2x2] | SH7 | Coast Corner W-N External
5Ah | x | 205 | 206 | [3x3] | SH8 | Coast Corner S-E Ext
5Bh | x | 215 | 217 | [3x3] | SH9 | Coast Corner W-S Ext
5Ch | x | 012 | 011 | [2x2] | SH10 | Coast Corner N-E Ext
5Dh | 104 | 072 | 073 | [2x2] | D01 | Road Bottom End
5Eh | 120 | 091 | 091 | [2x2] | D02 | Road Left End
5Fh | 136 | 110 | 109 | [1x2] | D03 | Road Top End
60h | 152 | 129 | 127 | [2x2] | D04 | Road Right End
61h | 168 | 146 | 143 | [3x4] | D05 | Road S-N
62h | 183 | 162 | 160 | [2x3] | D06 | Road S-N
63h | 198 | 178 | 177 | [3x2] | D07 | Road S-N
64h | 211 | 193 | 193 | [3x2] | D08 | Road S-N
65h | 224 | 207 | 208 | [4x3] | D09 | Road W-E
66h | 095 | 063 | 063 | [4x2] | D10 | Road W-E
67h | 107 | 077 | 077 | [2x3] | D11 | Road W-E
68h | 123 | 096 | 095 | [2x2] | D12 | Road W-E
69h | 139 | 115 | 113 | [4x3] | D13 | Road Wu-Ed
6Ah | 156 | 133 | 130 | [3x3] | D14 | Road T N--W+E (4)
6Bh | 171 | 150 | 147 | [3x3] | D15 | Road Y S--N+E (4)
6Ch | 186 | 166 | 164 | [3x3] | D16 | Road Y S--N+E
6Dh | 201 | 183 | 182 | [3x2] | D17 | Road T S--W+E
6Eh | 214 | 198 | 198 | [3x3] | D18 | Road T W--N+S
6Fh | 227 | 210 | 211 | [3x3] | D19 | Road + W-N-E-S
70h | 097 | 067 | 067 | [3x3] | D20 | Road Corner N-E
71h | 109 | 081 | 081 | [3x2] | D21 | Road Corner S-E
72h | 125 | 100 | 099 | [3x3] | D22 | Road Corner W-S
73h | 141 | 120 | 118 | [3x3] | D23 | Road Corner W-N
74h | 158 | 138 | 135 | [3x3] | D24 | Road Diagonal NW-SE (5)
75h | 173 | 154 | 152 | [3x3] | D25 | Road Diag NW-SE
76h | 188 | 170 | 169 | [2x2] | D26 | Road Diag NW-SE (Conn.) (5)
77h | 203 | 187 | 187 | [2x2] | D27 | Road Diag NW-SE (Conn.)
78h | 217 | 201 | 202 | [2x2] | D28 | Road Corner W-SE (Conn.)
79h | 229 | 212 | 214 | [2x2] | D29 | Road Corner N-SE (Conn.)
7Ah | 100 | 069 | 070 | [2x2] | D30 | Road Y SE--N+W (Conn.)
7Bh | 112 | 083 | 083 | [2x2] | D31 | Road Corner E-NW (Conn.)
7Ch | 128 | 102 | 101 | [2x2] | D32 | Road Corner S-NW (Conn.)
7Dh | 144 | 122 | 120 | [2x2] | D33 | Road Y NW--S+E (Conn.)
7Eh | 161 | 140 | 137 | [3x3] | D34 | Road Diag SW-NE
7Fh | 176 | 156 | 154 | [3x3] | D35 | Road Diag SW-NE
80h | 191 | 172 | 171 | [2x2] | D36 | Road Diag SW-NE (Conn.)
81h | 206 | 189 | 189 | [2x2] | D37 | Road Diag SW-NE (Conn.)
82h | 220 | 203 | 204 | [2x2] | D38 | Road Corner E-SW (Conn.)
83h | 232 | 214 | 216 | [2x2] | D39 | Road Corner N-SW (Conn.)
84h | 103 | 071 | 072 | [2x2] | D40 | Road Y SW--N+E (Conn.)
85h | 115 | 085 | 085 | [2x2] | D41 | Road Corner W-NE (Conn.)
86h | 131 | 104 | 103 | [2x2] | D42 | Road Corner S-NE (Conn.)
87h | 147 | 124 | 122 | [2x2] | D43 | Road Y NE--W+S (Conn.)
88h | x | 017 | 016 | [5x4] | RV01 | River W-E
89h | x | 023 | 022 | [5x3] | RV02 | River W-E
8Ah | x | 030 | 030 | [4x4] | RV03 | River Wu-Ed
8Bh | x | 036 | 036 | [4x4] | RV04 | River Wd-Eu
8Ch | x | 041 | 041 | [3x3] | RV05 | River N-S
8Dh | x | 044 | 044 | [3x2] | RV06 | River N-S
8Eh | x | 046 | 046 | [3x2] | RV07 | River N-S
8Fh | x | 048 | 048 | [2x2] | RV08 | River Corner S-E
90h | x | 052 | 052 | [2x2] | RV09 | River Corner W-S
91h | x | 014 | 013 | [2x2] | RV10 | River Corner N-E
92h | x | 020 | 019 | [2x2] | RV11 | River Corner W-N
93h | x | 026 | 025 | [3x4] | RV12 | River Y N--W+S
94h | x | 032 | 032 | [4x4] | RV13 | River Y Eu--W+S
95h | 055 | x | x | [4x3] | RV14 | River W-E
96h | 060 | x | x | [4x3] | RV15 | River W-E
97h | 067 | x | x | [6x4] | RV16 | River Wd-Eu
98h | 073 | x | x | [6x5] | RV17 | River Wu-Ed
99h | 079 | x | x | [4x4] | RV18 | River N-S
9Ah | 085 | x | x | [4x4] | RV19 | River N-S
9Bh | 018 | x | x | [6x8] | RV20 | River Nr-Sl
9Ch | 025 | x | x | [5x8] | RV21 | River Nl-Sr
9Dh | 042 | x | x | [3x3] | RV22 | River Corner E-S
9Eh | 050 | x | x | [3x3] | RV23 | River Corner W-S
9Fh | 057 | x | x | [3x3] | RV24 | River Corner N-E
A0h | 062 | x | x | [3x3] | RV25 | River Corner N-W
A1h | 009 | 002 | 004 | [3x3] | FORD1 | River Crossing (Road W-E)
A2h | 010 | 003 | 005 | [3x3] | FORD2 | River Crossing (Road N-S)
A3h | 047 | 057 | 057 | [3x3] | FALLS1 | Falls W-E
A4h | 048 | 058 | 058 | [3x2] | FALLS2 | Falls N-S
A5h | x | 218 | 220 | [4x4] | BRIDGE1 | Bridge SW-NE
A6h | x | 059 | 059 | [4x4] | BRIDGE1D | Fallen Bridge SW-NE
A7h | x | 219 | 221 | [5x5] | BRIDGE2 | Bridge NW-SE
A8h | x | 060 | 060 | [5x5] | BRIDGE2D | Fallen Bridge NW-SE
A9h | 236 | x | x | [6x5] | BRIDGE3 | Bridge SW-NE
AAh | 092 | x | x | [6x5] | BRIDGE3D | Fallen Bridge SW-NE
ABh | 237 | x | x | [6x4] | BRIDGE4 | Bridge NW-SE
ACh | 093 | x | x | [6x4] | BRIDGE4D | Fallen Bridge NW-SE
ADh | 056 | x | x | [3x3] | SH24 | Fjord WD
AEh | 061 | x | x | [3x2] | SH25 | Coast WU
AFh | 068 | x | x | [3x2] | SH26 | Coast WU
B0h | 074 | x | x | [4x1] | SH27 | Coast WU
B1h | 080 | x | x | [3x1] | SH28 | Coast WU
B2h | 086 | x | x | [6x2] | SH29 | Coast WU
B3h | 019 | x | x | [2x2] | SH30 | Coast WU
B4h | 027 | x | x | [3x3] | SH31 | Fjord WU
B5h | x | x | 165 | [2x2] | P16 | Snow
B6h | x | x | 183 | [4x2] | P17 | Snow
B7h | x | x | 199 | [4x3] | P18 | Snow
B8h | x | x | 212 | [4x3] | P19 | Snow
B9h | x | x | 068 | [4x3] | P20 | Snow
BAh | x | 038 | 038 | [3x3] | SH34 | Coast WR
BBh | x | 043 | 043 | [3x3] | SH35 | Coast WL
BCh | 069 | x | x | [1x1] | SH36 | Coast Corner S-E Int
BDh | 075 | x | x | [1x1] | SH37 | Coast Corner W-S Int
BEh | 081 | x | x | [1x1] | SH38 | Coast Corner N-E Int
BFh | 087 | x | x | [1x1] | SH39 | Coast Corner N-W Int
C0h | 020 | x | x | [3x3] | SH40 | Coast Corner S-E Int
C1h | 028 | x | x | [3x3] | SH41 | Coast Corner N-W Int
C2h | 043 | x | x | [1x2] | SH42 | Coast WL
C3h | 051 | x | x | [1x3] | SH43 | Coast WL
C4h | 058 | x | x | [1x3] | SH44 | Coast WR
C5h | 063 | x | x | [1x2] | SH45 | Coast WR
C6h | 070 | x | x | [3x3] | SH46 | Coast Corner S-E Int
C7h | 076 | x | x | [3x3] | SH47 | Coast Corner S-E Int
C8h | 082 | x | x | [3x3] | SH48 | Coast Corner N-E Int
C9h | 088 | x | x | [3x3] | SH49 | Coast Corner N-W Int
CAh | 021 | x | x | [4x3] | SH50 | Coast Corner S-E Ext
CBh | 029 | x | x | [4x3] | SH51 | Coast Corner W-S Ext
CCh | 044 | x | x | [4x3] | SH52 | Coast Corner N-E Ext
CDh | 052 | x | x | [4x3] | SH53 | Coast Corner N-W Ext
CEh | 059 | x | x | [3x2] | SH54 | Coast WD
CFh | 064 | x | x | [3x2] | SH55 | Coast WD
D0h | 071 | x | x | [3x2] | SH56 | Coast WU
D1h | 077 | x | x | [3x2] | SH57 | Coast WU
D2h | 083 | x | x | [2x3] | SH58 | Coast WR
D3h | 089 | x | x | [2x3] | SH59 | Coast WR
D4h | 022 | x | x | [2x3] | SH60 | Coast WL
D5h | 030 | x | x | [2x3] | SH61 | Coast WL
D6h | 045 | x | x | [6x1] | SH62 | Coast WD
D7h | 053 | x | x | [4x1] | SH63 | Coast WD
!! Warning !!
Values from D8h-FEh will cause the game to crash (it just locks up on
my computer)!!!
The value FFh indicates the default terrain (I think the 4x4 template is
used).
Notes:
(0a) There may be some errors in this table because I typed it in a hurry
(you don't know how much time it takes), so if you find any errors
please report them to me.
(0b) The names are taken from the GAME.DAT file. I matched them with the
files in the theater mix files. The complete filenames are the names
above plus an extension that depends on the theater (.DES, .TEM, .WIN).
(1) For Coasts, WD, WU, WL, and WR mean : Water on the bottom
(Down), Top (Up), left and right.
(2) For cliffs and roads the two letters indicate from which to which side
the Road (or cliff) goes. The lowercase letter means up, down, left,
right to indicate in which part of that side it starts.
For Example:
River Wu-Ed :
OOOOO
rOOOO
OrrOO
OOOrr
OOOOO
(3) These templates exist in both the DESERT and the TEMPERATE theaters but
are not the same. I've put a description of both.
(4) For Roads:
Roads T and Y mean that the road splits in the shape of a T or a Y.
E--N+S means it starts from the east edge then splits in two parts, one
going to the north and the other to the south edge
(5) NW or any other corner means that the road ends in that corner and if it
says (Conn.), that means that it has an empty tile in that corner.
So you have to use the (Conn.) templates to stick together the other
ones.
(6) In TEMPERAT.MIX these two files are buggy, they report there are 67h
tiles, but if you look at the index you'll see they all point to the
second image which (I think) is of uniform color. Only the first tile is
ever used.
(7) These three templates don't work in C&C (HOM effect), but their graphics
exist in the DESERT.MIX file. Do not use them !
That's all. I hope this info will be used by somebody to make a scenery
editor.
Report any errors to me. Also, if you have any info about other file formats
please share it with me.

File diff suppressed because it is too large Load Diff

View File

@@ -1,99 +0,0 @@
Dune 2000 File Formats Specs. Specially for Programmers, who want make editor(s) for Dune 2000
Date: June 8, 2004
Author: Roman "Siberian GRemlin" Lotchenov
E-Mail #1: slos@scn.ru
E-Mail #2: SibGRem@rambler.ru
*****************************************************************************
Graphics Resources - .R8 and .R16
ImageHeader: Record
ID: Byte; //0 - no data, 1 - picture with pallete,
//2 - picture with current pallete.
Width: LongInt; //Width of picture
Height: LongInt; //Height of picture
X_Offset: LongInt; //Pictures offset on an axis X (from left border(edge) of virtual frame)
Y_Offset: LongInt; //Pictures offset on an axis Y (from top border(edge) of virtual frame)
ImageHandle: LongInt; //Handle to picture (in memory), 0 - image not have picture
PaletteHandle: LongInt; //Handle to pallete (in memory), 0 - image not have pallete,
//and using pallete from palette.bin filr. format - 256*RGB
Bpp: Byte; //Bpp of picture
FrameHeight: Byte; //Height of virtual frame, in which is displayed the picture
FrameWidth: Byte; //Width of virtual frame, in which is displayed the picture
Align: Byte; //Alignment on even border
End;
There is a matrix(array) of pixels by the size further:
For ImageHeader.Bpp = 8: ImageHeader.Width*ImageHeader.Height
For ImageHeader.Bpp = 16: ImageHeader.Width*ImageHeader.Height*2,
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
If PaletteOffset <> 0 and ImageHeader.ID = 1, then there is Pallete Header and Pallete
PalHeader: Record
Memory: LongInt; //The memory under a palette was allocated (There is no importance in a file)
PalHandle:LongInt; //Handle to colors array (in memory), if 0 - then game showe error message
End;
Palette: array[0..511] of byte; //Pallete: 256 records of colors
//Color record: 2 bytes - 5 bit red component, 6 bit green component,
//5 bit blue component
Warning: In files UI_ENG.R16 and UI_ENG.R8, cuted ImageHeader.ID
Warning: Files UIBB.R8 and UIBB.R16 is only picture(pixels array) without any headers. Width=640, Height=400
*****************************************************************************
Sound Resources - [Dune2000 Folder]\Data\GameSFX\SOUND.RS
HeaderSize: LongInt; //Size of RSoundHeader
RSoundBody: array[0..56] of record
FileName: Char[0..12]; //File name
Zero: Byte; //Always $00
FileOffset: DWord; //Offfset of WAVE
FileSize: DWord; //Size of Wave file
end;
*****************************************************************************
Text Resources - [Dune2000 Folder]\Data\UI_Data\TEXT.UIB
STUIBHeader: record
Strs: DWord; //Count of strings
end;
STUIBBody: array[0..STUIHeader.Strs] of record
NameCount: Word; //Count of symbols(chars) in string name
StrName: array[0..STUIBBody.NameCount] of char; //String name
StrCount: word; //Count of symbols(chars) in string
Str: array[0..STUIBBody.StrCount] of char; //String
end;
*****************************************************************************
Fonts Resources - .FNT and .FPL
FontHeader of record
FontLoadedFlag: byte; //Must be $00
SpaceSize: byte; //Size of space (in pixels)
FirstSymbol: byte; //Code of first symbol in font
Interval: byte; //Size of interval between symbols (in pixels)
MaxHeight: byte; //Maximum height of symbol
Reserve: array[0..2] of byte; //not used
SymbolsHandle array[0..255] of LongInt; //Handle table to symbols in memory (There is no importance in a file)
end;
Symbols: array[0..255] of record
Width: LongInt; //Width of symbol
Heigth: LongInt; //Heigth of symvol
Pixels: array[1..(Symbols.Width*Symbols.Heigth)] of byte;
end;
Warning: FONTCOL.FNT using pallete from FONTCOL.FPL, Format - 256*RGBF, F=Junk!
Warning: [Dune2000 Folder]\Data\BIN\Font.BIN - is sybmol code(index) table(map)
*****************************************************************************
Thanks to:
Michail Beschetnov for begins in R8 file format description
Magic Team for help with R8 file format and for Dune 2000 Image Converter
be-lam0r for help with FNT, R16 and R8
-=*************=-
Please sorry for my english...

View File

@@ -1,60 +0,0 @@
Crossplatform "Launcher" ideas:
provides facility for commands like "--install-ra-packages", etc instead of having to reinvent the wheel on each platform.
Command ideas:
--list-mods: Simple list of available mods
- This is already done on game init, just needs pulling somewhere generic
--mod-info <mod>: Metadata on specific mod
--list-mod-heirarchy: Like above, but shows mod heirarchy
Is this needed? With a combination of listing and mod info, you can easily build the tree yourself. But if every platform has to do this, we may as well share the code. *shrug* its not a big deal at this stage.
--install-ra-music <path to cd>: Extracts scores.mix and copies it to the ra/packages dir
--install-cnc-music <path to cd>: Copies scores.mix from cnc disk to cnc/packages dir
--download-(ra|cnc)-packages: downloads ds and extracts packages from web
--install-(ra|cnc)-packages <path to cd>: copies required files from ra/cnc cd
Implementation:
Either separate exe or in the OpenRA.Game executable as a cli interface for modifying
the game install.
Platform specific guis that call the appropriate commands, and launch the game itself.
Separate Exe: <-- lets go with this for the first version. It can link against Fileformats to get
the mix extraction and mod list stuff.
Pros:
Small
Doesn't clutter main executable with functionality not used elsewhere.
Cons:
OpenRA.Game executable:
Pros:
Cons:
Platform specific gui scope:
-- Allow setting basic settings before launch? (toggle fullscreen is frequently asked for)
This would be a nice feature given setting them in game requires a restart.
Lets limit this to graphical settings. I'd rather not reinvent the wheel for things that
don't need it.
-- Give an overview of installed mods.
-- Install new mods from site/downloaded archive.
-- Install new maps for a mod.
-- Update core game and mods
-- Launch game with a selection of mods.
-- Also allow the user to set custom commandline args
Via GUI selection? Via a textfield below the mods checkbox
That would be unfriendly to a lot of users or is this for "power user" options?
Power users. It can be hidden behind a toggle/pref if necessary.
Gameplan:
-- Start by building the cli interface, and hook up the existing postinstall scripts to use them
-- Code for listing mods exists, move this into fileformats (for --list-mods)
-- Code for extracting files from mixes exists in fileformats (for --install-ra-music).
-- Copying files: filesystem permissions? Do we require root? How do we handle this?
We do on Windows and Linux at least. Unless we do per user.
-- Is installing files to the support dir acceptable?
For mods, perhaps. For core game: no.
-- Gui launchers can run the cli app with appropriate permissions. cli can be dumb.
-- Require code to download files from intarwebs, and report progress to stdout.
This is about the only non-trivial code that we need to write. Its still relatively trivial.
-- Platform-specific maintainers work on their own launcher later
-- ????

View File

@@ -1,200 +0,0 @@
Netcode for OpenRA
Current deficiencies:
bandwidth use to say *nothing*. we have to say nothing _somehow_.
of course, but it's currently the bulk of our cost. it will probably continue to be so.
it's mostly NODELAY'd ACKs, right?~half is reduction by half enough?
enough to host 8p on my link. good enough, then.
port forwarding
versioning
limited to 8 players -- why exactly? other than a dumb check in server? Just the dumb check i think, which i have removed. Untested - there are probably other stupid assumptions.
setting NODELAY doubles our bandwidth usage
various bits of the engine get confused when people drop -- dumb bug.
latency
A <-> server <-> B can longer than it needs to be if A is near B
Peer to peer in some aspect then?
udp makes this easier than current, but still interesting.
server probably still needs to get everything, even if there are other faster
ways some players can get it.
This is sounding like we'd need proper routing algorithms
maybe. i can see "attempt to connect to everyone" being the only useful strategy here, so we can just send our orders over every link we have. (and ask the server to pass on the rest, if neccessary)
need to be careful about how much upstream bandwidth we'd use
at 25fps, saying "no orders this frame" is ~25*28 bytes/sec/player.
even chris' connection can handle that for 8p.
700B/s/player
that's assuming we remove the '3 ticks per net tick' thing
if we keep that, divide by 3.
use JUST udp, or tcp too? the --> server link could easily be TCP (without NODELAY, if necessary) as long as our players graph is fully connected via udp.
can we make udp multicast work?
through the internet..... probably not.
LAN, we might as well broadcast. LAN bandwidth isnt a concern :S nor latency.
Solutions:
port forwarding
UPNP - fixes the problem on _some_ routers huge pain in the arse to implement
BS, there are OTS libraries we can use with .NET/mono.
UDP+punchthrough - better solution
requires a server with a udp port open and usable.
Can we abuse the master server in some way for this?
on our current host, probably not
- dreamhost: no
- master.open-ra.org: yes
- dchote mentioned that he knows people with a bunch of redundant servers we can use for persistant lobbies. maybe.
can we host ALL internet lobbies on external servers?
- This would be a nice feature.
- Provide a dedicated server for people to run their own.
versioning
we need at least mod versions + engine version.
player limit
easily removed
requires lobby upgrades > easy
NODELAY
tcp latency optimization, but bandwidth pessimization.
do we have the equiv of TCP_CORK sockopt on all platforms?
i don't think so, though we may be able to achieve the same result by toggling NODELAY.
Extra features?
- game chat <-> irc bridge
- MOTD etc broadcast from master server into game lobbies
- Desync communication from clients to the server (write desync diffs to server.log).
- actively send desync logs to us (for internet games at least)
- AOE(?) style desync detection stream
explain.
chrisf was talking about this a while back, they have a stream that they can insert arbitrary data into to check sync.
i like this plan.
Can we focus first on making our current setup with tcp sane? Or is this more work than throwing everything out and starting again
probably easier to start again; the current server is a quick hack with hacks added :D
dont forget the extra hacks added after that :D
Sounds like every other part of the engine :D
parts of it are good.
also, most of it is 'top-level' stuff that other code doesn't rely on.
Implementation:
TCP connection to servers run by us; udp between peers.
- what about latency? having N players in NZ, with a server in the US shouldn't make things suck.
- latency will either be
- 'longest path through the udp connection graph' (if we allow routing), or
- longest A <-> server <-> B without a connection A <-> B otherwise.
- ideally, we can get a totally connected graph and this isn't an issue.
server provides punchthrough introduction where necessary
udp provides:
- reliable, order transport.
- because we commonly have N frames of nothing before an order, we can optimise this.
- multiple streams (at least: chat, orders, sync. possibly lobby.)
sync: build arbitrary stream of sync data, send per-frame hashes to the server (only)
send stream for that frame on request
adding to the stream should be as easy as Game.AddToSyncLog( T )
who checks sync? how do we get individual players' syncreports together?
Can the server check either hashes or whatever new mechanism, and then send an
order to clients to dump their syncreport? Relying on clients to check is a bit dumb
-> server should be able to drop the players that desync
(who? if there are N distinct groups)
can we split the game into N distinct games, in that case?
drop any one-player games, since we know which client is at fault here.
We can do this in general; the faulty client can either automatically win,
or play a bot on their side.
Open Questions:
what level of connectivity do we _require_ wrt p2p?
can we achieve 100% reliably?
100% reachable nodes? 100% that we can _directly_ communicate with via udp.
For what reasons do we still need a server? Besides sync checking?
If lobbies are done by an external server controlled by us, user created servers are not really necessary are they?
in the case of a not-100% connected graph, a player quitting may disconnect it.
-> we should never kill a game when a player leaves.
perf degradation is bad but acceptable.
Protocol:
Handshake:
Client says: "Version, all mod versions available, player state(name,color,etc)"
Server says: "Game id, mods versions required, syncrandom, lobbystate" OR "GTFO"
-- client should be given the option to change mods if required and possible
-- this can be done by noting the required mods, dropping, reiniting appropriately, and connecting again.
The client still needs to be told by the server what it needs, for direct connect.
-- Would this include available slots?
It doesn't need to -> clients can be dumped into an "observers bin" on join, if there
isn't a free slot available
I'm not sure how nice that actually is -- having the server dump players into a
real slot if one is available is nicer, for noobs.
when you want to play with specific people, having some of them be unable to join until you kick someone is undesirable. -> observer bin. let host pro/demote people into/outof full slots.
"Heroes of Newerth" (a dota clone) is kinda like this.
their previous game was kinda a disaster wrt lobby stuff :D
(savage, s2)
HoN's netcode is REALLY nice. fps-style though, so not useful.
overflow into a bin, sure.
Client says : "ACK, NACK"?
--password? --banning?
Connection moves to "Lobby" protocol.
Lobby:
Server says: "assigned slot (as per above discussion), other player details(?)"
-- Player info exchange could be done via UDP at this stage
we probably want to use this stage to _connect_ udp, so probably not.
also, no reason; we care about neither latency nor bandwidth here.
Transfer of maps? mods?
One easy way to do this is for the host to upload to a repository
then the other clients can retrieve the missing bits using WebClient etc.
(Rather than reinventing a bulk transfer protocol)
Need a data structure for info that is needed for the lobby; slots, minimap(?)
Why should they not download everything immediately? maps arent big.
How do existing rts's solve this?
by not having the client determine lobby structure from the map.
(more generally, by not loading the map until game start)
Syncing client info in a less hacky way (currently its a hack that only works in frame 0). yes, we fix that.
protocol stages:
Handshake:
verify versions, password; choose player name/color; client is assigned a clientid
Lobby:
Sync lobby info; alter player name, color, team, etc.
transmit maps and any other transferable but not-currently-present data.
connect udp.
Game:
orders over udp; sync over tcp.
-> Return to Lobby mode at the end of a game (after postgame etc). Drop and reconnect is fine, if its automated.
Implementation stages:
Handshake:
- This can do nothing, as a first attempt.
Lobby:
- The udp connections are the most interesting bit here.
- As a first attempt, require 100% connectivity. i hate routing.
interesting or "interesting"?
udp punchthrough is the latter.
Do we need this in our first N attempts?
If we want to establish UDP connections with everyone, I imagine so.
We need punchthrough or upnp. (and, excepting broken routers, punchthrough isn't much more difficult. THAT is the "interesting" case.)
- Don't need transferrable data in first attempt.
Game:
- We need reliable, working, ordered, udp data transfer.
Other Issues: (to be solved later)
Where does this magical infinite webspace live?
maps are small.
If it's permanent you can't pretend a limit won't ever be hit
it isn't permanent; it only has to last the duration of the server.
Storing the maps indexed by sha is probably a very sane way to do it.

View File

@@ -1,988 +0,0 @@
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

View File

@@ -1,57 +0,0 @@
======================
Dune 2 SHP file format
======================
Sourced from Red Horizon Utilities by Emanuel Rabina
http://www.ultraq.net.nz/redhorizon/
The Dune 2 SHP file, is a multiple image filetype, where each image can have
it's own set of dimensions. The file is structured as follows:
File header:
NumImages (2 bytes) - the number of images in the file
Offsets[NumImages + 1] - offset to the image header for an image. The last
(2 or 4 bytes each) offset points to the end of the file. The offsets
don't take into account the NumImages bytes at the
beginning, so add 2 bytes to the offset value to
get the actual position of an image header in the
file
The size of the offsets can be either 2 or 4 bytes. There is no simple way
to determine which it will be, but checking the file's 4th byte to see if
it's 0, seems to be a commonly accepted practice amongst existing Dune 2 SHP
file readers:
eg: A 2-byte offset file: 01 00 06 00 EC 00 45 0A ...
A 4-byte offset file: 01 00 08 00 00 00 EC 00 ...
^^
The marked byte will be 0 in 4-byte offset files, non 0 in 2-byte offset
files.
Lastly, like C&C SHP files, there is an extra offset, pointing to the end of
the file (or what would have been the position of another image header/data
pair).
Following the file header, are a series of image header & image data pairs.
The image header is structured as follows:
Image header:
Flags (2 bytes) - flags to identify the type of data following the
Datasize field, and/or the compression schemes used
Slices (1 byte) - number of Format2 slices used to encode the image
data. Often this is the same as the height of the
image
Width (2 bytes) - width of the image
Height (1 byte) - height of the image
Filesize (2 bytes) - size of the image data in the file
Datasize (2 bytes) - size of the image data when Format2 encoded/compressed
Regarding the flags, there seem to be 4 values:
- 00000000 (0) = Decompress with Format80, then Format2
- 00000001 (1) = (see 3)
- 00000010 (2) = Decompress with Format2
- 00000011 (3) = A small 16-byte lookup table follows, and the image data
should be decompressed with Format80 then Format2.
- 00000101 (5) = The first byte gives the size of the lookup table that
follows, and the image data should be decompressed with
Format80 then Format2.
And after this image header is the image data.

View File

@@ -1,855 +0,0 @@
Chapter II
Editing the .ini file
by mgP <parker@telis.org>
******************************
Introduction
Now that you have finished making your map with CCMap, you may wish to learn
some things about the .ini file.
Oh yeah... I almost forgot. You are probably asking, `What is an .ini file?'.
Well, every time you save your map to your hard drive in CCMap, it saves it
in two files. One is a file with a .map extension, which is always at 8K
(8192 bytes). This .map file contains information on the location and type of
all the map tiles in your mission. The other file is the .ini file, and is
probably much more important. It saves everything else you put on your map,
such as Tiberium, structures, infantry, units, trees, concrete walls, etc.
The .ini file can be edited through a text editor, such as MS-DOS Edit or
Notepad. By adding new sections to the .ini file, your mission can become
more advanced. The computer opponent(s) can create teams of units to attack
you at time intervals, or drop a load of engineers on a Chinook every once
in a while. Maybe they will fire an Ion Cannon at you once you attack their
base, or maybe launch a nuke at you when you attack their Temple of Nod.
That all sounds pretty cool, huh? Well there's more. You can change the
environment your mission is in, the size of the map you play on, the video
and text briefings you get, and many other things. All of this is done by
editing the .ini file. In this chapter, I'll show you how to do just that,
and give you some examples of other things. Another thing: there is one
drawback to the .ini file. If it exceeds 16 or 17K, you'll start to miss
some things from your mission. Maybe some triggers will disappear, then some
Tiberium, then some units, then...
I am now going to start. Each of the following chapters is a part of the .ini
file, and the heading of each .ini file part is the chapter name. In each, I
will give an example of what it might look like in your .ini file. In some,
I will also give a syntax, the order the variables for the example.
******************************
ALSO, IF YOU HAVE ANY QUESTIONS ABOUT ANYTHING HERE, OR ANYTHING NOT
LISTED HERE, DO NOT EMAIL ME. INSTEAD, ASK THEM AT OUR WEB BOARD AT
http://www.io.org/~isarog/c-c/php.cgi/~isarog/c-c/wwwboard/wwwboard2.html
******************************
Table of Contents
1. BASIC
2. MAP
3. WAYPOINTS
4. [GOODGUY], [BADGUY], [NEUTRAL], [SPECIAL], [MULTI1 - MULTI6]
5. TERRAIN
6. OVERLAY
7. SMUDGE
8. UNITS
9. INFANTRY
10. STRUCTURES
11. BASE
12. CELLTRIGGERS
13. TRIGGERS
14. TEAMTYPES
15. BRIEFING
16. You're done!
******************************
1. BASIC
The BASIC section is the first part of the .ini file. This tells of the
videos played before and after the mission, what side the player is, the
name of the mission, and some things which are unknown.
Example:
[BASIC]
CarryOverCap=-1 1
CarryOverMoney=35 2
Intro=X 3
BuildLevel=13 4
Theme=No Theme 5
Percent=30 6
Player=BadGuy 7
Action=X 8
Lose=X 9
Win=X 10
Brief=X 11
Name=Terrorists in the Village 12
Definition:
1. CarryOverCap: Unknown.
2. CarryOverMoney: The amount of credits carried over from the previous
mission divided by 100. So 35 equals 3500 credits. However, I have found
this not to be the case.. I think it is the percent of credits carried
over from the previous mission.
3. Intro: The introductory video played before the mission starts. See the
ccmovies.txt file for valid entries. Put an 'x' for no video.
4. BuildLevel: Changing this number does not really affect what you can build
in the game. The maximum value for this number is 99. A good way to be
able to build most things is replace a mission far in the game with your
mission.
5. Theme: What song is playing when the mission starts. Many to choose from.
See the ccsongs.txt file for valid entries.
6. Percent: Unknown.
7. Player: This is the side you will play as in your mission:
GoodGuy=GDI
BadGuy=Nod
Neutral=Civilians
Special=GDI and Nod stuff can be built by this team
Multi1-Multi6=Individual teams, multiplayer teams
8. Action: A video played before the mission, but after the one in Intro.
See the ccmovies.txt file for valid entries. Put an 'x' for no video.
9. Lose: The video played if you lose the mission. See the ccmovies.txt file
for valid entries. Put an 'x' for no video.
10. Win: The video played if you win the mission. See the ccmovies.txt file
for valid entries. Put an 'x' for no video.
11. Brief: The briefing video... Many too choose from. See the ccmovies.txt
file for valid entries. Put an 'x' for no video.
12. Name: This is for Covert Operations owners only. It will show up as this
name and it will show up in the `New Missions' list. Command & Conquer
owners without Covert Ops can put a name here also to specify the name
of their mission.
******************************
2. MAP
The MAP section of the .ini file tells of how big the map is going to be,
and the environment you will be in.
Example:
[MAP]
Height=35 1
Width=30 2
X=1 3
Y=1 4
Theater=Winter 5
Definition:
1. Height: Change this number to change the height of the map in your
mission. 64 is the maximum, but never go above 62. If you exceed 62,
Antanovs and A-10s will be stuck at the border of the map when they fly
in from the sides / top and bottom. Also, if you exceed 63, CCMap will
lock up.
2. Width: Change this number to change the width of the map in your mission.
64 is the maximum, but never go above 62. If you exceed 62, Antanovs and
A10s will be stuck at the border of the map when they fly in from the
sides / top and bottom. Also, if you exceed 63, CCMap will lock up.
3. X: The horizontal position of the top-left corner of the map. Values
range from 0 - 2. A value other than 1 lets you view the extra 1 cell
border on a 62x62 map.
4. Y: The vertical position of the top-left corner of the map. Values range
from 0 - 2. A value other than 1 lets you view the extra 1 cell border
on a 62x62 cell map.
5. Theater: The mission environment. Choose from Desert, Temperate, or
Winter.
Note: It is best to change the Height and the Width values of your mission
before you actually create the mission with CCMap. This will adjust the size
map you are creating. It is also a good idea to change the Theater value
before you make your map. Changing theater values in the middle, or after
you create your mission, can mess up the map.
******************************
3. WAYPOINTS
Waypoints are used in the TeamType section. All waypoints are actually cell
numbers, but instead of using the actual cell number, C&C will look up the
cell number in the appropriate waypoint. There are a total of 32 waypoints,
from 0 through 31, which you can define as you wish (as cell numbers). Most
missions have at least 27 waypoints. But three waypoints serve a specific
purpose:
- Waypoint 25: The yellow flare is always lit at this waypoint if
designated.
- Waypoint 26: The cell at the top left corner of the screen when the
mission starts. This is so you don't end up with a black screen at the
start of the mission, and have to go searching around a dark map until
you find one of your units.
- Waypoint 27: This waypoint is the default drop cell for Chinooks and APCs
if no 'Unload' command is specified.
If a waypoint has a value of '-1' it is unused.
Syntax: Waypoint=Cell number it represents
Example:
10=1377
^^ ^^
1 2
Definition:
1. 10: The waypoint # 10.
2. 1377: The cell number waypoint 10 represents.
******************************
4. [GOODGUY], [BADGUY], [NEUTRAL], [SPECIAL], [MULTI1 - MULTI6]
The sections GOODGUY, BADGUY, NEUTRAL, SPECIAL, MULTI1 - MULTI6 are very
important. Each of these sections tells of each side, including their allies,
starting credits, what edge of the map reinforcements come from, and some
unknown things.
Example:
[BadGuy]
Flaghome=0 1
FlagLocation=0 2
MaxBuilding=70 3
MaxUnit=150 4
Allies=BadGuy, Special 5
Edge=East 6
Credits=70 7
Definition:
1. Flaghome: Unknown.
2. FlagLocation: Unknown.
3. MaxBuilding: Unknown.
4. MaxUnit: Unknown.
5. Allies: This tells who your allies are. They won't attack you in your
mission. You can have multiple entries here.
6. Edge: Reinforcements by APC, and Chinook come from this side of the map.
Hovercraft always come from the south.
7. Credits: This number is the number of credits this side starts with,
divided by 100. So the 70 equals 7000 credits.
******************************
5. TERRAIN
The TERRAIN section has the type and location of all the terrain tiles in
your map. CCMap will handle all this for you. It is to complicated to put
in these entries manually, and too complicated to explain.
******************************
6. OVERLAY
This OVERLAY section has the type and location of all the overlay tiles in
your map. They include Tiberium, crates, sandbag walls, chainlink fences,
concrete walls, wooden fences, and barbed wire.
Syntax: Cell number=Overlay
Example:
541=TI12
^ ^^
1 2
Definition:
1. 541: The cell number this overlay tile is located in.
2. TI12: Tiberium with a density rating of 12.
Other overlay entries go like this:
WCRATE: Wooden crate containing 2000 Tiberium credits.
SCRATE: A steel crate containing one of the three parts to the nuke.
TI1: Tiberium with a density rating of 1.
TI2: Tiberium with a density rating of 2.
TI3: Tiberium with a density rating of 3.
TI4: Tiberium with a density rating of 4.
TI5: Tiberium with a density rating of 5.
TI6: Tiberium with a density rating of 6.
TI7: Tiberium with a density rating of 7.
TI8: Tiberium with a density rating of 8.
TI9: Tiberium with a density rating of 9.
TI10: Tiberium with a density rating of 10.
TI11: Tiberium with a density rating of 11.
TI12: Tiberium with a density rating of 12.
BRIK: Concrete wall.
SBAG: Sandbag wall.
CYCL: Chainlink fence.
BARB: Barbed wire.
WOOD: Wooden fence.
******************************
7. SMUDGE
Entries in SMUDGE are bomb craters (like the ones Adv. Guard Tower missiles
leave in the ground after they fire) and scorch marks (like the ones on the
ground after a nuke has hit, or when a flame tank scorches the ground).
These craters and scorch marks do not show up in CCMap, but will appear in
the mission. You will have to add these manually.
Syntax: Cell number=Smudge mark.
Example:
964=SC4
^ ^
1 2
Definition:
1. 964: The cell number this smudge is in.
2. SC4: The type of smudge mark. SC1 through SC6 are scorch-marks, and CR1
through CR6 are bomb craters.
******************************
8. UNITS
The UNITS section has the entries for all of the units which are on the map
when the mission starts.
Syntax: Number on list=Owner,Type of Unit,Health,Cell number,Direction,
Action,Associated Trigger.
Example:
006=GoodGuy,HTNK,256,512,96,Area Guard,att1
^ ^^^^^ ^^ ^ ^ ^^ ^^^^^^ ^^
1 2 3 4 5 6 7 8
Definition:
1. 006: The number on the list of units in the units section.
2. GoodGuy: Owner of the unit. Possible teams are:
GoodGuy=GDI
BadGuy=Nod
Neutral=Civilians
Special=GDI and Nod stuff can be built by this team
Multi1-Multi6=Individual teams, multiplayer teams
3. HTNK: What type of unit it is: a Heavy Tank (Mammoth Tank). Choose from:
VICE: Viceroid
FTNK: Flame Tank
STNK: Stealth Tank
LTNK: Light Tank
MTNK: Medium Tank
HTNK: Heavy Tank (Mammoth Tank)
MHQ: Mobile Headquarters
LST: Hovercraft
MRLS: Honest John Rocket Launcher
ARTY: Mobile Artillery
HARV: Harvester
MCV: Mobile Construction Vehicle
JEEP: Humm-Vee
BGGY: Nod Buggy
BIKE: Recon Bike
MSAM: Mobile Rocket Launcher
APC: Assault Personnel Carrier (APC)
BOAT: Gunboat
TRIC: Triceratops
TREX: Tyrannosaurus Rex
RAPT: Velociraptor
STEG: Stegosaurus
4. 256: Health of the unit.
256=Maximum health.
1=Basicially dead.
5. 512: Cell number the unit is located at.
6. 96: Direction the unit is facing. Choose from:
0=North
32=North-East
64=East
96=South-East
128=South
160=South-West
192=West
224=North-West
7. Area Guard: Action he undertakes during the mission. Choose from:
Area Guard : Guard an area of a few cells around the infantry / unit.
Attack Base : Attack the enemy base (give Engineers this command to
take over buildings).
Attack Civil. : Attack all civilians.
Attack Tarcom : Unknown.
Attack Units : Attack the enemy units and infantry.
Defend Base : Unit / Infantry will defend it's base from enemy attacks.
Guard : Unit will only guard a one cell radius, and will only attack
units which attack it.
Harvest : Gather Tiberium... Harvesters only.
Hunt : Will seek out enemies as long as he is alive.
None : No action undertaken by the unit / infantry.
Rampage : Like Attack Units, but the unit will attack targets more
wisely.
Retreat : Unknown. Maybe it has something to do with when the units
are attacked, they will retreat to a waypoint?
Return : Unknown. Maybe the same action as retreat?
Sticky : The unit will stay in it's starting cell, regardless of
anything.
8. Att1: The trigger associated with the unit. Put 'None' for no trigger to
be associated.
******************************
9. INFANTRY
The INFANTRY section has the entries for all the infantry on the map when
the mission starts.
Syntax: Number on list=Owner,Type of Infantry,Health,Cell number,
Sub-Cell number,Action,Direction,Associated Trigger.
Example:
011=GoodGuy,RMBO,256,950,3,Hunt,64,die7
^ ^^^^^ ^^ ^ ^ ^ ^^ ^^ ^^
1 2 3 4 5 6 7 8 9
Definition:
1. 011: Number on the list.
2. GoodGuy: Owner of the infantry. Possible teams are:
GoodGuy=GDI
BadGuy=Nod
Neutral=Civilians
Special=GDI and Nod stuff can be built by this team
Multi1-Multi6=Individual teams, multiplayer teams
3. RMBO: Type of infantry. Choose from:
RMBO: Commando
DELPHI: Agent Delphi
C1-C10: Civilians
E1: Minigunner
E2: Grenadier
E3: Bazooka Troop
E4: Flame-thrower Troop
E5: Chemical Warrior
E6: Engineer
4. 256: Health of the infantry.
256=Maximum health.
1=Basicially dead.
5. 950: The cell number the infantry is located at.
6. 3: The sub-cell number the infantry is in. 5 infantry can be in one cell,
thus sub-cell number values of 0 - 4.
7. Hunt: Action he undertakes during the mission.
Area Guard : Guard an area of a few cells around the infantry / unit.
Attack Base : Attack the enemy base (give Engineers this command to
take over buildings).
Attack Civil. : Attack all civilians.
Attack Tarcom : Unknown.
Attack Units : Attack the enemy units and infantry.
Defend Base : Unit / Infantry will defend it's base from enemy attacks.
Guard : Unit will only guard a one cell radius, and will only attack
units which attack it.
Harvest : Gather Tiberium... Harvesters only.
Hunt : Will seek out enemies as long as he is alive.
None : No action undertaken by the unit / infantry.
Rampage : Like Attack Units, but the unit will attack targets more
wisely.
Retreat : Unknown. Maybe it has something to do with when the units
are attacked, they will retreat to a waypoint?
Return : Unknown. Maybe the same action as retreat?
Sticky : The unit will stay in it's starting cell, regardless of
anything.
8. 64: Direction which the infantry is facing.
0=North
64=East
128=South
192=West
9. die7: The trigger associated with the infantry. Put `None' for no trigger
to be associated.
******************************
10. STRUCTURES
The STRUCTURES section of the .ini file has the data for all the structures,
or buildings, in the mission.
Syntax: Number on list=Owner,Structure type,Health,Cell number,Direction,
Associated Trigger.
Example:
021=BadGuy,AFLD,256,1668,0,Atk1
^ ^^^^ ^^ ^ ^^ ^ ^^
1 2 3 4 5 6 7
Definition:
1. 021: It's number on the list of structures in the structure section.
2. BadGuy: The owner of the structure. Possible teams are:
GoodGuy=GDI
BadGuy=Nod
Neutral=Civilians
Special=GDI and Nod stuff can be built by this team
Multi1-Multi6=Individual teams, multiplayer teams
3. AFLD: The type of structure: an Airfield. Choose from:
TMPL: Temple of Nod
EYE: Advanced Communications Center
WEAP: Weapons Factory
GTWR: Guard Tower
ATWR: Advanced Guard Tower
OBLI: Obelisk of Light
GUN: Gun Turret
FACT: Construction Yard
PROC: Tiberium Refinery
SILO: Tiberium Silo
HPAD: Helipad (Nod Apaches and GDI Orca pads)
HQ: Communications Center
SAM: Sam Site
AFLD: Airstrip
NUKE: Power Plant
NUK2: Advanced Power Plant
HOSP: Hospital
BIO: Biotech Lab
PYLE: Barracks
HNOD: Hand of Nod
ARCO: Civilian Water Pump
FIX: Repair Bay
MISS: Technology Center / Prison
V01 - V37: Civilian Buildings
4. 256: The health of the structure.
256=Full Health
1=Basicially Dead.
5. 1668: The cell number the structure is in.
6. 0: The direction the structure is facing. For structures, this is only
useful with Nod Gun Turrets. Here are possible values:
0=North
32=North-East
64=East
96=South-East
128=South
160=South-West
192=West
224=North-West
7. Atk1: A trigger associated with the structure. Put 'None' for no trigger
to be associated with the structure.
******************************
11. BASE
The BASE section defines which structures the computer is to rebuild. This
section of the .ini file is not done by CCMap, but by a utility called
BaseIt. It is included with CCTools, but can be downloaded off the Internet
as a single, separate utility.
Syntax: Number on list=What to Rebuild,Number
Example:
013=GUN,956312320
^ ^ ^^^^^
1 2 3
Definition:
1. 13: Number on the list.
2. GUN: Type of structure to rebuild.
3. 956312320: A strange number which defines where to rebuild the structure.
******************************
12. CELLTRIGGERS
CELLTRIGGERS are very unique. When you cross a certain cell, the associated
trigger is activated. With this, you can have reinforcements arrive when you
cross bridges, a nuke hit your base when you enter their base, and many other
things.
Syntax: Cell number=Associated Trigger
Example:
2054=drop
^^ ^^
1 2
Definition:
1. 2054: The cell which must be crossed for the associated trigger to
activate.
2. drop: The associated trigger. This is actually a shortcut to any of the
triggers in the trigger section.
******************************
13. TRIGGERS
The TRIGGERS section is the part of the .ini file which is probably the most
important. This tells when reinforcements to arrive, what the mission
objectives are, etc. It basically tells what happens when. Some triggers may
be associated with buildings, units, and infantry, but other triggers can
activate upon a certain amount of time passing, if something is built, if
something is attacked or destroyed, or many other things. Some trigger
entries may be associated to TeamType entries.
Syntax: Trigger Name=Why Activated,What Happens,Counter,Who Activates
Trigger,Associated TeamType Entry,Loop
Example:
SPY=Discovered,Ion Cannon,0,BadGuy,dstry,0
^ ^^^^^^ ^^^^^^^^ ^ ^^ ^^^ ^
1 2 3 4 5 6 7
Definition:
1. SPY: The name of the trigger. These can be anything you want...
2. Discovered: This is why the trigger was activated. For example, this
trigger would be activated if a unit associated with trigger SPY was
discovered by the player. Others entries are:
# Bldgs Dstr. : Trigger activates when the number of buildings in the
counter section are destroyed for the associated side.
# Units Dstr. : Trigger activates when the number of units in the
counter section are destroyed for the associated side.
All Destr. : Trigger activates when everything of the associated side
is destroyed.
Any : Used in association with the Cap=Win/Des=Lose variable.
Attacked : Trigger activates if the associated infantry / structure /
unit is attacked.
Bldgs Destr. : Trigger activates when all buildings of the associated
side have been destroyed.
Built It : Trigger is activated when the specified structure is built.
See the builtit.txt file on how to use this trigger.
Civ. Evac. : Trigger activates when all civilians are evacuated.
Credits : Trigger activates when the number of credits have been
reached in the counter section (credits / 10).
Destroyed : Trigger activates if the associated infantry / structure /
unit has been destroyed.
Discovered: Trigger activates if the associated infantry / structure /
unit has been discovered.
House Discovered : Trigger activates if the associated house (side)
has been seen by the player.
No Factories : Trigger activates if all unit / infantry producing
buildings have been destroyed (Nod: Hand of Nod & Airstrip; GDI:
Barracks & Weapons Factory) for the associated side.
None : Nothing activates the trigger.
Player Enters : Trigger activates when the player enters the cell
associated in the CellTriggers section.
Time : Trigger activates when a certain amount of time units has
passed.
Units Destr. : Trigger activates when all units of the associated
side have been destroyed.
3. Ion Cannon: This is what happened when the trigger is activated. Other
entries are:
Airsrike : A-10 Airstrike occurs.
All to Hunt : When the Trigger is activated, the associated side's
units & infantry go hunting for you.
Allow Win : Even if the Win trigger has been activated, you can not
complete the mission until the Allow Win trigger has been activated.
Autocreate : When the Trigger is activated, the computer player
randomly creates a team from the TeamType section.
Cap=Win/Des=Lose : When the buildings is captured, the mission is won.
If destroyed, you lose the mission.
Create Team : Create the associated TeamType entry (used only with the
1,0,0,1,0,15,1,0,0, combo).
Dstry Teams : Unknown. But in one .ini file for C&C, I did see a
Teams entry, but no teams were listed.
Dstry Trig 'XXXX' : Destroys the trigger called XXXX.
Dstry Trig 'YYYY' : Destroys the trigger called YYYY.
Dstry Trig 'ZZZZ' : Destroys the trigger called ZZZZ.
DZ at 'Z' : This lights up the yellow flare at Waypoint 25.
Ion Cannon : Ion Cannon is fired.
Lose : You lose the mission when the trigger is activated.
None : Nothing is activated.
Nuclear Missile : Nuclear Missile is fired.
Production : Reproduce destroyed buildings with using BaseIt, enables
the associated side to create teams.
Reinforce. : Reinforcements via A10s, APC, Chinook, Hovercraft, or
rolling off the side of the screen.
Win : You win the mission when the trigger is activated.
4. 0: This is a counter. Depending on your trigger action (entry 2,
Discovered) it can count credits, time, number of buildings destroyed,
and represent what structure is used with the Build It trigger.
5. BadGuy: Who activates the trigger.
6. dstry: TeamType entry associated with the trigger. Put 'None' for no
association.
7. 0: How many times the trigger is activated.
0=Once.
1 or 2=Trigger repeats once entry 4 (the counter) is reached again.
******************************
14. TEAMTYPES
TEAMTYPE entries are hard to understand... they are the entries which were
associated at the end of the Trigger entries. They tell specifically what the
Chinooks drop off, when the Chinooks come in, when APCs drop off, when APCs
come in, when the computer opponent creates teams of units, when A-10
Airstrikes arrive, and when reinforcements come in off the side of the
screen.
Syntax: TeamType Name=Team Owner,Number Combo,Number of Units,Units and
Quantity,Number of Actions,Actions.
Example:
atck=GoodGuy,1,0,0,1,0,15,1,0,0,2,MTNK:2,RMBO:1,2,Move:5,Attack Base:80,0,0
^^ ^^^ ^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^
1 2 3 4 5 6 7
Definition:
1. atck: The TeamType name, as associated to the trigger entries.
2. GoodGuy: The 'owner' of the team. Again, possible values are:
GoodGuy=GDI
BadGuy=Nod
Neutral=Civilians
Special=GDI and Nod stuff can be built by this team
Multi1-Multi6=Individual teams, multiplayer teams
3. 1,0,0,1,0,15,1,0,0,: The number combo. This defines what will happen in
this TeamType entry. Use the following templates:
1,0,0,1,0,15,1,0,0, or 0,0,0,0,0,15,0,0,0,: Create a team of units.
0,0,0,0,0,7,0,0,0,: Reinforce by hovercraft, APC, Chinook, or by
rolling off the side of the screen.
1,0,0,0,0,7,0,0,0,: Reinforce by A10 Airstrike, or by reinforcements
rolling off the side of the screen. See the text file on how to do
that.
4. 2: Number of units / infantry types in the team (not the total quantity).
5. MTNK:2,RMBO:1,: The units / infantry in the team and their quantity. We
know what the MTNK, and RMBO stand for (if you don't, see sections UNITS
and INFANTRY). Notice that each one is followed by a colon, then a
number. The number after the colon is the quantity of the preceding
unit / infantry in the TeamType. So this entry creates 2 Medium tanks and
1 Commando.
6. 2: Number of actions which they will under take. Here they move to
waypoint 5 then attack your base for 80 time units. The last action
entry should end with ,0,0. Other actions are:
Move : The units / infantry go to the designated waypoint. The
waypoint is the number after the colon.
Loop : Used at the end of all the actions. It will make the actions
loop over and over. Use a 1 after the colon.
Unload : For Chinooks, APCs, and Hovercraft, this command will have
them unload their cargo at the waypoint they are at. First give them
a move command to a specific waypoint, then an unload command with
the waypoint (i.e. Move:7,Unload:7)
Attack Units : Attacks enemy units. The number after the colon is for
how long the units are to attack.
Attack Base : Attacks enemy base (use this command for engineers
unloading off of Chinooks, APCs of Hovercraft to have them attempt
to capture buildings. Commandos do not use their C4 when given this
command). The number after the colon is for how long the units are
to attack.
******************************
15. BRIEFING
The BRIEFING section is for Covert Operations only. This is the text briefing
given every time you choose a new mission from the New Missions menu, and
the same text given when you Restate your mission objectives.
Every mission briefing may contain 304 characters. You may split the 304
characters into 4 lines (76 per line), or have many more lines, but with
less characters per line.
Here is an example of a BRIEFING section:
[BRIEFING]
1=This is an example mission briefing for this document.
2=Don't put this briefing in your real mission or you're stupid.
3=If you do, consult your psychiatrist immediately: you are insane.
4=But don't worry, he can help you.
For those of you without Covert Ops, below is how you make your mission
briefing. First, remember that set of letters and numbers which are the
prefix to the .ini and .bin files of your mission? For example, say that
mine were SCG12EA. Now, create a new file called MISSION.INI in the
Command & Conquer directory. Edit it through a DOS text editor. I would put
mine to look like this:
[SCG12EA]
1=This is an example mission briefing for this document.
2=Don't put this briefing in your real mission or you're stupid.
3=If you do, consult your psychiatrist immediately: you are insane.
4=But don't worry, he can help you.
Of course, your mission briefing may look (well, I hope it does) much
different then this one. Most likely the text and the combo of letters and
numbers at the top.
******************************
16. You're done!
Hope this gives you a good idea how to edit your .ini file. If you still
don't understand some things (or maybe a lot of things) visit our WebBoard
and ask around. It's at
http://www.io.org/~isarog/c-c/php.cgi/~isarog/c-c/wwwboard/wwwboard2.html.
===============================================================================
Copyright (C) 1996 Mark Smeltzer aka WarZone
==============================================================================
Built It Trigger FAQ
[1-1] Reasons why you would want to use it
[1-2] A thorough explaination of how to use it
[1-3] An advertisement of sorts for...The Ultimate C&C Startup Program!
*** Note: This is freeware! ***
==============================================================================
[1-1] Reasons why you would want to use the "Built It" trigger:
* suppose you want the AI to be able to start production when the "player"
creates a specific building (ex. a comm. centre)
* suppose that when a guard tower (etc.) is built you want a bunch of units
to attack
* suppose you want reinforcements to come when the "player" build an
adavanced comm. center
* suppose computer rebuilds its temple then the "player" gets reinforced
* and there are hundreds more!
==============================================================================
[1-2] A thorough explaination of the "Built It" trigger:
*** Note: this is the complicated part ***
Here's the format:
aaaa=Built It,bbbb,cccc,dddd,eeee,ffff
ex.= rein=Built It,Reinforce.,0,GoodGuy,rein1,0
aaaa= The name of the trigger (whatever you want here)
bbbb= the action the will occur when the structure is built
cccc= This is a number value that represents the sturcture to be rebuilt
Here are the values:
TMPL = 20
EYE = 21
WEAP = 0
GTWR = 1
ATWR = 2
OBLI = 3
GUN = 5
FACT = 6
PROC = 7
SILO = 8
HPAD = 9
HQ = 4
SAM = 10
AFLD = 11
NUKE = 12
NUK2 = 13
PYLE = 15
HAND = 19
FIX = 17
Sandbag Wall = 60 *
Chainlink Fence = 61 *
Concrete Wall = 62 *
Barbed Wire = 63 *
Wooden Fence = 64 *
* I haven't tested these...but the numbers are right.
dddd= which side builds the sturctures that activates the action
*** this can be the computer ***
Possible Values Are:
GoodGuy BadGuy Special Neutral Muilt1 - Muilt6
eeee= the teamtype to build/reinforce id the action is Reinforce. or
Create Team
ffff= specifies the trigger to loop
0 = don't loop
< 0 = loop (1 to 9) *
* not sure what the difference in behavior between these numbers's is

View File

@@ -1,350 +0,0 @@
.VQA files
by Aaron Glover (arn@ibm.net)
Each VQA has a 62-byte header, as follows:
VQAHeader: record
TextFORM: array[0..3] of Char; {Always 'FORM'}
FileBTF: LongInt; {Reverse - Bytes to follow}
TextWVQAVQHD: array[0..7] of Char; {Always 'WVQAVQHD'}
RStartPos: LongInt; {Reverse - Relative start position}
Unknown1: Word;
Unknown2: Word;
NumFrames: Word;
Width: Word;
Height: Word;
Unknown3: Word;
Unknown4: Word;
Unknown5: Word;
Unknown6: Word;
Unknown7: LongInt;
Unknown8: Word; {This changes}
Unknown9: Word;
Unknown10: Word;
Unknown11: array[0..13] of Char;
end;
Following the header, there are a number of `sub-files' that each
have a header of 8 bytes. The first four are the name (or type) of
the sub-file, the next four are a reverse LongInt that equals the
number of sub-file data bytes to follow (sub-file size minus sub-file
header size).
By `reverse LongInt', I mean a 4-byte Integer value stored backwards.
For example, take the the decimal value 77236. In hexadecimal it's
12DB4h, and would be stored in a binary file as the bytes B4 2D 01
00. As a reverse LongInt, it would be stored as 00 01 2D B4. More
human readable, but not how computers work.
Some sub-file names seem to start with a null byte (00h). There is a
reason for this, which will become apparent later. Just ignore the
null byte and assume the next one is the start of the sub-file
header.
So, after the header, you should find the something like the
following sub-files:
FINF
SND2
SND2
VQFR
SND2
VQFR
SND2
VQFR
SND2
VQFR
...
Each VQFR sub-file itself has sub-files. If you treat each VQFR sub-
file as if the `data bytes to follow' value was zero, you should get
something like:
FINF
SND2
SND2
VQFR
CBF0
CBP0
CPL0
VPTZ
SND2
VQFR
CBP0
VPTZ
SND2
VQFR
CBP0
VPTZ
SND2
VQFR
CBP0
VPTZ
...
FINF sub-file type:
First is a Word value that, if you multiply by two, gives the
position of the first data sub-file (relative to the start of the
VQA), then another Word value that seems to be always 4000h.
Following that is an array of LongInt values that, when multiplied by
two, give the position of each of the frame data sub-files (relative
to the start of the VQA). Each frame comprises of a SND2 sub-file
and a VQFR sub-file that follows immediately after.
This is why some of the sub-file names start with a null byte. Since
you have to multiply by two, each offset value must be even. So if
it would normally be odd, a null is inserted as the first byte to
make the sub-file's name offset even. Whew! Try saying that five
times fast!
The number of elements in the array is FrameNum (from the VQA header)
minus one.
I've noticed some of the LongInt values in this array are 40000000h
too large. I don't know why this is, at the moment I subtract
40000000h from values over 40000000h, it seems to work OK.
SND2 sub-file type:
I bet you've guessed this one. Well, so did I. Audio, right? I've
had a go at decoding them, and they seem to be in the same format as
the .AUD files, but I can't work them out (yet).
CBF0 sub-file type:
An array of eight-byte (4x2 pixel) uncompressed screen graphics.
I'll explain what they're used for when we get to the VPTZ sub-file
type. Just remember that it's an array of graphics that measure 4x2
screen pixels.
CBP0 sub-file type:
Eight of these (in frame order) appended together make up a complete
CBF0 sub-file that replaces the previous CBF0 sub-file information.
After you've displayed each eighth frame, you need to replace the
current CBF0 information with the new one you've made up from eight
CBP0 sub-files. Just do it, OK? This will make more sense when we
get to the VPTZ sub-file type.
CPL0 sub-file type:
The palette for the VQA file. An array of Red, Green and Blue byte
values (in that order). Note that there are sometimes less than 256
colours in the palette.
VPTZ sub-file type:
Well, here it is. This is the heart of the VQA file, the graphics.
Each VPTZ sub-file is compressed with the Format 80 method as
described later in this document.
When you decompress a VPTZ sub-file, you get an 80x156 graphic. The
top half (the first 78 lines) is the basis of the finished frame,
while the bottom half is a modifier for the pixels in the top half.
The final size of each VQA frame is 320x156. With the top half
(basis of the finished frame, remember) being 80x78, you can see that
we need to multiply by four in the X (horizontal) direction, and by
two in the Y (vertical) direction. Imagine that each pixel in the
top half in fact represents eight screen pixels, arranged in a 4x2
format.
I must distinguish between pixels and screen pixels. By pixel, I
mean one byte read from the decompressed VPTZ graphic, which, when
displayed on screen, measures 4x2 screen pixels.
Now, if you view a VQA, you can see that there is a higher resolution
used than each pixel being 4x2 screen pixels. This is where the
bottom half and the CBF0 sub-file type comes in.
The bottom half is an overlay of modifiers for the top half. That
is, the top-left pixel in the bottom half is a modifier for the top-
left pixel in the top half. The bottom half pixel values range from
00h to 0Fh.
0Fh means `no modifcation'. The corresponding pixel value in the top
half is copied eight times to produce the 4x2 screen pixel format.
00-0Eh are modifiers. If you treat these pixel values as the high
byte in a Word value, and treat the corresponding pixel value in the
top half as the low byte, you get the CBF0 array element number of
the 4x2 screen graphic you should display for that pixel. Make
sense? That is how the higher resolution is achieved.
Perhaps I should clarify. If TopByte is the top half pixel byte
value, and BottomByte is the bottom half pixel byte value, then the
4x2 screen pixel graphic is element number (BottomByte * 256 +
TopByte) in the CBF0 array.
Just display the frames in order, and presto! You have a VQA movie.
Format 80 compression method
by Vladan Bato (bat22@geocities.com)
----------
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).

View File

@@ -1,276 +0,0 @@
COMMAND & CONQUER GOLD AND C&C: RED ALERT *.VQP FILES
by Gordan Ugarkovic (ugordan@yahoo.com)
http://members.xoom.com/ugordan
Revision 1.02
Command & Conquer is a trademark of Westwood Studios, Inc.
Command & Conquer is Copyright (C)1995 Westwood Studios, Inc.
Command & Conquer: Red Alert is a trademark of Westwood Studios, Inc.
Command & Conquer: Red Alert is Copyright (C)1995-1999 Westwood Studios, Inc.
DESCRIPTION:
I used to think that viewing the Red Alert movies in SVGA gives you a higher
resolution, but recently I found out that this is not the case. The movie
resolution remains the same, you simply stretch a low-res movie (320x156 or
320x200) to double its width (640 pixels) and between two adjacent
horizontal pixels you insert a third one that has a color which is the
average value of the 2 pixels' colors.
When I say average value, I don't mean averaging the indexes to palette,
that would be very easy but incorrect. I mean averaging the COLORS themselves
and finding a color in the palette that most closely matches the desired one.
This process of searching is very slow, so a different method needs to be
applied.
This is where a VQP file comes in. In order to be able to average
(interpolate) colors very fast, one needs a COLOR LOOKUP TABLE.
That is the basic purpose of VQP files: to provide you with the neccessary
color lookup tables.
FILE FORMAT:
The VQP file format is actually very simple.
First there is a LONG INT (4 bytes) value which represents how many
lookup tables for the corresponding VQA movie the VQP contains.
Since every palette has a different color order, we obviously need a new
lookup table every time the palette changes.
After the value come the lookup tables themselves. Every lookup table is
exactly 32896 bytes long. I will explain why there are 32896 bytes in a
lookup table and not 65536 (256*256) as someone might suspect.
The reason for this is that some of the color values repeat, for example
if you have an interpolation value for [23][176], you don't have to write
the value [176][23] because the values will be the same. This saves space
needed by almost 50% !
Let's consider a palette which has 5 colors.
We would have to write the following combinations:
C1 C2 C1 C2 C1 C2 C1 C2 C1 C2
------- ------- ------- ------- -------
0 0 1 0 2 0 3 0 4 0
1 1 2 1 3 1 4 1
2 2 3 2 4 2
3 3 4 3
4 4
Note that none of the combinations repeat.
The number of these combinations is [5+(5+1)]/2 = 15
Likewise, if we had 256 colors, we would have [256+(256+1)]/2 = 32896
different color combinations.
But enough of the math, here is some pseudo-code that will load
the lookup table and fill all the values (it will expand the 32896 bytes
to the full 65536 byte lookup table).
(The lookup table is a 2D array, each dimension having 256 elements):
for C1 = 0 to 255 do
for C2 = 0 to C1 do
begin
val = GetNextByte;
lookup[C1][C2] = val;
lookup[C2][C1] = val;
end;
The function GetNextByte should return the next byte from the file
or from the memory buffer.
Every time the palette changes you run that piece of code
to load the correct lookup table and you'll be fine.
Now, let's say that Left is the color of the left pixel, Right is the
color of the right pixel and Middle is the color we need. We would
get this color value by simply indexing into the lookup table:
Middle = lookup[Left][Right]; (or lookup[Right][Left], it's the same)
It is interesting to note that, with these lookup tables, it is
possible to do a full interpolation of the movies, that is, interpolate
in the vertical direction as well, unlike the Red Alert Win95 version
which only interpolates in the horizontal direction.
Having said that, one can wonder: Where are all the VQPs located?
For SIZZLE.VQA and SIZZLE2.VQA it was easy, but what's with all the
other movies?
So, I started looking and, well, you know those 8 MB of unknown data
located between the 640x400 VQA start movie and SPEECH.MIX in
REDALERT.MIX... :)))
Anyway, here goes...
REDALERT.MIX OFFSETS OF *.VQP FILES
FOR ALL RED ALERT MOVIES
[ENGLISH RED ALERT VERSION ONLY]
~~~~~~~
Movie names are from FILENAME.TXT by Moritz Mertinkat.
Here is what he has to say about the document:
<These excerpts were taken from "The Red Alert Single Player Mission
Creation Guide" (Release 1.1), Copyright 1997 by Andrew Griffin and
C. F. Harkins (andrewg@light.iinet.net.au and cfhark@msn.com).
The latest version can be found at: www.geocities.com/TimesSquare/5458
The text above was slightly modified by Moritz Mertinkat for use in
RA-MIXer; i.e. I added some aspects and corrected some parts of the
text which provided wrong (or not enough) information.
Moritz Mertinkat (ramixer@gmx.net), 23-MAR-1998>
NOTE: Although the offsets given here are for the English version of
Red Alert, I assume the movie names are the same for all the
other language versions and so is the ordering of the VQPs in
REDALERT.MIX. In the English version, the VQPs follow immediately
after the 640x400 VQA. The first one is one of the copies of VQP
for the Lands of Lore 2 Sneak Peek (See note later in the document).
The next one is for AAGUN, so if you are able to find the VQP for it,
you will probably be able to find all the other offsets because
they are stored in succession, one after the other.
Movie name Offset (from start of file, decimal)
-----------------------
AAGUN 16101380
AFTRMATH 16134280
AIRFIELD 20279388
ALLY1 16167180
ALLY2 16529060
ALLY4 16561960
ALLY5 16594860
ALLY6 16660656
ALLY8 16693556
ALLY9 16759352
ALLY10 16232976
ALLY10B 16265876
ALLY11 16298776
ALLY12 16463260
ALLY14 16496160
ALLYEND 16792252
ALLYMORF 16825152
APCESCPE 16858052
ASSESS 16890952
AVERTED 20410984
BATTLE 16923852
BEACHEAD 20443884
BINOC 16956752
BMAP 16989652
BOMBRUN 20509684
BRDGTILT 17022552
COUNTDWN 20542584
CRONFAIL 17088352
CRONTEST 17055452
DESTROYR 17121252
DOUBLE 20575484
DPTHCHRG 20608384
DUD 17154152
ELEVATOR 17187052
EXECUTE 20641284
FLARE 17219952
FROZEN 17252852
GRVESTNE 17285752
LANDING 20707084
MASASSLT 17351552
MCV 17384452
MCVBRDGE 20739984
MCV_LAND 17417352
MIG 20772884
MOVINGIN 21101848
MONTPASS 17450252
MTNKFACT 21134748
NUKESTOK 21167648
OILDRUM 17483152
ONTHPRWL 21200548
OVERRUN 17516052
PERISCOP 21233448
PROLOG 17548952 and 21266348
RADRRAID 21792688
REDINTRO 18075292 and 21825588
SEARCH 21858488
SFROZEN 21891388
SHIPSINK 18108192
SHORBOMB 18173992
SHORBOM1 18141092
SHORBOM2 18173992
SITDUCK 21924288
SLNTSRVC 21957188
SNOWBOMB 18305584
SNSTRAFE 22022988
SOVBATL 22055888
SOVCEMET 22088788
SOVFINAL 22121688
SOVIET1 18338484
SOVIET2 22450676
SOVIET3 22483576
SOVIET4 22516476
SOVIET5 22549376
SOVIET6 22582276
SOVIET7 22615176
SOVIET8 22648076
SOVIET9 22746768
SOVIET10 22286176
SOVIET11 22319076
SOVIET12 22351976
SOVIET13 22384876
SOVIET14 22417776
SOVMCV 22812564
SOVTSTAR 18371384
SPOTTER 22878364
SPY 18404284
STRAFE 22911264
TAKE_OFF 22944164
TANYA1 18437184
TANYA2 18470084
TESLA 22977064
TOOFAR 18502984
TRINITY 18535884
V2ROCKET 23009964
As you can see, even the low-res version of REDINTRO contains a VQP.
At least 3 VQAs have 2 copies of VQP data (PROLOG, REDINTRO and LoL 2 SP).
I don't know why this is, but the copies appear to be the same.
Clearly a waste of disk space (Lands of Lore 2 SP VQPs are each 1,7 MB !)...
Apart from the movies listed above, MAIN.MIX also contains a slightly
different version of Lands of Lore 2 Sneak Peek than in the root
of the CDs. As I said, a VQP for this movie exists, and there are 2 copies
of it (offsets 14456576 and 18568784), but they don't contain
lookup data for all 52 palettes, so the last 2 palettes are messed up.
I don' know why the guys at Westwood even bothered to store this VQA
in MAIN.MIX, when there is one in the root of the CD, obviously
more disk space wasted... :(((
Also, the VQP for one of the Allied briefings (I think ALLY1) indicates
the corresponding VQA has more palettes than it actually has, but that
shouldn't present a problem.
If you want to include these offsets in your program, please ask for
my permission.
If you have any questions or comments, feel free e-mail me.
--------------------------------
Gordan Ugarkovic (ugordan@yahoo.com)
27 July 1999.
[END-OF-FILE]

View File

@@ -21,12 +21,17 @@ make package
# Remove the mdb files that are created during `make` # Remove the mdb files that are created during `make`
find . -path "*.mdb" -delete find . -path "*.mdb" -delete
Markdown.pl README.md > README.html
Markdown.pl CONTRIBUTING.md > CONTRIBUTING.html
Markdown.pl DOCUMENTATION.md > DOCUMENTATION.html
# List of files that are packaged on all platforms # List of files that are packaged on all platforms
# Note that the Tao dlls are shipped on all platforms except osx and that # Note that the Tao dlls are shipped on all platforms except osx and that
# they are now installed to the game directory instead of placed in the gac # they are now installed to the game directory instead of placed in the gac
FILES="OpenRA.Game.exe OpenRA.Editor.exe OpenRA.Utility.exe OpenRA.Renderer.SdlCommon.dll OpenRA.Renderer.Cg.dll \ FILES="OpenRA.Game.exe OpenRA.Editor.exe OpenRA.TilesetBuilder.exe OpenRA.Utility.exe OpenRA.FileFormats.dll \
OpenRA.Renderer.Gl.dll OpenRA.Renderer.Null.dll OpenRA.FileFormats.dll FreeSans.ttf FreeSansBold.ttf titles.ttf \ OpenRA.Renderer.SdlCommon.dll OpenRA.Renderer.Cg.dll OpenRA.Renderer.Gl.dll OpenRA.Renderer.Null.dll \
cg glsl mods/ra mods/cnc mods/d2k COPYING HACKING INSTALL CHANGELOG" FreeSans.ttf FreeSansBold.ttf titles.ttf cg glsl mods/ra mods/cnc mods/d2k \
README.html CONTRIBUTING.html DOCUMENTATION.html COPYING HACKING INSTALL CHANGELOG"
echo "Copying files..." echo "Copying files..."
for i in $FILES; do for i in $FILES; do