| FAQ | Downloads | Screen Shots | Tech Docs
File Format Specifications
 

Batman The Caped Crusader
File Format Specifications

By Brian Provinciano

July 4th, 2002


Introduction

These Tech Docs for Batman The Caped Crusader apply to the PC version only. The ports of the game contain completely different file formats.

Before reverse engineering the game, it needed to be unpacked. The program UNEXE was the only one able to successfully unpack it. It needs to be unpacked twice with this program. You first unpack the original EXE, then unpack the produced EXE.


The File Types

The EGA Sprite/Picture Graphics (EGA*.DAT)
The EGA Icon Graphics (*EGAICON.DAT)
The Level Tile Files (*BDATA.DAT)
The Level Information Files (*PDATA.DAT)

 

The EGA Sprite/Picture Graphics

The EGA graphics are quite a simple format. Being four bit, 16 colour images, they are stored in the standard EGA bitplane form, along with a mask on the end. The image is stored in a series of four 1 bit images. Combining them, you will get the final image. They were stored like this for speed since it writes directly to the EGA video.

Picture graphics (EGALOGO.DAT) have no transparency information. The sprites do. The transparency is generated by a fifth 1 bit image, each bit for a pixel. If the bit is set, is will be transparent, otherwise, it will be normal.

There is no size information stored in the files. It is hard coded in the EXE.

Here is the size table:

FILE NAME WIDTH HEIGHT FRAME HEIGHT

File Name Width Height Frame Height
egaalpha.dat 272 8 8
1egaback.dat 16 6016 16
1egabad1.dat 48 640 64
1egabad2.dat 48 640 64
1egaobj.dat 16 200 8
1egatoys.dat 32 256 32
2egaback.dat 16 6016 16
2egabad1.dat 48 640 64
2egabad2.dat 48 640 64
2egaobj.dat 16 200 8
2egatoys.dat 32 192 32
egaclimb.dat 32 384 64
egafire.dat 16 176 8
egajfall.dat 64 128 64
egakick.dat 64 384 64
egalogo.dat 320 192 192
egameter.dat 32 32 16
egapunch.dat 64 448 64
egaturn.dat 48 512 64
egawalk.dat 48 512 64

Each of the four or five (if it has transparency) images are the dimensions of the WIDTH*HEIGHT rather than for each frame.


The EGA Icon Graphics

The icons are each 24x24 images. Each icon file contains 31 icons. Graphics are stored in the same method as the others, except that each icon is separated. It contains 31*4 1 bit images, rather than one large one.


The Level Tile Files

The level tile files are generally just an array of words defining the tile indexes to be used in the level. However, they are stored is a strict ASCII format rather than binary.

The file contains ASCII arrays of tile information for each level. Each time is represented by a three byte ASCII number. If the high bits are zero, they can be represented by a space. Each level it terminated by a 'Z'. Since the character codes are three bytes, a '\r' and '\n' follow it. Finally, the file is padded with '.' characters.

Here is the code I wrote based off the original EXE (should be identical to the original algorithm).

  word_670_12F = Buffer;
  word_670_12D = 1;

  get_next_byte:
  fread(tempBuf,3,1,f);
  di = 0;
  ax = 0;
  loop_top:
    ax = al * 10;
    bx = tempBuf[di];

    if(bl=='Z') // end of room!
      goto loc_0_2731;

    if(bl!=' ') {
      bx = (bh<<8)+(bl-'0');
      ax += bx;
    }
    di++;
    if (di!=3) goto loop_top;

    word_670_12F ++;
    *word_670_12F = ax;
    goto get_next_byte;
  loc_0_2731:
    word_670_12D++;
    roomPointers[word_670_12D] = word_670_12F-Buffer;
    if(bx>mbx) mbx=bx;
    ax = word_670_12D;
    if(al<=totalRooms) goto get_next_byte;

And here is a more readable version I wrote later:

  do {
    fread(char3code,3,1,f);
    if(char3code[0]=='Z') { // End of room
      room++;
      roomPointers[room] = offs*2;
    } else {
      Number = 0;
      for(int i=0;i<3;i++) {
        if(char3code[i]!=' ') {
          Number = (Number*10)+(char3code[i]-'0');
        }
      }
      Buffer[offs]=Number;
      offs++;
    }
  } while(room<totalRooms);

When the game loads the files, it not only converts them to binary, but also builds a look up table with their offsets.


The Level Information Files

The level information files contain each level's width, height, position, surrounding rooms, and door positions. They are stored in an encrypted format. Once decrypted, they are stored in two seperate tables--one for the size and coordinates, the other for the room/door information.

They encryption method is difficult to explain. Here is the code I wrote based off the original algorithm in the EXE...

  totalRooms = fgetc(f)-'#';

  pBuf = 0;
  pBufPlus1 = 1;

  do {
    pBuf++;
    fread(strBuf20,12,1,f);

    ah = (_crotl((strBuf20[0]-'#'),4)&0xF0);
    dh = strBuf20[1]-'#';
    special_adder = 0;
    if(dh<=6) {
      dh+=4;
      special_adder=4;
    }
    ah += dh;

    pDatBuf1[pBuf]         = (ah<<8)|(_crotl((strBuf20[2]-'#'),4)&0xF0);
    pDatBuf1[pBuf+0x80]   = (ah<<8)|(strBuf20[3]-'#');
    pDatBuf2[pBufPlus1+0x100]   = strBuf20[4]-'#';
    pDatBuf2[pBufPlus1+0x180]   = strBuf20[5]-'#';
    pDatBuf2[pBufPlus1+0x200]   = strBuf20[6]-'#';
    pDatBuf2[pBufPlus1+0x280]   = strBuf20[7]-'#';
    pDatBuf2[pBufPlus1+0x300]   = strBuf20[8]-'#';
    pDatBuf2[pBufPlus1+0x380]   = strBuf20[9]-'#';
    pDatBuf2[pBufPlus1]   = ((strBuf20[10]-'#')+special_adder)&0xFF;
    pDatBuf2[pBufPlus1+ 0x80]   = ((strBuf20[11]-'#')+special_adder)&0xFF;
    pBufPlus1++;
    totalRooms--;
  } while(totalRooms);

pDatBut1 contains the level size and coordinates broken up into two word sized arrays, each 0x100 bytes long. The first array contains two bytes for each level. The first is the level's height shifted left four bits. The next contains the level position. The high nibble is the X, the low is the Y (more on this later). The second array contains two byte entries for each level as well. The first entry is the Width of the level, the second is a copy of the position.

I believe it was a limitation of the PC which made it so the levels could only be positioned on spots divisible by eight. The files store more precise locations, but they are lost. So, 3 is the same as 5, for example.

Here are algorithms for obtaining the actual X and Y values:

  ActualX = ((Levels.RmX[rm] - 2) / 2) * 8;
  ActualY = (Levels.RmY[rm] - 1) * 8;

pDatBuf2 contains the level room information. It is broken up into eight 0x80 byte arrays. Each byte represents a level, with mazimum 127.

The arrays are as follows:

0x000: Position of the south door
0x080: Position of the north door
0x100: Unused in the PC version?
0x180: Unused in the PC version?
0x200: Number of the room west of it (0 if none)
0x280: Number of the room east of it (0 if none)
0x300: Number of the room south of it (0 if none)
0x380: Number of the room north of it (0 if none)


end.

BriPro.com ©1999-2008 Brian Provinciano. All rights reserved.