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:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -54,4 +54,8 @@ OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3
|
|||||||
|
|
||||||
# KDE crap
|
# KDE crap
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
*.directory
|
*.directory
|
||||||
|
|
||||||
|
# auto-generated documentation
|
||||||
|
DOCUMENTATION.md
|
||||||
|
*.html
|
||||||
6
Makefile
6
Makefile
@@ -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)
|
||||||
|
|||||||
@@ -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```");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
5179
doc/RACG110.TXT
5179
doc/RACG110.TXT
File diff suppressed because it is too large
Load Diff
@@ -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
|
|
||||||
|
|
||||||
625
doc/cncff.txt
625
doc/cncff.txt
@@ -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
|
|
||||||
500
doc/cncmap.txt
500
doc/cncmap.txt
@@ -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.
|
|
||||||
2064
doc/cncrules.ini
2064
doc/cncrules.ini
File diff suppressed because it is too large
Load Diff
@@ -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...
|
|
||||||
@@ -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
|
|
||||||
-- ????
|
|
||||||
|
|
||||||
@@ -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.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
988
doc/raff.txt
988
doc/raff.txt
@@ -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
|
|
||||||
@@ -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.
|
|
||||||
@@ -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
|
|
||||||
350
doc/vqa_frmt.txt
350
doc/vqa_frmt.txt
@@ -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).
|
|
||||||
|
|
||||||
276
doc/vqp_info.txt
276
doc/vqp_info.txt
@@ -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]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user