Test: Load c&c terrain tiles

This commit is contained in:
Paul Chote
2010-03-01 20:52:38 +13:00
parent 88f322d3cc
commit 3fd7af5532
8 changed files with 1176 additions and 21 deletions

View File

@@ -29,27 +29,52 @@ namespace OpenRA.FileFormats
public Terrain( Stream stream ) public Terrain( Stream stream )
{ {
int Width, Height; int Width, Height, IndexEnd, IndexStart;
uint ImgStart;
// Try loading as a cnc .tem
BinaryReader reader = new BinaryReader( stream ); BinaryReader reader = new BinaryReader( stream );
Width = reader.ReadUInt16(); Width = reader.ReadUInt16();
Height = reader.ReadUInt16(); Height = reader.ReadUInt16();
if( Width != 24 || Height != 24 ) if( Width != 24 || Height != 24 )
throw new InvalidDataException( string.Format( "{0}x{1}", Width, Height ) ); throw new InvalidDataException( string.Format( "{0}x{1}", Width, Height ) );
/*NumTiles = */reader.ReadUInt16(); /*NumTiles = */reader.ReadUInt16();
reader.ReadUInt16(); /*Zero1 = */reader.ReadUInt16();
/*XDim = */reader.ReadUInt16(); /*uint Size = */reader.ReadUInt32();
/*YDim = */reader.ReadUInt16(); ImgStart = reader.ReadUInt32();
/*uint FileSize = */reader.ReadUInt32(); /*Zero2 = */reader.ReadUInt32();
uint ImgStart = reader.ReadUInt32();
reader.ReadUInt32(); if (reader.ReadUInt16() == 65535) // ID1 = FFFFh for cnc
reader.ReadUInt32(); {
int IndexEnd = reader.ReadInt32(); /*ID2 = */reader.ReadUInt16();
reader.ReadUInt32(); IndexEnd = reader.ReadInt32();
int IndexStart = reader.ReadInt32(); IndexStart = reader.ReadInt32();
}
else // Load as a ra .tem
{
stream.Position = 0;
// Try loading as an RA .tem
reader = new BinaryReader( stream );
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
if( Width != 24 || Height != 24 )
throw new InvalidDataException( string.Format( "{0}x{1}", Width, Height ) );
/*NumTiles = */reader.ReadUInt16();
reader.ReadUInt16();
/*XDim = */reader.ReadUInt16();
/*YDim = */reader.ReadUInt16();
/*uint FileSize = */reader.ReadUInt32();
ImgStart = reader.ReadUInt32();
reader.ReadUInt32();
reader.ReadUInt32();
IndexEnd = reader.ReadInt32();
reader.ReadUInt32();
IndexStart = reader.ReadInt32();
}
Log.Write("IndexStart: {0}",IndexStart);
stream.Position = IndexStart; stream.Position = IndexStart;
foreach( byte b in new BinaryReader(stream).ReadBytes(IndexEnd - IndexStart) ) foreach( byte b in new BinaryReader(stream).ReadBytes(IndexEnd - IndexStart) )

View File

@@ -76,6 +76,7 @@ namespace OpenRA.FileFormats
using( Stream s = FileSystem.Open( tilename + suffix ) ) using( Stream s = FileSystem.Open( tilename + suffix ) )
{ {
Log.Write(tilename+suffix);
if( !tiles.ContainsKey( (ushort)( start + i ) ) ) if( !tiles.ContainsKey( (ushort)( start + i ) ) )
tiles.Add( (ushort)( start + i ), new Terrain( s ) ); tiles.Add( (ushort)( start + i ), new Terrain( s ) );
} }
@@ -88,9 +89,11 @@ namespace OpenRA.FileFormats
public byte[] GetBytes(TileReference r) public byte[] GetBytes(TileReference r)
{ {
Terrain tile; Terrain tile;
if( tiles.TryGetValue( r.tile, out tile ) ) try {
return tile.TileBitmapBytes[ r.image ]; if( tiles.TryGetValue( r.tile, out tile ) )
return tile.TileBitmapBytes[ r.image ];
} catch (System.ArgumentOutOfRangeException) {}
byte[] missingTile = new byte[ 24 * 24 ]; byte[] missingTile = new byte[ 24 * 24 ];
for( int i = 0 ; i < missingTile.Length ; i++ ) for( int i = 0 ; i < missingTile.Length ; i++ )
missingTile[ i ] = 0x36; missingTile[ i ] = 0x36;

View File

@@ -1,4 +1,4 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA. * This file is part of OpenRA.
@@ -34,7 +34,9 @@ namespace OpenRA
Sprite[] shadowBits = SpriteSheetBuilder.LoadAllSprites("shadow"); Sprite[] shadowBits = SpriteSheetBuilder.LoadAllSprites("shadow");
Sprite[,] sprites = new Sprite[128, 128]; Sprite[,] sprites = new Sprite[128, 128];
bool dirty = true; bool dirty = true;
bool hasGPS = false;
// TODO: Testing
bool hasGPS = true;
Player owner; Player owner;
Map map; Map map;
public Rectangle? bounds; public Rectangle? bounds;

625
doc/cncff.txt Normal file
View File

@@ -0,0 +1,625 @@
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 Normal file
View File

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

View File

@@ -43,7 +43,6 @@
Building: Building:
Dimensions: 1,1 Dimensions: 1,1
Footprint: x Footprint: x
BaseNormal: no
BuildSounds: constru2.aud, hvydoor1.aud BuildSounds: constru2.aud, hvydoor1.aud
SellSounds: cashturn.aud SellSounds: cashturn.aud
RenderBuilding: RenderBuilding:

View File

@@ -15,6 +15,7 @@ Packages:
mods/cnc/packages/sounds.mix mods/cnc/packages/sounds.mix
mods/cnc/packages/tempicnh.mix mods/cnc/packages/tempicnh.mix
mods/cnc/packages/updatec.mix mods/cnc/packages/updatec.mix
mods/cnc/packages/temperat.mix
# Cannot qualify the RA names because they may live inside a mix # Cannot qualify the RA names because they may live inside a mix
~main.mix ~main.mix
redalert.mix redalert.mix

View File

@@ -32,7 +32,7 @@ World:
PaletteFromFile@terrain_temperat: PaletteFromFile@terrain_temperat:
Name: terrain Name: terrain
Theater: temperat Theater: temperat
Filename: temperat_ra.pal Filename: temperat.pal
PaletteFromFile@player_temperat: PaletteFromFile@player_temperat:
Name: player Name: player
Theater: temperat Theater: temperat