[By Josef: This is a page written by Chris Becke, which disappeared from the web some time ago. Because it still contains useful information, I present it here. Everything here was written by Chris Becke, except for this introduction.]

Transport Tycoon

Here is some stuff I have relating to Transport Tycoon.

Transport Tycoon Versions
Links
Playing without a CD
Transport Tycoons Internals


Transport Tycoon Versions

These are the versions of Transport Tycoon I know of:

Box Name Released By Description
Transport Tycoon Playable Demo Microprose The original Transport Tycoon playable demo runs for two years, and only trains are available.
Transport Tycoon Microprose The original Transport Tycoon
Transport Tycoon World Editor Microprose The original Transport Tycoon, with a scenario editor and an addition tileset for the surface of mars.
Transport Tycoon Deluxe Microprose The enhanced version of the game features 4 environments: classic (temperate), tropical / dessert, alpine and toyland. Mars is NOT included.
Transport Tycoon Deluxe for Windows Hasbro A windows port of Transport Tycoon Delux shipped as part of the Hasbro Tycoon Collection - a package set that includes Rollercoaster Tycoon, Railroad Tycoon II and Transport Tycoon Deluxe


Playing Transport Tycoon Deluxe without a CD

After installation the tycoon.bat file must be edited. It runs ttdlx.exe with a parameter indicating where to find the cd files. Either copy the files from the root of the cd-rom into the tycoon directory (and delete the command line parameter), or change the parameter to point to where the cd-rom image is stored.



Links

Phil McCrum's and Bill & Mikes Tycoom pages are excellent and full of info, even if they do overlap to a large degree. When they finally bore you, there are many other good pages that can be found searching the Transport Tycoon Webring.



Transport Tycoon Internals

The files in the Transport Tycoon Delux CD and directory are generally of one of the following types:

Graphic
All files with the GRF extension contain graphics
Scenario / Save game
*.sv0 are user edited scenario files.
*.sv1 are save games
*.sv2 are multiplayer savegames
*.ss0 are built in scenario files
*.ss1 are built in save games
Catalog Files
CAT files contain BLOBs of data. sample.cat contains all the sounds used by the game in WAVE format
PAT files
adlib.cat, gm.cat and roland.cat all contain a PAT file data that is transport tycoons music. The PAT file appears to be some sort of MIDI stream, but I don't know enough to get it into a playable format

tttools.zip (5Kb) is a small archive containing some interesting things.

Yes these tools lake a little finesse :) I can't really be bothered to put a lot of work into them.



CAT file format

The cat file begins with an index with 4 byte values alternately indicating the position in the file of the next BLOB, followed by the length of the BLOB.

There is no count of the number of entries in the index - a reader must simply stop reading the index when it reaches the first BLOB

The actual BLOB data is made up of two parts: A name field, and the source file data.

The name field begins with a byte counting the number of bytes of name that follow (not counding the initial byte). The bytes that follow seem to be a zero terminated ascii string.

This code fragment shows you might read in a BLOB. pfile is a file pointer that has already beek seeked to the BLOB offset as obtained from the index:

  unsigned char cb;
  fread(&cb,1,1,pFile);
  fread(pName,cb,1,pFile);
  fread(pBuffer,length,1,pFile);


GRF file format

The GRF files appear to be a catalog of sprites. The file consists of a variable number of sprite blobs, and finishes with a 4 byte value being the sum of the lengths of the sprite blobs.

Each sprite blob begins with a 16bit number being the number of bytes that follow the length field, before the next sprite blob (or the end of the file). These 16bit headers are not counted in the file size written to the end of the file

At this time I don't know how to decode the sprite data itself. It appeard the 1st byte has some significance - 0xff & 0x02 are checked by the loading code. The sprite painting routines appear the skip the 1st byte.



SV1/SV2/SS0/SS1/DAT save game file format

The save consists of three streams of compressed data, followed by a 4 byte checksum value calculate a rather unorthodox way. Was Chris Saywer really tring to protect the files from corrutpion? Or hacking? Well, here the formula is, which only goes to show that game authors should spend more time improving the game, and waste less time trying to stop creative editing :)

this table describes the basic file layout. Whereever two sizes are given, the first size refers to the size of the structure in TTO, the 2nd size is the size in TTDLX

field Size (bytes) Description
name 39 / 47 The name the file was saved as
name-check 2 A 16bit checksum of the name to allow the load dialog to display a list of games without checksumming the entire file.
data (variable) The RLE compressed data.
file-check 4 A checksum of the entire file, including the name, name-check, and data fields.

Calculating the name checksum

The name checksum is calculated by adding each byte in the name field to a 16 bit accumulator, rotating the accumulator left one bit after each addition. Finally, the checksum is xored with 0xAAAA.

This C-code function demonstrates how.

WORD CalcTitleChecksum(
  char* pszTitle,  // A pointer to the name of the savegame
  int cb)          // set to either 39 or 47 for TTO or TTD savegames
{
  WORD sum = 0;

  for(int i=0; i<cb; i++)
  {
    sum += pszTitle[i];
    sum = (sum << 1) + (sum >> 15);
  }

  return sum ^ 0xAAAA;
}

Calculating the file checksum

The checksum is calculated by summing each byte in the file, in sequence, into a 32bit checksum value. The result of the addition is truncated to the lower 8 bits. The checksum is then rotated left 3 bit positions. Finally, 105116 is added to the checksum value. The following pseudo code demonstrates how to calculate the checksum:

Transport tycoon deluxe changes the checksum calculation only slightly. Instead of adding 105116, 201100 is added. Or subtracted, in the case of title.dat (the map thats loaded to display in the background of the main menu!)

unsigned long calcchecksum(unsigned char* pbData, int cbData)
{
  union
  {
    unsinged long l;
    unsigned char b;
  } checksum = 0;

  for(int i=0; i<cbData; i++)
  {
    checksum.b += pbData[i];
    checksum.l = _lrotl(checksum.l,3);
  }

  if(version == 1)
    checksum.l += 0x019a9c;
  else if(loading_title)
    checksum.l -= 201100;
  else
    checksum.l += 201100;

  return checksum.l;
}

If you actually use this, don't forget that the file size you pass in must be less the 4 byte checksum itself.

Reading the V1 / (TTO) Data

The compressed data section, once expanded, contains the following game structs:

The game structs are:

Reading the V2 / (TTDLX) Data

The compressed section, once expanded, contains the following game structs:

The decompression algorithm is a RLE variant that works like this:

Starting at position 41 / 49 read a byte - this we will call the rlecode. If the rlecode byte is positive then read the next (rlecode+1) bytes and write them to the decompressed data. If the rlecode is negative then the next byte is repeated (-rlecode+1) times in the decompressed data. Immediately following the (one or many) bytes just read is the the next rlecode byte (unless of course you have run out of file).

Once again - an incredible stupid C function demonstrating the procedure

void rle_expand(
  BYTE* pBuf,   // For TTD, a pointer to a 618873 byte buffer
  BYTE* pSrc,   // points the the source RLE data.
  int cb)       // the size of the sorce data.
{
  BYTE* pEnd = pSrc + cb;

  while(pSrc < pEnd)
  {
    int code = (char)*pSrc++;

    if(code < 0)
    {
      BYTE v = *pSrc++;
      do
        *pBuf++ = v;
      while(code++);
    }
    else
    {
      do
        *pBuf++ = *pSrc++;
      while(code--);
    }
  }
}