Commander Keen EGA Header
Many early (1989-1993) id Software/Softdisk games use an EGAHEAD.* file to read their graphics files. While the number and function of various graphics files vary substantially across various games, the header format itself is rather constant, with only a few minor variations. (Indeed it is possible to see a progressive development of the format over the years by tracing changes across several games.) In Commander Keen 1-3 itself two Raw EGA data files contain all the tiles, sprites and in-game images. In other games more files are usually required.
There are 'types' of graphics, 8x8 fonts, 16x16 tiles, unmasked images and masked sprites. Sprites are almost always stored separately because they usually require 5 planes of EGA data, not 4.
The EGAHEAD file may be external or internal and is divided into three parts, the first section deals with the number and location of fonts, tiles, images and sprites. The second section is a list of the names of unmasked images (Each 16 bytes long.) and the third (And usually largest.) section deals with a list of the names of sprites. (Each 128 bytes long.)
Note that the addresses of graphics are offsets from where an EGA plane starts. So with a plane size of 100, the address 40 would have us looking for data at 40, 140, 240... in the graphics file. If graphics are stored separately, then this address is usually blank (Since it will start at the file start.)
Commander Keen format
Section 1: 0 4 Latplansiz Size of 4-plane EGA plane; should be one quarter of the size of the UNCOMPRESSED EGA file size. In Keen this is for the EGALATCH file. 4 4 Sprplansiz Size of 5-plane EGA plane; should be one fifth of the size of the UNCOMPRESSED EGA file size. In Keen this is EGASPRIT. This may be blank in games that store their sprites in multiple files. 8 4 Imgdatstart Where in the EGAHEAD the entries for unmasked graphics (Excluding font and tiles.) start. If there are none, this is blank. 12 4 Sprdatstart Where in the EGAHEAD the entries for masked graphics (Sprites) start; by default this is right after the unmasked graphics. 16 2 Fontnum Number of 8x8 font entries are in the font; note that many games have this for drawing windows, with the actual black and white font stored in the executable. 18 4 Fontloc Offset in memory where font data is placed. Should be zero since font is first. In Keen 1-3 also the location in LATCH file where font data starts. 22 2 Unknum Used for the ending screen until this was removed. Number of screen graphics. 24 4 Unkloc Used for screen graphics until removal. Offset in memory where screen data placed. 28 2 Tilenum Number of 16x16 tiles 30 4 Tileloc Offset in memory\LATCH where tile data placed\starts. 34 2 Bmpnum Number of unmasked bitmaps 36 4 Bmploc Offset in memory\plane where unmasked bitmap data starts\placed. 40 2 Spritenum Number of sprite images 42 4 Spriteloc Offset in EGASPRIT plane of start of sprite data. Is, of course, zero. Also relates to memory 46 2 Compression Add 2 to this byte if EGALATCH is compressed, add 1 to it if EGASPRIT is compressed. Thus uncompressed graphics have this set at 0 and fully compressed at 3. The only game that compresses its graphics like this is Commander Keen 1. Attempting to set any compression for the other games will result in garbage graphics.
Section 2: 2 Size h The width of the graphic divided by 8 2 2 Size v The height of the graphic in pixels; if this cannot be divided into neat 16 byte pieces, the extra data, usually 8 bytes, is added to the size. 4 4 Loc When added to the graphic offset in the header, gives the location of the start of the graphic data in the plane. For the first graphic this is thus zero. 8 8 Name Name of the graphic, padded with nulls.
Section 3: 0 2 Width The width of the graphic divided by 8 2 2 Height The height of the graphic in pixels; the same rule applies as for unmasked graphics except now we have: 4 2 Loc offset Usually 8, this is the number of bytes 'extra' that must be added to the location to reach the start of the sprite data. This appears when a sprite is so small, usually 8x8 pixels, that it doesn't fill a multiple of 16 bytes. This will affect ALL sprites after the aberration until another one occurs to fix the shortfall. 6 2 Location Multiplying this by 16 bytes gives the location of the start of the sprite data in the EGA plane. 8 4 Hitbox ul Location of the upper-left corner of the sprite's hitbox or collision rectangle, in pixels, starting from 0,0. First two bytes are the h location and the next two are the v location. In the EGAHEAD, both values are multiplied by 256. 12 4 Hitbox br Same as above, for the bottom left corner. 16 12 Name The sprite name, usually includes a number and is usually only 10 bytes long. May spill into the next field in games that do not use that. 28 4 h/v off The horizontal and vertical offset of the sprite frame from the sprite event. In early games this is blank, but in later ones such as Shadow Knights it is utilized. This can be used to 'line up' frames of different heights and so on. 32 3*32 Copies Games use these entries for smooth movement; each 32 byte entry is a copy of the initial sprite shifted 2 pixels left. The game will automatically generate the graphics, but the preceding information must be duplicated. In the copies, 1 is added to the width field.
There are several differences between other games and Commander Keen. The most notable is usually the presence of more than two graphics files. Sprites are often split into various S_* files, each of which is compressed, containing, as its first word, the decompressed file size (Including the word itself and any header the raw data may have.) It is usually not hard to calculate a plane size from this.
Addresses in the header will point to the right location in whatever file is being used at the time. Thus is sprites have been split up into several files, it is possible to see when files are 'switched' whenever the pointer for a sprite is less (usually 0) than the pointer to the previous sprite. (A new file is being opened and data read from the start of it, instead of the end of the old file.) Note however that the order sprite files are opened and how many sprites they contain is usually hard-coded.
Another effect of this is that pointers in the EGA are used for memory, NOT files. In Keen they are the same, since the EGALATCH is copied directly into memory in segments, essentially the whole file is copied as-is. In other games with more files the game is hard-coded to calculate where to read from the number of graphics entries, their size or whether or not a file has been opened so they header pointers are not a reliable guide.
Aside fro Commander Keen, no other games are LZW compressed and so don't use that feature in the header. Other forms of compression are used which may or may not be indicated in the header somehow.
As games progressed an additional modification was added to the header format; the last four bytes of a sprite's name were set aside to be h and v offsets of the sprite image (as used in Commander Keen 4-6 games.) This left a sprite with a maximum name length of 11 bytes. Since the last four bytes are seldom used (are zero), it can often be assumed that all games use this with few problems.
Finally is the issue of 'sprite blitting' The header's sprite entries are 128 bytes long, being essentially four copies of a 32 byte entry. In earlier games each was in fact a separate entry, there were in effect four times the number of sprites, each one used for when a sprite was moving 0, 2, 4, and 6 pixels left or right. Later games automated the creation of these sprites, shrinking file size. For simplicity the header format was left as-is.
Dangerous Dave in Copyright Infringement
Dangerous Dave 2
Dangerous Dave 2 stores the header and LATCH internally in the executable at 74896 and 101096 respectively (in the UNLZEXE'd executable.) Because the EGALATCH.DD2 file is stored internally there is an interesting situation with 8x8 tiles and unmasked bitmaps; the EGAHEAD points to 32 8x8 tiles, but the last tile is overwritten by the start of the unmasked bitmap data. This means that 8 bytes from each EGA plane are copied into memory twice, once as the end of 8x8 tiles and again as the first unmasked bitmap. It also means that the 'location' of the bitmaps (e.g. $100) is 8 bytes larger than the location of the EGA data in the internal file.
Otherwise the format is nearly identical. Number of unmasked bitmaps and their location are at 40\42 in the header instead of 34\36. There is no sprite plane size at 4 since the sprites are stored in several compressed files (each containing its own planesize.) Tiles are stored in a separate file EGATILES.DD2. Since each tile may or may not be loaded in a level depending on whether it's needed, the tile file is composed of 858 128-byte entries, each containing 4-EGA planes for the tile. There is a 'copy' of the EGA planesize at byte 40 and bytes 22-34 and 52-64 are blank or contain nonsense data.
Rescue Rover has two sprite files, S_PLAY.ROV and S_DEMO.ROV used in that order. Bitmaps and 8x8 font are stored in EGAPLANE.ROV, tiles are 32x32 and stored in EGABTILE.ROV (TED 16x16 tiles are stored in a file not used by the game, EGATILES.ROV. Finally a monochrome font is stored in EGAFONT0.ROV There are also several compressed screen images, *PIC.ROV
The number\location-in-file of the sprites are stored at slightly different places, at bytes 47 and 49 instead of 41 and 43. In practice the location of tile and sprite data is 0, since they do not share files with any other EGA graphics.
Shadow Knights uses the same (subtly different) EGA header as Rescue Rover, this document http://levellord.rewound.net/Index/File%20Formats/Shadow%20Knights/Shadow%20EGA.txt describes how the compression used for the sprites and the slightly odd layout of the tile data works.
Slordax uses a format exactly identical to Commander Keen.
This format has been reverse engineered several times, mostly by the Commander Keen community. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)