Monster Bash Level Format
Monster Bash stores its levels across a number of different files inside BASHx.DAT. Annoyingly, many of the files have the same filename and only differ in the 'filetype code' also stored in the .DAT file.
Map description file
Each map contains a file (of .DAT filetype code #0) which contains the filenames of the other associated files for the level. The file contains a number of fixed-length strings of 31 bytes each, corresponding to a filename in the main .DAT file. Note that the DAT file will have multiple files matching the names used here, so the DAT filetype codes (or fake filename extensions) are used to differentiate between particular files.
|Data type||Description||DAT filetype code/extension|
|char bgtiles||Filename of the background tileset||3 (.tbg)|
|char fgtiles||Filename of the foreground tileset||4 (.tfg)|
|char bonustiles||Filename of the bonus tileset||5 (.tbn)|
|char sprites||Name of the sprite list||6 (.sgl)|
|char palette||Filename of the palette file(?)||14 (.pal)|
|char sounds||Filename of the PC speaker sound effects||8 (.snd)|
|char unknown||Unused slot? (contains "UNNAMED")||N/A|
Each map file uses three tilesets - one for the background and two for the foreground (called bonus and fg below.) See DAT Format (Monster Bash) for details on the file types and image format. The animation frames for each sprite are stored in separate files (one file per sprite.)
The background layer is a list of 16-bit indices into the background tileset. It is stored in a file of .DAT filetype code #1.
|UINT16LE mapWidthBytes||Width of map, in bytes (divide by two to get width in tiles)|
|UINT16LE pixelWidth||Width of map, in pixels (divide by 16 to get width in tiles)|
|UINT16LE pixelHeight||Height of map, in pixels (divide by 16 to get height in tiles)|
|UINT16LE tiles[mapWidth * mapHeight]||Tile codes, one per tile|
The mapStripe value has something to do with calculating offsets into the map file when the game tries to draw parts of the map. If it is off by one, the game can draw the map fine when scrolling horizontally, but when scrolling vertically each row's tiles are drawn with an accumulating offset (i.e. row 2 is missing the first tile in the row, row 3 is missing the first two tiles, and so on.) Greatly reducing the value in lots of 16 allows the map to be drawn correctly, however some of the tile properties are then lost - sprites can't be collected, items can't be shot, etc.
To calculate this value, the following formula seems to work:
mapStripe = pixelHeight * 16 + mapWidthBytes / 2
The lower nine bits of each tilecode are indices into the background tileset (so if
tilecode & 0x1FF was 2, the third tile from the background tileset would be drawn at that location.)
The upper seven bits control the tile's behaviour:
|Bit||Binary (Decimal)||Mask||Purpose when bit is 1|
|1||0000001 (1)||0x0200||Can't walk right into tile|
|2||0000010 (2)||0x0400||Can't walk left into tile|
|3||0000100 (4)||0x0800||Can't fall down through tile (i.e. ground tiles you stand on)|
|4||0001000 (8)||0x1000||Can't jump up through tile|
|5||0010000 (16)||0x2000||Foreground tile contains an interactive item (point, spear, zombie spawning grave, etc.)|
|6||0100000 (32)||0x4000||Slanted tile (direction controlled by foreground tile)|
|7||1000000 (64)||0x8000||Climbable (ladder)|
The foreground layer is a list of 8-bit indices into the two masked tilesets. It is stored in a file of .DAT filetype code #2 (.mfg).
|UINT16LE mapWidth||Width of map, in tiles|
|BYTE tiles[mapWidth * mapHeight]||Tile codes|
The height of the layer is the same as for the background layer. If the background layer is unavailable, it can be approximated by dividing the file's size by the map width, but as some files have an extra 0x00 byte at the end this method requires a little more effort to work correctly.
Each byte represents an index to the tileset. Values with the high bit unset (less than 128) are indices into the bonus tileset, and values with the high bit set (>= 128) are indices into the fg tileset (so a map code of 129 refers to the second tile in the fg tileset.)
The sprite layer is a list of sprite filenames and their coordinates. It is stored in a file of .DAT filetype code #7 (.msp), while the sprites themselves are .DAT filetype code #64 (.spr).
The sprite layer begins with an unknown UINT16LE value which always seems to be 0xFFFE, followed by the below structure repeated until EOF.
|UINT32LE len||Length of this structure, including this field|
|UINT32LE unknown||Always 0x00000000|
|UINT32LE unknown||Unused? Changing seems to have no effect|
|UINT16LE unknown||Always 0x0000|
|UINT32LE x||X-offset, in pixels|
|UINT32LE y||Y-offset, in pixels|
|char filename[len-44]||Sprite filename, with two terminating nulls|
Sprite list (.sgl)
When loading a level, the engine needs to preload all sprites that will be used in the level. Each sprite must be explicitly listed (even if it's listed in the sprite layer) as well as other associated sprites, such as the knife sprite thrown by the knife-thrower. The game will misbehave if it attempts to draw a sprite that has not been loaded.
The names of these sprites are listed in the Sprite List (.sgl) file. This file contains one ASCII filename (no extension) padded with 0x00 to 31 bytes long, one after the other until EOF.
The official files store the sprite names in alphabetical order, however this is not required.
This list will always include some names, like those belonging to the player sprite and the health gauge, however others only need to be included if related sprites exist in the level. No need to load the zombie head sprites if there are no zombies in the level, for instance (doing so won't cause any harm, but may use up too much memory preventing the level from loading.)
The following table lists the sprites that should appear in this list, based on the sprites appearing in the sprite layer.
|Sprite name (.msp)||Additional required sprites (.sgl)|
|(Mandatory)||arrows blank border border2 cat chunk dog flag float100? guage heart leaf rock? score splat white|
|break_screen crack crawl_left crawl_right dirt_l dirt_r main_die main_exit main_hat_l main_hat_r main_l main_meter main_r main_stars|
|cyclops_l cyclops_r cyc_horn_l cyc_horn_r Confirm these last two are needed|
|devil_l devil_r pfork_l pfork_r|
|iman_l iman_r hat|
|nemesis||main_broom (plus all main_r dependent sprites)|
|skelet_l sketet_r jaw_l jaw_r|
|swamp_l swamp_r swamp2_l swamp2_r swamp_scum2_l swamp_scum2_r swamp_scum_l swamp_scum_r|
|tman_bl tman_br pellet_h|
|tman_ld tman_lu pellet_h|
|tman_rd tman_ru pellet_h|
|tman_tl tman_tr pellet_h|
|vulture||vulture vulture_l vulture_r|
|zb_l zb_r zbh_l zbh_r zhead zhead_r|
The following table lists the sprites that should appear, based on tiles appearing in the foreground layer:
|Map element||Additional required sprites (.sgl)|
|collapsing walkway||plank plank_r|
|skull (point item)||skullw|
This file format was reverse engineered by Malvineous. 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!)