Last Updated September 18, 2004
Many thanks go to Jonathon Wilson for determing much of the information on this page!
The visual items in RCT2 are stored in the g1.dat file in the data directory and as individual dat files in the objdata directory.
The dat files begin with a sixteen byte "DAT File Header". The first four
bytes are flags. The next eight bytes are the ASCII characters of the file
name (padded with trailing spaces as needed). The next four bytes are a checksum.
The DAT File Header is followed by an encoded data chunk. It is the same
type of encoding as described on the SV6/SC6 page. (The first byte specifies
the type of encoding; the next four bytes are the size.) The remainder of
the description here is based on the decoded file. This is a "work in progress"!
I am using the following model for the Dat file structure:
DAT File Header |
Object Header |
String Table(s) |
Group Info |
Optional |
Image Directory |
Graphics Data |
The first byte of the DAT File Header contains a flag to identify the type of dat file. Use the lower four bits to identify the type (0 through 0x0A) of the object. Every object has a DAT File Header, Object Header (different for each object type) and a String Table.
DAT File Header: The high nibble of the first byte of the Flags is used to determine if this is a standard (original=8, 1st expansion pack=1) or custom object (high nibble=0). Also, the lower four bits of the first byte determine the "Type" of the object as described below. The remainder of Flags can be ignored. The last byte of Flags is 0x00 for RCT2 custom files made with my editor, 0x09 for original RCT2 files, and 0x0C for RCT2 expansion pack files. Custom files made with other programs may have any value at this spot. I highly recommend using 0x00.
Flags : longword
filename : 8 bytes
checksum : longword
The Checksum is calculated by starting with the value 0xF369A75B. Read one byte at a time from the decoded file. Start with the first byte of the file, then skip the next three bytes. Then read the eight bytes of the Filename. Skip the four bytes of the checksum (you're calculating it now!). Then process each byte of the remainder of the (decoded) file.
Each byte is processed by XOR'ing it with the low byte of CheckSum. Then CheckSum is rotated left by eleven bits. (this was errantly listed as thirteen earlier)
Object Type |
Description | Obj Header Size |
String Tables | Group Info |
"Optional" | Images |
0 |
Ride/Shop | 0x1C2 | 3 | No | variable size - It starts with a variable number of 3-byte structures.
Start by reading the first byte after the string table. If that byte
is 0xFF, then there are 32 structures. Otherwise, that byte is the value
of how many 3-byte structures to read.
After these, there are four variable length structures. The first byte of each one indicates the length of that structure (not counting the first byte itself). However, if the first byte is 0xFF, use the next two bytes for the length (not counting the three bytes used to indicate length in this case). These four structures specify the loading positions for peeps. There is a byte for each peep position on the ride. The upper and lower nibble specify the X/Y offsets. Some rides have more than one type of vehicle. For example, some rides have less seating in the first vehicle than in subsequent vehicles. Each structure specifies the loading for a vehicle subtype for the ride. For flat rides, the lower 5 bits of the sctructure length specify ? while the remaining upper bits specify ? In the case of shops, there is a single 3-byte structure which contains three bytes of 0x00; while the four other structures are each of zero length. |
Yes |
1 |
Small Scenery | 0x1C | 1 | Yes | Animation Sequence - presence is conditional; determined by a flag in the Obj Header. Consists of a variable number of bytes to indicate the sequence of animation frames. A 0xFF indicates the end of the sequence. Objects such as gears have a simple up-count sequence. Objects such as the bat statues have an up/down sequence so the wings will spread open - then close smoothly. Some objects have a complicated sequence which involve partial up/down counts within the overall sequence. That allows the butterfly to open and close its wings partially as well as fully for a more interesting animation. | Yes |
2 |
large scenery | 0x1A | 1 | Yes | variable - first is a conditional block of 0x40E bytes if bit 3 of the Obj Header flag is set; this is for the "3D" letters for some of the sign objects in the game. Then, there are a variable number of 9-byte structures. Each structure represents a tile of the object. The structure contains the X, Y, base height and clearance height of the tile. There are also flags to indicate which quadrants are occupied and if walls can be built on the sides. The end of this sequence is signaled by a word of 0xFFFF. | Yes |
3 |
Walls | 0x0E | 1 | Yes | 0 | Yes |
4 |
Path Banners | 0x0C | 1 | Yes | 0 | Yes |
5 |
Paths | 0x0E | 1 | No | 0 | Yes |
6 |
Path additions (benches, etc) | 0x0E | 1 | Yes | 0 | Yes |
7 |
Scenery Group | 0x10E | 1 | No | variable size - names of assoc files in 16 byte structures:
Flag : 4 bytes First byte of flag (0xFF indicates termination -no structure) |
Yes |
8 |
Park Entrance | 0x08 | 1 | No | 0 | Yes |
9 |
Water | 0x10 | 1 | No | 0 | Yes |
10 |
Scenario text | 0x08 | 3 | No | 0 | No |
Object Header: Following the DAT File Header is a "Object Header" which is a different structure (and size) for each object type. Here are some Delphi definitions for some of the Object Headers and their flags:
TType1Header = packed record
{00} MsgRef : word; // zero
{02} Fill_1 : longword; // zero
{06} Flags : longword; // zero
{0A} Height : byte;
{0B} CursorSel : byte;
{0C} BuildFee : smallint;
{0E} RemoveFee : smallint;
{10} GraphicsStart : longword; // zero in DAT files
{14} Anim1 : word; // Delay
between individual frames of animation - controls speed
{16} Anim2 : word; // bits0..4:
animation counter mask (ie. sequence length - 1)
// bit 5: 0=continuous animation (sequence
length should be a power of 2)
// bit 5: 1=intermittent; bits 6 and up
indicate interval length
{18} Anim3 : word; // Length
of animation sequence (limit to 0x80)
{1A} BaseIndex : byte; // zero in DAT files
{1B} Fill_2 : byte; // zero in DAT
files
end;
Flag Name | Hex Value | Description |
T1_FULLSQUARE | 00000001 |
Full square tile (else: a quarter tile object) |
T1_OFFSET | 00000002 |
Image vertical reference is based on the center of the tile (else: it is based on the top of the tile) |
T1_FLAT | 00000004 |
Must be on a flat surface. Also, walls can't occupy the same tile |
T1_RARROW | 00000008 |
Provide a rotation button in the scenery dialog |
T1_ANIMATION | 00000010 |
Animated object = multiple frames and animation sequence present |
T1_GARDEN_DRAW | 00000020 |
garden draw logic - three frames which progress over time without water (wither) |
T1_GARDEN_UNK | 00000040 |
garden draw logic - the frames can regress with water (allows handymen to water them) |
T1_DRAW2DIALOG | 00000080 |
Combine the first 2 frames when drawing the item in the scenery dialog |
T1_SPACEA | 00000100 |
Diagonal object - check T1_SPACEC |
T1_GLASS | 00000200 |
A "glass" object: the first image is the "frame" and the second image is the "glass" |
T1_REMAP_1 | 00000400 |
Uses the first remappable color |
T1_1SPRAY | 00000800 |
Use fountain drawing logic = 2 frames: the first frame is stationary and the second is animated |
T1_4SPRAY | 00001000 |
Use fountain/4 drawing logic = the first frame is stationary; there are "back" and "front" animations (for 4 fountain sprays) |
T1_CLOCK | 00002000 |
Use clock drawing logic = the first frame is stationary; there are two animations (the hands of the clock - which are timed to real time) |
T1_SWAMPGOO | 00004000 |
Use the same image for all 4 views; plus animate 16 frames |
T1_ANIMDATA | 00008000 |
Has animation sequence data (a sequence after the "Group Info") |
T1_DRAW2MAIN | 00010000 |
This specifies that the object should use 2 frames instead of 1 for the object on the main game screen |
T1_STACK | 00020000 |
Can be stacked and/or placed on water (e.g. trees dont have this bit set) |
T1_NOWALLS | 00040000 |
Specifies that no walls may be built at the same location as this object (can be built below and above) |
T1_REMAP_2 | 00080000 |
Uses the second remappable color |
T1_NOSUPPORTS | 00100000 |
No supports - useful for "building" components: walls/roofs, etc |
T1_DIALOGFRAMES | 00200000 |
First set of frames are only for the scenery dialog |
T1_SMALL_COG | 00400000 |
? - only used for the small cogwheel |
T1_UNKNOWN | 00800000 |
? - unknown |
T1_SPACEB | 01000000 |
Occupies half of a tile |
T1_SPACEC | 02000000 |
Occupies 3/4 of a tile - T1_SPACEA must be set also |
T1_PAINT_SUPPORTS | 04000000 |
Supports are painted with the first remappable color (else they are painted black) |
T1_POLE | 08000000 |
? - only used for suppleg1.dat |
T1_RESA | 10000000 |
unused |
T1_RESB | 20000000 |
unused |
T1_RESC | 40000000 |
unused |
T1_RESD | 80000000 |
unused |
TType2Header = packed record // Large Scenery : length = 1A
{00}reserved0 : word; // Always zero in files
{02}reserved1 : longword; // Always zero in files
{06}CursorSel : byte;
{07}flags : byte; // bit 3 = 3D
sign
{08}BuildFee : word;
{0A}RemoveFee : smallint;
{0C}reserved2 : longword; // Always zero in files
{10}reserved3 : byte; // Always zero in files
{11}Scrolling : byte; // 0xFF if not scrolling,
otherwise, indicates scrolling direction, location
{12}reserved4 : longword; // Always zero in files
{16}reserved5 : longword; // Always zero in files
end;
Flag Name | Hex Value | Description |
T2_REMAP_1 | 01 | uses first color selection |
T2_REMAP_2 | 02 | uses second color selection |
T2_3DTEXT | 04 | |
T2_SCROLL | 08 | uses standard scrolling text technique |
T2_PHOTOGENIC | 10 | guests appreciate the scenery object (and photograph it) |
T2_UNUSED_1 | 20 | unused |
T2_UNUSED_2 | 40 | unused |
T2_UNUSED_3 | 80 | unused |
TType2TileSpec = packed record
Row : smallint; // div by 32
Col : smallint; // div by 32
Z : smallint; // div by 16
Clearance : byte; // div by 8
Unknown1 : byte; // bit 5 is set to indicate no
supports
Flags : byte; // upper nibble=tile occupation
(F=full tile), lower nibble=walls (0=all sides)
end;
TType3Header = packed record // Walls : length = 14.
{00}reserved0 : word; // Always zero in files
{02}reserved1 : longword; // Always zero in files
{06}CursorSel : byte; //
{07}Flags : byte;
{08}Clearance : byte; //
{09}Effects : byte; // first nibble = visibility (0 = opaque),
upper nibble: 1 = animated (8 frames)
{0A}BuildFee : word; // X 10.
{0C}reserved2 : byte; // Always zero in files
{0D}Scrolling : byte; // 0xFF if not scrolling
end;
Flag Name | Hex Value | Description |
T3_REMAP_1 | 01 |
uses first color selection |
T3_GLASS | 02 | combine two frames |
T3_FLAT | 04 | if set, cannot be built on sloped land |
T3_TWOSIDES | 08 | has a front and a back |
T3_DOOR | 10 | special processing for doorways (36 images) |
T3_UNUSED | 20 | unused |
T3_REMAP_2 | 40 | uses second color selection |
T3_REMAP_3 | 80 | uses third color selection |
TType4Header = packed record // Banners : length = 12.
{00}reserved0 : word; // always zero
{02}reserved1 : longword; // always zero
{06}Scrolling : byte; // 0xFF if not scrolling, otherwise,
indicates scrolling direction, location
{07}Flags : byte;
{08}BuildFee : word; // X 10. refund is 75% (rounded
down)
{0A}reserved2 : word; // always zero
end;
Flag Name | Hex Value | Description |
T4_REMAP_1 | 01 | uses first color selection |
TType6Header = packed record // Path Additions : length = 14.
{00}reserved0 : word; // Always zero in files
{02}reserved1 : longword; // Always zero in files
{06}Flags : word;
{08}Subtype : byte;
{09}CursorSel : byte;
{0A}BuildFee : word; // X 10.
{0C}reserved2 : byte; // Always zero in files
{0D}unknown1 : byte; // Always zero in files
end;
Flag Name | Hex Value | Description |
T6_HOLDTRASH | 0001 | has an extra static frame |
T6_CANSIT | 0002 | |
T6_CANVANDAL | 0004 | has second static frame |
T6_LIGHT | 0008 | |
T6_JUMPFOUNTAIN | 0010 | |
T6_JUMPSNOWBALL | 0020 | |
T6_UNKNOWN1 | 0040 | set for benches and jumping fountains/snowballs and Litter bins |
T6_UNKNOWN2 | 0080 | set for benches and jumping fountains/snowballs |
T6_QLINETV | 0100 |
Subtypes:
0 = Lamp (edge centered, 1 dialog view, 2 frames of static (normal and vandalized)
1 = Litter bin (edge centered/inset, 1 dialog view, 3 frames of static (normal and vandalized, and full)
2 = Bench (edge centered/inset, 1 dialog view, 2 frames of static (normal and vandalized)
3 = Jump fountain (corners, 1 dialog view, 1 frame of static)
String Table(s): Folowing the Object Header
is a string table containing text in different languages.Each string begins
with a byte to specify the language.
Code | Language | 1st Expansion pack |
0 | British English | English |
1 | American English | (not used) |
2 | French | French |
3 | German | German |
4 | Spanish | Spanish |
5 | Italian | Italian |
6 | Dutch | Dutch |
7 | Swedish | Swedish |
9 | Korean? | (not used) |
10 | Chinese | Chinese |
11 | Chinese | (not used) |
13 | Portugese | (not used) |
The string immediately follows that byte and is null terminated. An 0xFF for the Language code indicates the end of the strings. Type 0 and 10 objects have three string tables; other types have one string table.
Group Info: a sixteen byte structure. There is a four byte value. This is followed by an eight byte string indicating which scenery group file this item belongs to (if any). That is followed by a 4-byte value.
Flag : longword (first byte is 0xFF if default item
- 87 for official groups, 07 for custom groups)
FileName : 8 bytes
Checksum: longword = 0
Image directory: First is a 4-byte value which specifies how many images are in the file. Then a 4-byte value which specifies the length of the scan line graphic data (starting after the image directory). Then there is a sixteen byte entry for each image. It uses the same format as the csg1i.dat file of RCT1.
TGraphicRecord = record
StartAddress : longword;
Width, Height, Xoffset, Yoffset : smallint; // signed two byte variables
Flags : word;
unused : word // to pad the structure to 16 bytes
end;
StartAddress points to the start of the scan line index in the file. It is an offset rather than an absolute address - the first scan line index has a StartAddress of 00000000.